Commit 37ec7d22 by wonwoo Committed by Johannes Edmeier

Add Telegram notifier

parent f1a73bce
......@@ -129,10 +129,10 @@ spring.boot.admin.notify.mail.to=admin@example.com
|===
[[pagerduty-notifications]]
==== Pagerduty notifications ====
To enable pagerduty notifications you just have to add a generic service to your pagerduty-account and set `spring.boot.admin.notify.pagerduty.service-key` to the service-key you received.
==== PagerDuty notifications ====
To enable https://www.pagerduty.com/[PagerDuty] notifications you just have to add a generic service to your PagerDuty-account and set `spring.boot.admin.notify.pagerduty.service-key` to the service-key you received.
.Pagerduty notifications configuration options
.PagerDuty notifications configuration options
|===
| Property name |Description |Default value
......@@ -145,7 +145,7 @@ To enable pagerduty notifications you just have to add a generic service to your
| `"UNKNOWN:UP"`
| spring.boot.admin.notify.pagerduty.service-key
| Service-key to use for Pagerduty
| Service-key to use for PagerDuty
|
| spring.boot.admin.notify.pagerduty.url
......@@ -168,7 +168,7 @@ To enable pagerduty notifications you just have to add a generic service to your
[[opsgenie-notifications]]
==== OpsGenie notifications ====
To enable OpsGenie notifications you just have to add a new JSON Rest API integration to your OpsGenie account and set `spring.boot.admin.notify.opsgenie.api-key` to the apiKey you received.
To enable https://www.opsgenie.com/[OpsGenie] notifications you just have to add a new JSON Rest API integration to your OpsGenie account and set `spring.boot.admin.notify.opsgenie.api-key` to the apiKey you received.
.OpsGenie notifications configuration options
|===
......@@ -221,7 +221,7 @@ To enable OpsGenie notifications you just have to add a new JSON Rest API integr
[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.
To enable https://www.hipchat.com/[Hipchat] notifications you need to create an API token from you Hipchat account and set the appropriate configuration properties.
.Hipchat notifications configuration options
|===
......@@ -259,7 +259,7 @@ To enable Hipchat notifications you need to create an API token from you Hipchat
[slack-notifications]
==== Slack notifications ====
To enable Slack notifications you need to add a incoming Webhook under custom integrations on your Slack
To enable https://slack.com/[Slack] notifications you need to add a incoming Webhook under custom integrations on your Slack
account and configure it appropriately.
.Slack notifications configuration options
......@@ -298,7 +298,7 @@ account and configure it appropriately.
[letschat-notifications]
==== Let's Chat notifications ====
To enable Let's Chat notifications you need to add the host url and add the API token and username from Let's Chat
To enable https://sdelements.github.io/lets-chat/[Let's Chat] notifications you need to add the host url and add the API token and username from Let's Chat
.Let's Chat notifications configuration options
|===
......@@ -353,4 +353,37 @@ To enable Microsoft Teams notifications you need to setup a connector webhook ur
| spring.boot.admin.notify.ms-teams.*
| There are several options to customize the message title and color
|
|===
[telegram-notifications]
==== Telegram notifications ====
To enable https://telegram.org/[Telegram] notifications you need to create and authorize a telegram bot and set the appropriate configuration properties for auth-token and chat-id.
.Microsoft Teams notifications configuration options
|===
| Property name |Description |Default value
| spring.boot.admin.notify.telegram.enabled
| Enable Microsoft Teams notifications
| `true`
| spring.boot.admin.notify.telegram.auth-token
| The token identifiying und authorizing your Telegram bot (e.g. `123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11`).
|
| spring.boot.admin.notify.telegram.chat-id
| Unique identifier for the target chat or username of the target channel
|
| spring.boot.admin.notify.telegram.disable-notify
| If true users will receive a notification with no sound.
| `false`
| spring.boot.admin.notify.telegram.parse_mode
| The parsing mode for the sent message. Currently ``HTML'` and `'Markdown'` are supported.
| `'HTML'`
| spring.boot.admin.notify.telegram.message
| Text to send. SpEL-expressions are supported.
| `+++"<strong>#{application.name}</strong>/#{application.id} is <strong>#{to.status}</strong>"+++`
|===
\ No newline at end of file
......@@ -43,6 +43,7 @@ import de.codecentric.boot.admin.notify.NotifierListener;
import de.codecentric.boot.admin.notify.OpsGenieNotifier;
import de.codecentric.boot.admin.notify.PagerdutyNotifier;
import de.codecentric.boot.admin.notify.SlackNotifier;
import de.codecentric.boot.admin.notify.TelegramNotifier;
import de.codecentric.boot.admin.notify.filter.FilteringNotifier;
import de.codecentric.boot.admin.notify.filter.web.NotificationFilterController;
import de.codecentric.boot.admin.web.PrefixHandlerMapping;
......@@ -102,7 +103,8 @@ public class NotifierConfiguration {
@Bean
public PrefixHandlerMapping prefixHandlerMappingNotificationFilterController() {
PrefixHandlerMapping prefixHandlerMapping = new PrefixHandlerMapping(notificationFilterController());
PrefixHandlerMapping prefixHandlerMapping = new PrefixHandlerMapping(
notificationFilterController());
prefixHandlerMapping.setPrefix(adminServerProperties.getContextPath());
return prefixHandlerMapping;
}
......@@ -112,7 +114,7 @@ public class NotifierConfiguration {
@ConditionalOnBean(MailSender.class)
@AutoConfigureAfter({ MailSenderAutoConfiguration.class })
@AutoConfigureBefore({ NotifierListenerConfiguration.class,
CompositeNotifierConfiguration.class })
CompositeNotifierConfiguration.class })
public static class MailNotifierConfiguration {
@Autowired
private MailSender mailSender;
......@@ -128,7 +130,7 @@ public class NotifierConfiguration {
@Configuration
@ConditionalOnProperty(prefix = "spring.boot.admin.notify.pagerduty", name = "service-key")
@AutoConfigureBefore({ NotifierListenerConfiguration.class,
CompositeNotifierConfiguration.class })
CompositeNotifierConfiguration.class })
public static class PagerdutyNotifierConfiguration {
@Bean
@ConditionalOnMissingBean
......@@ -138,7 +140,6 @@ public class NotifierConfiguration {
}
}
@Configuration
@ConditionalOnProperty(prefix = "spring.boot.admin.notify.opsgenie", name = "api-key")
@AutoConfigureBefore({ NotifierListenerConfiguration.class,
......@@ -152,12 +153,10 @@ public class NotifierConfiguration {
}
}
@Configuration
@ConditionalOnProperty(prefix = "spring.boot.admin.notify.hipchat", name = "url")
@AutoConfigureBefore({ NotifierListenerConfiguration.class,
CompositeNotifierConfiguration.class })
CompositeNotifierConfiguration.class })
public static class HipchatNotifierConfiguration {
@Bean
@ConditionalOnMissingBean
......@@ -170,7 +169,7 @@ public class NotifierConfiguration {
@Configuration
@ConditionalOnProperty(prefix = "spring.boot.admin.notify.slack", name = "webhook-url")
@AutoConfigureBefore({ NotifierListenerConfiguration.class,
CompositeNotifierConfiguration.class })
CompositeNotifierConfiguration.class })
public static class SlackNotifierConfiguration {
@Bean
@ConditionalOnMissingBean
......@@ -196,11 +195,26 @@ public class NotifierConfiguration {
@Configuration
@ConditionalOnProperty(prefix = "spring.boot.admin.notify.ms-teams", name = "webhook-url")
@AutoConfigureBefore({ NotifierListenerConfiguration.class,
CompositeNotifierConfiguration.class})
CompositeNotifierConfiguration.class })
public static class MicrosoftTeamsNotifierConfiguration {
@Bean
@ConditionalOnMissingBean
@ConfigurationProperties("spring.boot.admin.notify.ms-teams")
public MicrosoftTeamsNotifier microsoftTeamsNotifier() { return new MicrosoftTeamsNotifier(); }
public MicrosoftTeamsNotifier microsoftTeamsNotifier() {
return new MicrosoftTeamsNotifier();
}
}
@Configuration
@ConditionalOnProperty(prefix = "spring.boot.admin.notify.telegram", name = "auth-token")
@AutoConfigureBefore({ NotifierListenerConfiguration.class,
CompositeNotifierConfiguration.class })
public static class TelegramNotifierConfiguration {
@Bean
@ConditionalOnMissingBean
@ConfigurationProperties("spring.boot.admin.notify.telegram")
public TelegramNotifier telegramNotifier() {
return new TelegramNotifier();
}
}
}
/*
* Copyright 2014-2017 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 java.util.HashMap;
import java.util.Map;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.expression.Expression;
import org.springframework.expression.ParserContext;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.web.client.RestTemplate;
import de.codecentric.boot.admin.event.ClientApplicationEvent;
/**
* Notifier submitting events to Telegram.
*/
public class TelegramNotifier extends AbstractStatusChangeNotifier {
private static final String DEFAULT_MESSAGE = "<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 telegram (i.e. https://api.telegram.org)
*/
private String apiUrl = "https://api.telegram.org";
/**
* Unique identifier for the target chat or username of the target channel
*/
private String chatId;
/**
* The token identifiying und authorizing your Telegram bot (e.g. `123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11`)
*/
private String authToken;
/**
* Send Markdown or HTML, if you want Telegram apps to show bold, italic, fixed-width text or
* inline URLs in your bot's message.
*/
private String parse_mode = "HTML";
/**
* If true users will receive a notification with no sound.
*/
private boolean disableNotify = false;
private Expression message;
public TelegramNotifier() {
this.message = parser.parseExpression(DEFAULT_MESSAGE, ParserContext.TEMPLATE_EXPRESSION);
}
@Override
protected void doNotify(ClientApplicationEvent event) {
restTemplate.getForObject(buildUrl(), Void.class, createMessage(event));
}
protected String buildUrl() {
return String.format(
"%s/bot%s/sendmessage?chat_id={chat_id}&text={text}&parse_mode={parse_mode}"
+ "&disable_notification={disable_notification}",
this.apiUrl, this.authToken);
}
private Map<String, Object> createMessage(ClientApplicationEvent event) {
Map<String, Object> parameters = new HashMap<>();
parameters.put("chat_id", this.chatId);
parameters.put("parse_mode", this.parse_mode);
parameters.put("disable_notification", this.disableNotify);
parameters.put("text", getText(event));
return parameters;
}
protected String getText(ClientApplicationEvent event) {
return message.getValue(event, String.class);
}
public void setRestTemplate(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
public void setRestTemplate(RestTemplateBuilder builder) {
this.restTemplate = builder.build();
}
public String getApiUrl() {
return apiUrl;
}
public void setApiUrl(String apiUrl) {
this.apiUrl = apiUrl;
}
public String getChatId() {
return chatId;
}
public void setChatId(String chatId) {
this.chatId = chatId;
}
public String getAuthToken() {
return authToken;
}
public void setAuthToken(String authToken) {
this.authToken = authToken;
}
public boolean isDisableNotify() {
return disableNotify;
}
public void setDisableNotify(boolean disableNotify) {
this.disableNotify = disableNotify;
}
public String getParse_mode() {
return parse_mode;
}
public void setParse_mode(String parse_mode) {
this.parse_mode = parse_mode;
}
public void setMessage(String message) {
this.message = parser.parseExpression(message, ParserContext.TEMPLATE_EXPRESSION);
}
}
......@@ -46,6 +46,7 @@ import de.codecentric.boot.admin.notify.NotifierListener;
import de.codecentric.boot.admin.notify.OpsGenieNotifier;
import de.codecentric.boot.admin.notify.PagerdutyNotifier;
import de.codecentric.boot.admin.notify.SlackNotifier;
import de.codecentric.boot.admin.notify.TelegramNotifier;
public class NotifierConfigurationTest {
private static final ClientApplicationEvent APP_DOWN = new ClientApplicationStatusChangedEvent(
......@@ -114,6 +115,12 @@ public class NotifierConfigurationTest {
}
@Test
public void test_telegram() {
load(null, "spring.boot.admin.notify.telegram.auth-token:123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11");
assertThat(context.getBean(Notifier.class), is(instanceOf(TelegramNotifier.class)));
}
@Test
public void test_multipleNotifiers() {
load(TestMultipleNotifierConfig.class);
assertThat(context.getBean(Notifier.class), is(instanceOf(CompositeNotifier.class)));
......
package de.codecentric.boot.admin.notify;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import java.util.HashMap;
import java.util.Map;
import org.junit.Before;
import org.junit.Test;
import org.springframework.web.client.RestTemplate;
import de.codecentric.boot.admin.event.ClientApplicationStatusChangedEvent;
import de.codecentric.boot.admin.model.Application;
import de.codecentric.boot.admin.model.StatusInfo;
public class TelegramNotifierTest {
private TelegramNotifier notifier;
private RestTemplate restTemplate;
@Before
public void setUp() {
restTemplate = mock(RestTemplate.class);
notifier = new TelegramNotifier();
notifier.setDisableNotify(false);
notifier.setAuthToken("--token-");
notifier.setChatId("-room-");
notifier.setParse_mode("HTML");
notifier.setApiUrl("https://telegram.com");
notifier.setRestTemplate(restTemplate);
}
@Test
public void test_onApplicationEvent_resolve() {
StatusInfo infoDown = StatusInfo.ofDown();
StatusInfo infoUp = StatusInfo.ofUp();
notifier.notify(getEvent(infoDown, infoUp));
verify(restTemplate).getForObject(
eq("https://telegram.com/bot--token-/sendmessage?chat_id={chat_id}&text={text}"
+ "&parse_mode={parse_mode}&disable_notification={disable_notification}"),
eq(Void.class), eq(getParameters("UP")));
}
@Test
public void test_onApplicationEvent_trigger() {
StatusInfo infoDown = StatusInfo.ofDown();
StatusInfo infoUp = StatusInfo.ofUp();
notifier.notify(getEvent(infoUp, infoDown));
verify(restTemplate).getForObject(
eq("https://telegram.com/bot--token-/sendmessage?chat_id={chat_id}&text={text}"
+ "&parse_mode={parse_mode}&disable_notification={disable_notification}"),
eq(Void.class), eq(getParameters("DOWN")));
}
private ClientApplicationStatusChangedEvent getEvent(StatusInfo infoDown, StatusInfo infoUp) {
return new ClientApplicationStatusChangedEvent(Application.create("Telegram").withId("-id-")
.withHealthUrl("http://health").build(), infoDown, infoUp);
}
private Map<String, Object> getParameters(String status) {
Map<String, Object> parameters = new HashMap<>();
parameters.put("chat_id", "-room-");
parameters.put("text", getMessage("Telegram", "-id-", status));
parameters.put("parse_mode", "HTML");
parameters.put("disable_notification", false);
return parameters;
}
private String getMessage(String name, String id, String status) {
return "<strong>" + name + "</strong>/" + id + " is <strong>" + status + "</strong>";
}
}
\ No newline at end of file
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