Skip to content

Commit 37ec7d2

Browse files
wonwoojoshiste
authored andcommitted
Add Telegram notifier
1 parent f1a73bc commit 37ec7d2

File tree

5 files changed

+290
-18
lines changed

5 files changed

+290
-18
lines changed

spring-boot-admin-docs/src/main/asciidoc/server-notifications.adoc

+41-8
Original file line numberDiff line numberDiff line change
@@ -129,10 +129,10 @@ [email protected]
129129
|===
130130

131131
[[pagerduty-notifications]]
132-
==== Pagerduty notifications ====
133-
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.
132+
==== PagerDuty notifications ====
133+
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.
134134

135-
.Pagerduty notifications configuration options
135+
.PagerDuty notifications configuration options
136136
|===
137137
| Property name |Description |Default value
138138

@@ -145,7 +145,7 @@ To enable pagerduty notifications you just have to add a generic service to your
145145
| `"UNKNOWN:UP"`
146146

147147
| spring.boot.admin.notify.pagerduty.service-key
148-
| Service-key to use for Pagerduty
148+
| Service-key to use for PagerDuty
149149
|
150150

151151
| spring.boot.admin.notify.pagerduty.url
@@ -168,7 +168,7 @@ To enable pagerduty notifications you just have to add a generic service to your
168168

169169
[[opsgenie-notifications]]
170170
==== OpsGenie notifications ====
171-
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.
171+
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.
172172

173173
.OpsGenie notifications configuration options
174174
|===
@@ -221,7 +221,7 @@ To enable OpsGenie notifications you just have to add a new JSON Rest API integr
221221

222222
[hipchat-notifications]
223223
==== Hipchat notifications ====
224-
To enable Hipchat notifications you need to create an API token from you Hipchat account and set the appropriate configuration properties.
224+
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.
225225

226226
.Hipchat notifications configuration options
227227
|===
@@ -259,7 +259,7 @@ To enable Hipchat notifications you need to create an API token from you Hipchat
259259

260260
[slack-notifications]
261261
==== Slack notifications ====
262-
To enable Slack notifications you need to add a incoming Webhook under custom integrations on your Slack
262+
To enable https://slack.com/[Slack] notifications you need to add a incoming Webhook under custom integrations on your Slack
263263
account and configure it appropriately.
264264

265265
.Slack notifications configuration options
@@ -298,7 +298,7 @@ account and configure it appropriately.
298298

299299
[letschat-notifications]
300300
==== Let's Chat notifications ====
301-
To enable Let's Chat notifications you need to add the host url and add the API token and username from Let's Chat
301+
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
302302

303303
.Let's Chat notifications configuration options
304304
|===
@@ -353,4 +353,37 @@ To enable Microsoft Teams notifications you need to setup a connector webhook ur
353353
| spring.boot.admin.notify.ms-teams.*
354354
| There are several options to customize the message title and color
355355
|
356+
|===
357+
358+
[telegram-notifications]
359+
==== Telegram notifications ====
360+
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.
361+
362+
.Microsoft Teams notifications configuration options
363+
|===
364+
| Property name |Description |Default value
365+
366+
| spring.boot.admin.notify.telegram.enabled
367+
| Enable Microsoft Teams notifications
368+
| `true`
369+
370+
| spring.boot.admin.notify.telegram.auth-token
371+
| The token identifiying und authorizing your Telegram bot (e.g. `123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11`).
372+
|
373+
374+
| spring.boot.admin.notify.telegram.chat-id
375+
| Unique identifier for the target chat or username of the target channel
376+
|
377+
378+
| spring.boot.admin.notify.telegram.disable-notify
379+
| If true users will receive a notification with no sound.
380+
| `false`
381+
382+
| spring.boot.admin.notify.telegram.parse_mode
383+
| The parsing mode for the sent message. Currently ``HTML'` and `'Markdown'` are supported.
384+
| `'HTML'`
385+
386+
| spring.boot.admin.notify.telegram.message
387+
| Text to send. SpEL-expressions are supported.
388+
| `+++"<strong>#{application.name}</strong>/#{application.id} is <strong>#{to.status}</strong>"+++`
356389
|===

spring-boot-admin-server/src/main/java/de/codecentric/boot/admin/config/NotifierConfiguration.java

+24-10
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import de.codecentric.boot.admin.notify.OpsGenieNotifier;
4444
import de.codecentric.boot.admin.notify.PagerdutyNotifier;
4545
import de.codecentric.boot.admin.notify.SlackNotifier;
46+
import de.codecentric.boot.admin.notify.TelegramNotifier;
4647
import de.codecentric.boot.admin.notify.filter.FilteringNotifier;
4748
import de.codecentric.boot.admin.notify.filter.web.NotificationFilterController;
4849
import de.codecentric.boot.admin.web.PrefixHandlerMapping;
@@ -102,7 +103,8 @@ public NotificationFilterController notificationFilterController() {
102103

103104
@Bean
104105
public PrefixHandlerMapping prefixHandlerMappingNotificationFilterController() {
105-
PrefixHandlerMapping prefixHandlerMapping = new PrefixHandlerMapping(notificationFilterController());
106+
PrefixHandlerMapping prefixHandlerMapping = new PrefixHandlerMapping(
107+
notificationFilterController());
106108
prefixHandlerMapping.setPrefix(adminServerProperties.getContextPath());
107109
return prefixHandlerMapping;
108110
}
@@ -112,7 +114,7 @@ public PrefixHandlerMapping prefixHandlerMappingNotificationFilterController() {
112114
@ConditionalOnBean(MailSender.class)
113115
@AutoConfigureAfter({ MailSenderAutoConfiguration.class })
114116
@AutoConfigureBefore({ NotifierListenerConfiguration.class,
115-
CompositeNotifierConfiguration.class })
117+
CompositeNotifierConfiguration.class })
116118
public static class MailNotifierConfiguration {
117119
@Autowired
118120
private MailSender mailSender;
@@ -128,7 +130,7 @@ public MailNotifier mailNotifier() {
128130
@Configuration
129131
@ConditionalOnProperty(prefix = "spring.boot.admin.notify.pagerduty", name = "service-key")
130132
@AutoConfigureBefore({ NotifierListenerConfiguration.class,
131-
CompositeNotifierConfiguration.class })
133+
CompositeNotifierConfiguration.class })
132134
public static class PagerdutyNotifierConfiguration {
133135
@Bean
134136
@ConditionalOnMissingBean
@@ -138,7 +140,6 @@ public PagerdutyNotifier pagerdutyNotifier() {
138140
}
139141
}
140142

141-
142143
@Configuration
143144
@ConditionalOnProperty(prefix = "spring.boot.admin.notify.opsgenie", name = "api-key")
144145
@AutoConfigureBefore({ NotifierListenerConfiguration.class,
@@ -152,12 +153,10 @@ public OpsGenieNotifier opsgenieNotifier() {
152153
}
153154
}
154155

155-
156-
157156
@Configuration
158157
@ConditionalOnProperty(prefix = "spring.boot.admin.notify.hipchat", name = "url")
159158
@AutoConfigureBefore({ NotifierListenerConfiguration.class,
160-
CompositeNotifierConfiguration.class })
159+
CompositeNotifierConfiguration.class })
161160
public static class HipchatNotifierConfiguration {
162161
@Bean
163162
@ConditionalOnMissingBean
@@ -170,7 +169,7 @@ public HipchatNotifier hipchatNotifier() {
170169
@Configuration
171170
@ConditionalOnProperty(prefix = "spring.boot.admin.notify.slack", name = "webhook-url")
172171
@AutoConfigureBefore({ NotifierListenerConfiguration.class,
173-
CompositeNotifierConfiguration.class })
172+
CompositeNotifierConfiguration.class })
174173
public static class SlackNotifierConfiguration {
175174
@Bean
176175
@ConditionalOnMissingBean
@@ -196,11 +195,26 @@ public LetsChatNotifier letsChatNotifier() {
196195
@Configuration
197196
@ConditionalOnProperty(prefix = "spring.boot.admin.notify.ms-teams", name = "webhook-url")
198197
@AutoConfigureBefore({ NotifierListenerConfiguration.class,
199-
CompositeNotifierConfiguration.class})
198+
CompositeNotifierConfiguration.class })
200199
public static class MicrosoftTeamsNotifierConfiguration {
201200
@Bean
202201
@ConditionalOnMissingBean
203202
@ConfigurationProperties("spring.boot.admin.notify.ms-teams")
204-
public MicrosoftTeamsNotifier microsoftTeamsNotifier() { return new MicrosoftTeamsNotifier(); }
203+
public MicrosoftTeamsNotifier microsoftTeamsNotifier() {
204+
return new MicrosoftTeamsNotifier();
205+
}
206+
}
207+
208+
@Configuration
209+
@ConditionalOnProperty(prefix = "spring.boot.admin.notify.telegram", name = "auth-token")
210+
@AutoConfigureBefore({ NotifierListenerConfiguration.class,
211+
CompositeNotifierConfiguration.class })
212+
public static class TelegramNotifierConfiguration {
213+
@Bean
214+
@ConditionalOnMissingBean
215+
@ConfigurationProperties("spring.boot.admin.notify.telegram")
216+
public TelegramNotifier telegramNotifier() {
217+
return new TelegramNotifier();
218+
}
205219
}
206220
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
/*
2+
* Copyright 2014-2017 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package de.codecentric.boot.admin.notify;
17+
18+
import java.util.HashMap;
19+
import java.util.Map;
20+
21+
import org.springframework.boot.web.client.RestTemplateBuilder;
22+
import org.springframework.expression.Expression;
23+
import org.springframework.expression.ParserContext;
24+
import org.springframework.expression.spel.standard.SpelExpressionParser;
25+
import org.springframework.web.client.RestTemplate;
26+
27+
import de.codecentric.boot.admin.event.ClientApplicationEvent;
28+
29+
/**
30+
* Notifier submitting events to Telegram.
31+
*/
32+
public class TelegramNotifier extends AbstractStatusChangeNotifier {
33+
private static final String DEFAULT_MESSAGE = "<strong>#{application.name}</strong>/#{application.id} is <strong>#{to.status}</strong>";
34+
private final SpelExpressionParser parser = new SpelExpressionParser();
35+
private RestTemplate restTemplate = new RestTemplate();
36+
37+
/**
38+
* base url for telegram (i.e. https://api.telegram.org)
39+
*/
40+
private String apiUrl = "https://api.telegram.org";
41+
42+
/**
43+
* Unique identifier for the target chat or username of the target channel
44+
*/
45+
private String chatId;
46+
47+
/**
48+
* The token identifiying und authorizing your Telegram bot (e.g. `123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11`)
49+
*/
50+
private String authToken;
51+
52+
/**
53+
* Send Markdown or HTML, if you want Telegram apps to show bold, italic, fixed-width text or
54+
* inline URLs in your bot's message.
55+
*/
56+
private String parse_mode = "HTML";
57+
58+
/**
59+
* If true users will receive a notification with no sound.
60+
*/
61+
private boolean disableNotify = false;
62+
63+
private Expression message;
64+
65+
public TelegramNotifier() {
66+
this.message = parser.parseExpression(DEFAULT_MESSAGE, ParserContext.TEMPLATE_EXPRESSION);
67+
}
68+
69+
@Override
70+
protected void doNotify(ClientApplicationEvent event) {
71+
restTemplate.getForObject(buildUrl(), Void.class, createMessage(event));
72+
}
73+
74+
protected String buildUrl() {
75+
return String.format(
76+
"%s/bot%s/sendmessage?chat_id={chat_id}&text={text}&parse_mode={parse_mode}"
77+
+ "&disable_notification={disable_notification}",
78+
this.apiUrl, this.authToken);
79+
}
80+
81+
private Map<String, Object> createMessage(ClientApplicationEvent event) {
82+
Map<String, Object> parameters = new HashMap<>();
83+
parameters.put("chat_id", this.chatId);
84+
parameters.put("parse_mode", this.parse_mode);
85+
parameters.put("disable_notification", this.disableNotify);
86+
parameters.put("text", getText(event));
87+
return parameters;
88+
}
89+
90+
protected String getText(ClientApplicationEvent event) {
91+
return message.getValue(event, String.class);
92+
}
93+
94+
public void setRestTemplate(RestTemplate restTemplate) {
95+
this.restTemplate = restTemplate;
96+
}
97+
98+
public void setRestTemplate(RestTemplateBuilder builder) {
99+
this.restTemplate = builder.build();
100+
}
101+
102+
public String getApiUrl() {
103+
return apiUrl;
104+
}
105+
106+
public void setApiUrl(String apiUrl) {
107+
this.apiUrl = apiUrl;
108+
}
109+
110+
public String getChatId() {
111+
return chatId;
112+
}
113+
114+
public void setChatId(String chatId) {
115+
this.chatId = chatId;
116+
}
117+
118+
public String getAuthToken() {
119+
return authToken;
120+
}
121+
122+
public void setAuthToken(String authToken) {
123+
this.authToken = authToken;
124+
}
125+
126+
public boolean isDisableNotify() {
127+
return disableNotify;
128+
}
129+
130+
public void setDisableNotify(boolean disableNotify) {
131+
this.disableNotify = disableNotify;
132+
}
133+
134+
public String getParse_mode() {
135+
return parse_mode;
136+
}
137+
138+
public void setParse_mode(String parse_mode) {
139+
this.parse_mode = parse_mode;
140+
}
141+
142+
public void setMessage(String message) {
143+
this.message = parser.parseExpression(message, ParserContext.TEMPLATE_EXPRESSION);
144+
}
145+
}

spring-boot-admin-server/src/test/java/de/codecentric/boot/admin/config/NotifierConfigurationTest.java

+7
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
import de.codecentric.boot.admin.notify.OpsGenieNotifier;
4747
import de.codecentric.boot.admin.notify.PagerdutyNotifier;
4848
import de.codecentric.boot.admin.notify.SlackNotifier;
49+
import de.codecentric.boot.admin.notify.TelegramNotifier;
4950

5051
public class NotifierConfigurationTest {
5152
private static final ClientApplicationEvent APP_DOWN = new ClientApplicationStatusChangedEvent(
@@ -113,6 +114,12 @@ public void test_ms_teams() {
113114
assertThat(context.getBean(MicrosoftTeamsNotifier.class), is(instanceOf(MicrosoftTeamsNotifier.class)));
114115
}
115116

117+
@Test
118+
public void test_telegram() {
119+
load(null, "spring.boot.admin.notify.telegram.auth-token:123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11");
120+
assertThat(context.getBean(Notifier.class), is(instanceOf(TelegramNotifier.class)));
121+
}
122+
116123
@Test
117124
public void test_multipleNotifiers() {
118125
load(TestMultipleNotifierConfig.class);

0 commit comments

Comments
 (0)