Spring Boot Admin實現服務健康預警
阿新 • • 發佈:2020-05-15
## Over View
上一篇文章主要介紹了Spring Boot Admin的概況以及我們如何在系統中引入和使用Spring Boot Admin,以此來幫助我們更加了解自己的系統,做到能快速發現、排查問題。本篇文章將用程式碼演示Spring Boot Admin的訊息通知功能,並利用這個開箱即用的特性來個性化我們的需求,優化我們在服務治理方面的工作效率。
Spring Boot Admin內建了多種開箱即用的系統通知渠道,包括郵件、Slack、Telegram、Hipchat等多種社交媒體的通知渠道。但是考慮到它所支援的大都是一些國外的主流社交媒體,在國內的本地化可能並不是那麼的友好。不過沒關係Spring Boot Admin也提供了通用的介面,使得使用者可以基於他所提供的介面來自定義通知方式。下面使用Spring Boot Admin的通知功能來實現基於郵件和國內辦公軟體“飛書”的服務健康預警。
---
## 郵件預警
### 依賴引入
在Spring Boot Admin的服務端專案中引入郵件相關依賴
```xml
org.springframework.boot
spring-boot-starter-mail
```
### 新增配置
新增Spring Mail相關配置,我們配置好我們郵箱的Smtp伺服器相關資訊
```properties
spring.mail.host=your email smtp server
spring.mail.password=your password
spring.mail.port=your email smtp server port
spring.mail.test-connection=true
[email protected]
```
新增Spring Boot Admin(SBA)中相關的郵件配置,以下是SBA官方提供的郵件相關引數
| Property name | Description | Default value |
| :-------------------------------------------------- | :----------------------------------------------------------- | :----------------------------------------------------------- |
| spring.boot.admin.notify.mail.enabled | Enable mail notifications | true |
| spring.boot.admin.notify.mail.ignore-changes | Comma-delimited list of status changes to be ignored. Format: ":". Wildcards allowed. | "UNKNOWN:UP" |
| spring.boot.admin.notify.mail.template | Resource path to the Thymeleaf template used for rendering. | "classpath:/META-INF/spring-boot-admin-server/mail/status-changed.html" |
| spring.boot.admin.notify.mail.to | Comma-delimited list of mail recipients | "root@localhost" |
| spring.boot.admin.notify.mail.cc | Comma-delimited list of carbon-copy recipients | |
| spring.boot.admin.notify.mail.from | Mail sender | "Spring Boot Admin " |
| spring.boot.admin.notify.mail.additional-properties | Additional properties which can be accessed from the template | |
我們這裡使用如下配置
```properties
[email protected]
spring.boot.admin.notify.mail.ignore-changes=""
spring.boot.admin.notify.mail.to=目標郵箱
```
配置中的ignore-changes引數表示服務從一個狀態變成其他狀態時發出預警,例如:"UNKNOWN:UP" 表示服務從未知狀態變成UP時,發出通知。當其值是""時,表示任何狀態變更都會發出預警。若想指定其他引數,參考上面的引數表。
完成上述操作後,重啟Spring Boot Admin服務端,當客戶端服務註冊進來並且狀態變為UP時,我們可以收到一封郵件:
![image-20200514220500095](https://tva1.sinaimg.cn/large/007S8ZIlgy1gesbwm70otj318o0hodiq.jpg)
### 新增郵件模版
Spring Boot admin傳送的郵件可以自定義模板樣式,我們使用thymeleaf語法編寫郵件模板,示例模板程式碼可參考本文在Github的[程式碼示例倉庫](https://github.com/cg837718548/sba-server-demo/tree/master/src/main/resources/templates),編寫完模板檔案之後,將檔案放入專案src/main/resources/templates中,並且在配置檔案中增加指定模板檔案的地址:
```properties
spring.boot.admin.notify.mail.template=classpath:/templates/status-changed.html
```
重啟Spring Boot Admin服務端,當客戶端服務註冊進來並且狀態變為UP時,我們可以收到一封郵件,如下是我們對郵件進行本地化之後的樣式:
![image-20200514220449191](https://tva1.sinaimg.cn/large/007S8ZIlgy1gesbwgn8r4j318s0hwdit.jpg)
---
## 飛書預警
由於Spring Boot Admin內建的通知渠道都是國外的社交媒體,不過它也提供了自定義通知渠道的介面,所以我們很容易就可以自定義通知渠道,下面演示整合辦公軟體飛書的通知。
### 獲取通知地址
飛書中提供了聊天機器人,我們只需呼叫機器人的WebHook就可以實現詳細的推送(企業微信,釘釘也具有類似功能)。
![image-20200514232216500](https://tva1.sinaimg.cn/large/007S8ZIlgy1gese51m47rj31900u0jzo.jpg)
### 自定義通知渠道
Spring Boot Admin中提供了一個AbstractStatusChangeNotifier抽象類,我們可以通過繼承它來自定義通知渠道
```java
public class FlyBookNotifier extends AbstractStatusChangeNotifier {
private static final String DEFAULT_MESSAGE = "#{instance.registration.name} (#{instance.id}) 狀態發生轉變 #{lastStatus} ➡️ #{instance.statusInfo.status} " +
"\n" +
"\n 例項詳情:#{instanceEndpoint}";
private final SpelExpressionParser parser = new SpelExpressionParser();
private RestTemplate restTemplate;
private URI webhookUrl;
private Expression message;
public FlyBookNotifier(InstanceRepository repository, RestTemplate restTemplate) {
super(repository);
this.restTemplate = restTemplate;
this.message = parser.parseExpression(DEFAULT_MESSAGE, ParserContext.TEMPLATE_EXPRESSION);
}
@Override
protected Mono doNotify( InstanceEvent event, Instance instance) {
if (webhookUrl == null) {
return Mono.error(new IllegalStateException("'webhookUrl' must not be null."));
}
return Mono
.fromRunnable(() -> restTemplate.postForEntity(webhookUrl, createMessage(event, instance), Void.class));
}
public void setRestTemplate(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
protected Object createMessage(InstanceEvent event, Instance instance) {
Map messageJson = new HashMap<>();
messageJson.put("title", "