Commit ee3a9905 by ukjbrown

Add hipchat notification, test and relevant docs

parent c40cd36b
......@@ -428,6 +428,44 @@ To enable pagerduty notifications you just have to add a generic service to your
|
|===
[hipchat-notifications]
==== Hipchat notifications ====
To enable Hipchat notifications you need to create an API token from you Hipchat account and set the appropriate configuration properties.
.Hipchat notifications configuration options
|===
| Property name |Description |Default value
| spring.boot.admin.notify.hipchat.enabled
| Enable Hipchat notifications
| `true`
| spring.boot.admin.notify.hipchat.ignore-changes
| Comma-delimited list of status changes to be ignored. Format: "<from-status>:<to-status>". Wildcards allowed.
| `"UNKNOWN:UP"`
| spring.boot.admin.notify.hipchat.url
| The HipChat REST API (V2) URL
|
| spring.boot.admin.notify.hipchat.auth-token
| The API token with access to the notification room
|
| spring.boot.admin.notify.hipchat.room-id
| The ID or url-encoded name of the room to send notifications to
|
| spring.boot.admin.notify.hipchat.notify
| Whether the message should trigger a user notification
| `false`
| spring.boot.admin.notify.hipchat.description
| Description to use in the event. SpEL-expressions are supported
| `+++"<strong>#{application.name}</strong>/#{application.id} is <strong>#{to.status}</strong>"+++`
|
|===
[reminder-notifactaions]
==== Reminder notifications ====
To get reminders for down/offline applications you can add a `RemindingNotifier` to your `ApplicationContext`. The `RemindingNotifier` uses another `Notifier` as delegate to send the reminders.
......
package de.codecentric.boot.admin.config;
import de.codecentric.boot.admin.notify.HipchatNotifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author Jamie Brown
*/
@Configuration
@ConditionalOnProperty("spring.boot.admin.notify.hipchat.url")
public class HipchatNotifierConfiguration
{
@Bean
@ConditionalOnMissingBean
@ConditionalOnProperty(prefix = "spring.boot.admin.notify.hipchat", name = "enabled", matchIfMissing = true)
@ConfigurationProperties("spring.boot.admin.notify.hipchat")
public HipchatNotifier hipchatNotifier()
{
return new HipchatNotifier();
}
}
package de.codecentric.boot.admin.notify;
import de.codecentric.boot.admin.event.ClientApplicationStatusChangedEvent;
import org.springframework.expression.Expression;
import org.springframework.expression.ParserContext;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.web.client.RestTemplate;
import java.net.URI;
import java.util.HashMap;
import java.util.Map;
/**
* @author Jamie BRown
*/
public class HipchatNotifier extends AbstractStatusChangeNotifier
{
private final static String DEFAULT_DESCRIPTION = "<strong>#{application.name}</strong>/#{application.id} is <strong>#{to.status}</strong>";
private final SpelExpressionParser parser = new SpelExpressionParser();
private RestTemplate restTemplate = new RestTemplate();
/**
* Base URL for HipChat API (i.e. https://ACCOUNT_NAME.hipchat.com/v2
*/
private URI url;
/**
* API token that has access to notify in the room
*/
private String authToken;
/**
* Id of the room to notify
*/
private String roomId;
/**
* TRUE will cause OS notification, FALSE will only notify to room
*/
private Boolean notify;
/**
* Trigger description. SpEL template using event as root;
*/
private Expression description;
public HipchatNotifier()
{
this.description = parser.parseExpression(DEFAULT_DESCRIPTION,
ParserContext.TEMPLATE_EXPRESSION);
}
@Override
protected void doNotify(ClientApplicationStatusChangedEvent event)
{
restTemplate.postForEntity(buildUrl(), createHipChatNotification(event), Void.class);
}
private String buildUrl()
{
return String.format("%s/room/%s/notification?auth_token=%s", url.toString(), roomId, authToken);
}
private Map<String, Object> createHipChatNotification(ClientApplicationStatusChangedEvent event)
{
Map<String, Object> result = new HashMap<String, Object>();
String color = "UP".equals(event.getTo().getStatus()) ? "green" : "red";
String message = description.getValue(event, String.class);
result.put("color", color);
result.put("message", message);
result.put("notify", Boolean.TRUE.equals(notify));
result.put("message_format", "html");
return result;
}
public void setUrl(URI url)
{
this.url = url;
}
public void setAuthToken(String authToken)
{
this.authToken = authToken;
}
public void setRoomId(String roomId)
{
this.roomId = roomId;
}
public void setNotify(Boolean notify)
{
this.notify = notify;
}
public void setDescription(String description)
{
this.description = parser.parseExpression(description, ParserContext.TEMPLATE_EXPRESSION);
}
public void setRestTemplate(RestTemplate restTemplate)
{
this.restTemplate = restTemplate;
}
}
package de.codecentric.boot.admin.notify;
import de.codecentric.boot.admin.event.ClientApplicationStatusChangedEvent;
import de.codecentric.boot.admin.model.Application;
import de.codecentric.boot.admin.model.StatusInfo;
import org.junit.Before;
import org.junit.Test;
import org.springframework.web.client.RestTemplate;
import java.net.URI;
import java.util.HashMap;
import java.util.Map;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
/**
* @author Jamie Brown
*/
public class HipchatNotifierTest
{
private HipchatNotifier notifier;
private RestTemplate restTemplate;
@Before
public void setUp()
{
restTemplate = mock(RestTemplate.class);
notifier = new HipchatNotifier();
notifier.setNotify(true);
notifier.setAuthToken("--token-");
notifier.setRoomId("-room-");
notifier.setUrl(URI.create("http://localhost/v2"));
notifier.setRestTemplate(restTemplate);
}
@Test
public void test_onApplicationEvent_resolve()
{
StatusInfo infoDown = StatusInfo.ofDown();
StatusInfo infoUp = StatusInfo.ofUp();
notifier.notify(new ClientApplicationStatusChangedEvent(
Application.create("App").withId("-id-").withHealthUrl("http://health").build(),
infoDown, infoUp));
Map<String, Object> expected = new HashMap<String, Object>();
expected.put("color", "green");
expected.put("message", "<strong>App</strong>/-id- is <strong>UP</strong>");
expected.put("notify", Boolean.TRUE);
expected.put("message_format", "html");
verify(restTemplate).postForEntity(any(String.class), eq(expected), eq(Void.class));
}
@Test
public void test_onApplicationEvent_trigger()
{
StatusInfo infoDown = StatusInfo.ofDown();
StatusInfo infoUp = StatusInfo.ofUp();
notifier.notify(new ClientApplicationStatusChangedEvent(
Application.create("App").withId("-id-").withHealthUrl("http://health").build(),
infoUp, infoDown));
Map<String, Object> expected = new HashMap<String, Object>();
expected.put("color", "red");
expected.put("message", "<strong>App</strong>/-id- is <strong>DOWN</strong>");
expected.put("notify", Boolean.TRUE);
expected.put("message_format", "html");
verify(restTemplate).postForEntity(any(String.class), eq(expected), eq(Void.class));
}
}
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