Commit af951b06 by Johannes Edmeier

Make the AbstractNotifier work for any event.

With this change the AbstractNotifier isn't specialized on status changes, but the default behaviour for the existing notifiers isn't changed. In addition the existing notifiers have been improved so that subclassing has become easier. To have existing notifiers acting on other events you need to override shouldNotify(). fixes #270
parent 5ebb3a39
/*
* Copyright 2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.codecentric.boot.admin.notify;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import de.codecentric.boot.admin.event.ClientApplicationEvent;
/**
* Abstract Notifier which allows disabling and filtering of events.
*
* @author Johannes Edmeier
*/
public abstract class AbstractEventNotifier implements Notifier {
/**
* Enables the notification.
*/
private boolean enabled = true;
@Override
public void notify(ClientApplicationEvent event) {
if (enabled && shouldNotify(event)) {
try {
doNotify(event);
} catch (Exception ex) {
getLogger().error("Couldn't notify for event {} ", event, ex);
}
}
}
protected abstract boolean shouldNotify(ClientApplicationEvent event);
protected abstract void doNotify(ClientApplicationEvent event) throws Exception;
private Logger getLogger() {
return LoggerFactory.getLogger(this.getClass());
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
}
\ No newline at end of file
/* /*
* Copyright 2013-2014 the original author or authors. * Copyright 2016 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -17,9 +17,6 @@ package de.codecentric.boot.admin.notify; ...@@ -17,9 +17,6 @@ package de.codecentric.boot.admin.notify;
import java.util.Arrays; import java.util.Arrays;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import de.codecentric.boot.admin.event.ClientApplicationEvent; import de.codecentric.boot.admin.event.ClientApplicationEvent;
import de.codecentric.boot.admin.event.ClientApplicationStatusChangedEvent; import de.codecentric.boot.admin.event.ClientApplicationStatusChangedEvent;
...@@ -28,7 +25,7 @@ import de.codecentric.boot.admin.event.ClientApplicationStatusChangedEvent; ...@@ -28,7 +25,7 @@ import de.codecentric.boot.admin.event.ClientApplicationStatusChangedEvent;
* *
* @author Johannes Edmeier * @author Johannes Edmeier
*/ */
public abstract class AbstractStatusChangeNotifier implements Notifier { public abstract class AbstractStatusChangeNotifier extends AbstractEventNotifier {
/** /**
* List of changes to ignore. Must be in Format OLD:NEW, for any status use * as wildcard, e.g. * List of changes to ignore. Must be in Format OLD:NEW, for any status use * as wildcard, e.g.
...@@ -36,36 +33,17 @@ public abstract class AbstractStatusChangeNotifier implements Notifier { ...@@ -36,36 +33,17 @@ public abstract class AbstractStatusChangeNotifier implements Notifier {
*/ */
protected String[] ignoreChanges = { "UNKNOWN:UP" }; protected String[] ignoreChanges = { "UNKNOWN:UP" };
/**
* Enables the mail notification.
*/
private boolean enabled = true;
@Override @Override
public void notify(ClientApplicationEvent event) { protected boolean shouldNotify(ClientApplicationEvent event) {
if (event instanceof ClientApplicationStatusChangedEvent) { if (event instanceof ClientApplicationStatusChangedEvent) {
ClientApplicationStatusChangedEvent statusChange = (ClientApplicationStatusChangedEvent) event; ClientApplicationStatusChangedEvent statusChange = (ClientApplicationStatusChangedEvent) event;
if (enabled && shouldNotify(statusChange.getFrom().getStatus(), String from = statusChange.getFrom().getStatus();
statusChange.getTo().getStatus())) { String to = statusChange.getTo().getStatus();
try { return Arrays.binarySearch(ignoreChanges, from + ":" + to) < 0
doNotify(statusChange); && Arrays.binarySearch(ignoreChanges, "*:" + to) < 0
} catch (Exception ex) { && Arrays.binarySearch(ignoreChanges, from + ":*") < 0;
getLogger().error("Couldn't notify for status change {} ", statusChange, ex);
}
}
} }
} return false;
protected boolean shouldNotify(String from, String to) {
return Arrays.binarySearch(ignoreChanges, (from + ":" + to)) < 0
&& Arrays.binarySearch(ignoreChanges, ("*:" + to)) < 0
&& Arrays.binarySearch(ignoreChanges, (from + ":*")) < 0;
}
protected abstract void doNotify(ClientApplicationStatusChangedEvent event) throws Exception;
private Logger getLogger() {
return LoggerFactory.getLogger(this.getClass());
} }
public void setIgnoreChanges(String[] ignoreChanges) { public void setIgnoreChanges(String[] ignoreChanges) {
...@@ -74,7 +52,4 @@ public abstract class AbstractStatusChangeNotifier implements Notifier { ...@@ -74,7 +52,4 @@ public abstract class AbstractStatusChangeNotifier implements Notifier {
this.ignoreChanges = copy; this.ignoreChanges = copy;
} }
public void setEnabled(boolean enabled) { }
this.enabled = enabled;
}
}
\ No newline at end of file
...@@ -24,6 +24,7 @@ import org.springframework.expression.ParserContext; ...@@ -24,6 +24,7 @@ import org.springframework.expression.ParserContext;
import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.web.client.RestTemplate; import org.springframework.web.client.RestTemplate;
import de.codecentric.boot.admin.event.ClientApplicationEvent;
import de.codecentric.boot.admin.event.ClientApplicationStatusChangedEvent; import de.codecentric.boot.admin.event.ClientApplicationStatusChangedEvent;
/** /**
...@@ -55,7 +56,7 @@ public class HipchatNotifier extends AbstractStatusChangeNotifier { ...@@ -55,7 +56,7 @@ public class HipchatNotifier extends AbstractStatusChangeNotifier {
/** /**
* TRUE will cause OS notification, FALSE will only notify to room * TRUE will cause OS notification, FALSE will only notify to room
*/ */
private Boolean notify; private boolean notify = false;
/** /**
* Trigger description. SpEL template using event as root; * Trigger description. SpEL template using event as root;
...@@ -68,7 +69,7 @@ public class HipchatNotifier extends AbstractStatusChangeNotifier { ...@@ -68,7 +69,7 @@ public class HipchatNotifier extends AbstractStatusChangeNotifier {
} }
@Override @Override
protected void doNotify(ClientApplicationStatusChangedEvent event) { protected void doNotify(ClientApplicationEvent event) {
restTemplate.postForEntity(buildUrl(), createHipChatNotification(event), Void.class); restTemplate.postForEntity(buildUrl(), createHipChatNotification(event), Void.class);
} }
...@@ -77,18 +78,31 @@ public class HipchatNotifier extends AbstractStatusChangeNotifier { ...@@ -77,18 +78,31 @@ public class HipchatNotifier extends AbstractStatusChangeNotifier {
authToken); authToken);
} }
private Map<String, Object> createHipChatNotification( protected Map<String, Object> createHipChatNotification(ClientApplicationEvent event) {
ClientApplicationStatusChangedEvent event) { Map<String, Object> result = new HashMap<>();
Map<String, Object> result = new HashMap<String, Object>(); result.put("color", getColor(event));
String color = "UP".equals(event.getTo().getStatus()) ? "green" : "red"; result.put("message", getMessage(event));
String message = description.getValue(event, String.class); result.put("notify", getNotify());
result.put("color", color);
result.put("message", message);
result.put("notify", Boolean.TRUE.equals(notify));
result.put("message_format", "html"); result.put("message_format", "html");
return result; return result;
} }
protected boolean getNotify() {
return notify;
}
protected String getMessage(ClientApplicationEvent event) {
return description.getValue(event, String.class);
}
protected String getColor(ClientApplicationEvent event) {
if (event instanceof ClientApplicationStatusChangedEvent) {
return "UP".equals(((ClientApplicationStatusChangedEvent) event).getTo().getStatus()) ? "green" : "red";
} else {
return "gray";
}
}
public void setUrl(URI url) { public void setUrl(URI url) {
this.url = url; this.url = url;
} }
...@@ -101,7 +115,7 @@ public class HipchatNotifier extends AbstractStatusChangeNotifier { ...@@ -101,7 +115,7 @@ public class HipchatNotifier extends AbstractStatusChangeNotifier {
this.roomId = roomId; this.roomId = roomId;
} }
public void setNotify(Boolean notify) { public void setNotify(boolean notify) {
this.notify = notify; this.notify = notify;
} }
......
...@@ -18,20 +18,26 @@ package de.codecentric.boot.admin.notify; ...@@ -18,20 +18,26 @@ package de.codecentric.boot.admin.notify;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import de.codecentric.boot.admin.event.ClientApplicationEvent;
import de.codecentric.boot.admin.event.ClientApplicationStatusChangedEvent; import de.codecentric.boot.admin.event.ClientApplicationStatusChangedEvent;
/** /**
* Notifier that just writes to a logger. * Notifier that just writes to a logger.
* *
* @author Johannes Edmeier * @author Johannes Edmeier
*/ */
public class LoggingNotifier extends AbstractStatusChangeNotifier { public class LoggingNotifier extends AbstractStatusChangeNotifier {
private static Logger LOGGER = LoggerFactory.getLogger(LoggingNotifier.class); private static Logger LOGGER = LoggerFactory.getLogger(LoggingNotifier.class);
@Override @Override
protected void doNotify(ClientApplicationStatusChangedEvent event) throws Exception { protected void doNotify(ClientApplicationEvent event) throws Exception {
LOGGER.info("Application {} ({}) is {}", event.getApplication().getName(), if (event instanceof ClientApplicationStatusChangedEvent) {
event.getApplication().getId(), event.getTo().getStatus()); LOGGER.info("Application {} ({}) is {}", event.getApplication().getName(),
event.getApplication().getId(), ((ClientApplicationStatusChangedEvent) event).getTo().getStatus());
} else {
LOGGER.info("Application {} ({}) {}", event.getApplication().getName(),
event.getApplication().getId(), event.getType());
}
} }
} }
...@@ -25,7 +25,7 @@ import org.springframework.expression.spel.support.StandardEvaluationContext; ...@@ -25,7 +25,7 @@ import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.mail.MailSender; import org.springframework.mail.MailSender;
import org.springframework.mail.SimpleMailMessage; import org.springframework.mail.SimpleMailMessage;
import de.codecentric.boot.admin.event.ClientApplicationStatusChangedEvent; import de.codecentric.boot.admin.event.ClientApplicationEvent;
/** /**
* Notifier sending emails. * Notifier sending emails.
...@@ -71,7 +71,7 @@ public class MailNotifier extends AbstractStatusChangeNotifier { ...@@ -71,7 +71,7 @@ public class MailNotifier extends AbstractStatusChangeNotifier {
} }
@Override @Override
protected void doNotify(ClientApplicationStatusChangedEvent event) { protected void doNotify(ClientApplicationEvent event) {
EvaluationContext context = new StandardEvaluationContext(event); EvaluationContext context = new StandardEvaluationContext(event);
SimpleMailMessage message = new SimpleMailMessage(); SimpleMailMessage message = new SimpleMailMessage();
......
...@@ -25,6 +25,7 @@ import org.springframework.expression.ParserContext; ...@@ -25,6 +25,7 @@ import org.springframework.expression.ParserContext;
import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.web.client.RestTemplate; import org.springframework.web.client.RestTemplate;
import de.codecentric.boot.admin.event.ClientApplicationEvent;
import de.codecentric.boot.admin.event.ClientApplicationStatusChangedEvent; import de.codecentric.boot.admin.event.ClientApplicationStatusChangedEvent;
/** /**
...@@ -72,44 +73,56 @@ public class PagerdutyNotifier extends AbstractStatusChangeNotifier { ...@@ -72,44 +73,56 @@ public class PagerdutyNotifier extends AbstractStatusChangeNotifier {
} }
@Override @Override
protected void doNotify(ClientApplicationStatusChangedEvent event) throws Exception { protected void doNotify(ClientApplicationEvent event) throws Exception {
restTemplate.postForEntity(url, createPagerdutyEvent(event), Void.class); restTemplate.postForEntity(url, createPagerdutyEvent(event), Void.class);
} }
private Map<String, Object> createPagerdutyEvent(ClientApplicationStatusChangedEvent event) { protected Map<String, Object> createPagerdutyEvent(ClientApplicationEvent event) {
Map<String, Object> result = new HashMap<String, Object>(); Map<String, Object> result = new HashMap<>();
result.put("service_key", serviceKey); result.put("service_key", serviceKey);
result.put("incident_key", result.put("incident_key",
event.getApplication().getName() + "/" + event.getApplication().getId()); event.getApplication().getName() + "/" + event.getApplication().getId());
result.put("description", description.getValue(event, String.class)); result.put("description", getDescirption(event));
Map<String, Object> details = new HashMap<String, Object>(); Map<String, Object> details = getDetails(event);
details.put("from", event.getFrom());
details.put("to", event.getTo());
result.put("details", details); result.put("details", details);
if ("UP".equals(event.getTo().getStatus())) { if (event instanceof ClientApplicationStatusChangedEvent) {
result.put("event_type", "resolve"); if ("UP".equals(((ClientApplicationStatusChangedEvent) event).getTo().getStatus())) {
result.put("event_type", "resolve");
} else { } else {
result.put("event_type", "trigger"); result.put("event_type", "trigger");
if (client != null) { if (client != null) {
result.put("client", client); result.put("client", client);
} }
if (clientUrl != null) { if (clientUrl != null) {
result.put("client_url", clientUrl); result.put("client_url", clientUrl);
}
Map<String, Object> context = new HashMap<>();
context.put("type", "link");
context.put("href", event.getApplication().getHealthUrl());
context.put("text", "Application health-endpoint");
result.put("contexts", Arrays.asList(context));
} }
Map<String, Object> context = new HashMap<String, Object>();
context.put("type", "link");
context.put("href", event.getApplication().getHealthUrl());
context.put("text", "Application health-endpoint");
result.put("contexts", Arrays.asList(context));
} }
return result; return result;
} }
protected String getDescirption(ClientApplicationEvent event) {
return description.getValue(event, String.class);
}
protected Map<String, Object> getDetails(ClientApplicationEvent event) {
Map<String, Object> details = new HashMap<>();
if (event instanceof ClientApplicationStatusChangedEvent) {
details.put("from", ((ClientApplicationStatusChangedEvent) event).getFrom());
details.put("to", ((ClientApplicationStatusChangedEvent) event).getTo());
}
return details;
}
public void setUrl(URI url) { public void setUrl(URI url) {
this.url = url; this.url = url;
} }
......
...@@ -10,6 +10,7 @@ import org.springframework.expression.ParserContext; ...@@ -10,6 +10,7 @@ import org.springframework.expression.ParserContext;
import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.web.client.RestTemplate; import org.springframework.web.client.RestTemplate;
import de.codecentric.boot.admin.event.ClientApplicationEvent;
import de.codecentric.boot.admin.event.ClientApplicationStatusChangedEvent; import de.codecentric.boot.admin.event.ClientApplicationStatusChangedEvent;
/** /**
...@@ -53,7 +54,7 @@ public class SlackNotifier extends AbstractStatusChangeNotifier { ...@@ -53,7 +54,7 @@ public class SlackNotifier extends AbstractStatusChangeNotifier {
} }
@Override @Override
protected void doNotify(ClientApplicationStatusChangedEvent event) throws Exception { protected void doNotify(ClientApplicationEvent event) throws Exception {
restTemplate.postForEntity(webhookUrl, createMessage(event), Void.class); restTemplate.postForEntity(webhookUrl, createMessage(event), Void.class);
} }
...@@ -81,7 +82,7 @@ public class SlackNotifier extends AbstractStatusChangeNotifier { ...@@ -81,7 +82,7 @@ public class SlackNotifier extends AbstractStatusChangeNotifier {
this.message = parser.parseExpression(message, ParserContext.TEMPLATE_EXPRESSION); this.message = parser.parseExpression(message, ParserContext.TEMPLATE_EXPRESSION);
} }
protected Object createMessage(ClientApplicationStatusChangedEvent event) { protected Object createMessage(ClientApplicationEvent event) {
Map<String, Object> messageJson = new HashMap<>(); Map<String, Object> messageJson = new HashMap<>();
messageJson.put("username", username); messageJson.put("username", username);
if (icon != null) { if (icon != null) {
...@@ -95,17 +96,19 @@ public class SlackNotifier extends AbstractStatusChangeNotifier { ...@@ -95,17 +96,19 @@ public class SlackNotifier extends AbstractStatusChangeNotifier {
attachments.put("text", getText(event)); attachments.put("text", getText(event));
attachments.put("color", getColor(event)); attachments.put("color", getColor(event));
attachments.put("mrkdwn_in", Collections.singletonList("text")); attachments.put("mrkdwn_in", Collections.singletonList("text"));
messageJson.put("attachments", Collections.singletonList(attachments)); messageJson.put("attachments", Collections.singletonList(attachments));
return messageJson; return messageJson;
} }
private String getText(ClientApplicationStatusChangedEvent event) { protected String getText(ClientApplicationEvent event) {
return message.getValue(event, String.class); return message.getValue(event, String.class);
} }
private String getColor(ClientApplicationStatusChangedEvent event) { protected String getColor(ClientApplicationEvent event) {
return "UP".equals(event.getTo().getStatus()) ? "good" : "danger"; if (event instanceof ClientApplicationStatusChangedEvent) {
return "UP".equals(((ClientApplicationStatusChangedEvent) event).getTo().getStatus()) ? "good" : "danger";
} else {
return "#439FE0";
}
} }
} }
...@@ -25,6 +25,7 @@ import org.junit.Test; ...@@ -25,6 +25,7 @@ import org.junit.Test;
import org.springframework.mail.MailSender; import org.springframework.mail.MailSender;
import org.springframework.mail.SimpleMailMessage; import org.springframework.mail.SimpleMailMessage;
import de.codecentric.boot.admin.event.ClientApplicationEvent;
import de.codecentric.boot.admin.event.ClientApplicationStatusChangedEvent; import de.codecentric.boot.admin.event.ClientApplicationStatusChangedEvent;
import de.codecentric.boot.admin.model.Application; import de.codecentric.boot.admin.model.Application;
import de.codecentric.boot.admin.model.StatusInfo; import de.codecentric.boot.admin.model.StatusInfo;
...@@ -96,7 +97,7 @@ public class MailNotifierTest { ...@@ -96,7 +97,7 @@ public class MailNotifierTest {
public void test_onApplicationEvent_throw_doesnt_propagate() { public void test_onApplicationEvent_throw_doesnt_propagate() {
Notifier notifier = new AbstractStatusChangeNotifier() { Notifier notifier = new AbstractStatusChangeNotifier() {
@Override @Override
protected void doNotify(ClientApplicationStatusChangedEvent event) throws Exception { protected void doNotify(ClientApplicationEvent event) throws Exception {
throw new IllegalStateException("test"); throw new IllegalStateException("test");
} }
}; };
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment