一团滥、背景
sentry告警支持自定義插件,但是最新的版本(21.8.0)默認(rèn)只集成了webhook报强,沒(méi)有了企業(yè)微信灸姊,更無(wú)法支持釘釘。所以我們要實(shí)現(xiàn)其他的告警方式秉溉,比如短信力惯、電話等其他方式,可以接收它的回調(diào)字段以擴(kuò)展多種消息通知方式召嘶。
二父晶、sentry的設(shè)置
1、增加告警渠道
step-1.png
step-2.png
step3.png
2弄跌、新增告警規(guī)則
step-1.png
step-2.png
到這里甲喝,sentry的設(shè)置就已完成。
接下來(lái)就是要實(shí)現(xiàn)webhook铛只,接收并解析回調(diào)信息埠胖,然后調(diào)用企業(yè)微信、SMS等渠道發(fā)送給對(duì)應(yīng)的用戶淳玩。
三直撤、webhoook實(shí)現(xiàn)
1、回調(diào)字段
可以自己寫一個(gè)post的urimapping蜕着,將其完整打印谋竖,詳見下面的java示例代碼。
第一層.png
event明細(xì).png
@PostMapping("/api/msg/callback")
@ResponseBody
public String notify(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String requestResultJson = IOUtils.toString(request.getInputStream(), request.getCharacterEncoding());
if (log.isInfoEnabled()) {
log.info("回調(diào)報(bào)文內(nèi)容是:{}", requestResultJson);
}
Map<String, Object> resultMap = JSON.parseObject(requestResultJson, HashMap.class);
// 自定義的擴(kuò)展字段承匣,也就是寫在蓖乘?后面的字段
String group = request.getParameter("group");
}
2、拼接消息內(nèi)容
2.1悄雅、接口
public interface SentryWebhookService {
String APPLICATION_ID = "operation";
String DEFAULT_GROUP = "trade";
String MSG_SUBJECT = "sentry報(bào)警";
String MSG_TEMPLATE = "**${projectName}** --- ${environment}環(huán)境下出現(xiàn)<font color=\"warning\">告警</font>,需要及時(shí)跟進(jìn)G谩! \n" +
"> 版 本 : **${release}** \n" +
"> \n" +
"> 時(shí) 間 : <font color=\"info\">${timestamp}</font> \n" +
"> \n" +
"> URL : **${culprit}** \n" +
"> \n" +
"> Log類 : **${logger}** \n" +
"> \n" +
"> 詳 情 :[${message}](${url}) \n " +
"> \n" +
"> [如無(wú)法點(diǎn)擊宽闲,請(qǐng)復(fù)制網(wǎng)址: `${url}]`\n";
/**
* 解析sentry回調(diào)信息
*
* @param sentryAlertsRequest
* @return
*/
Map<String, String> parseNotify(String sentryAlertsRequest);
}
2.2众眨、實(shí)現(xiàn)類
@Slf4j
@Service
public class SentryWebhookServiceImpl implements SentryWebhookService {
@Override
public Map<String, String> parseNotify(String sentryAlertsRequest) {
JSONObject jsonObject = JSON.parseObject(sentryAlertsRequest);
Map<String, String> paramMap = Maps.newHashMap();
paramMap.put("projectName", jsonObject.getString("project_name"));
paramMap.put("level", jsonObject.getString("level"));
paramMap.put("culprit", jsonObject.getString("culprit"));
paramMap.put("message", jsonObject.getString("message"));
paramMap.put("logger", jsonObject.getString("logger"));
paramMap.put("url", jsonObject.getString("url"));
// 解析event中的時(shí)間戳握牧,環(huán)境以及版本號(hào)
JSONObject eventObject = jsonObject.getJSONObject("event");
BigDecimal timestamp = new BigDecimal(eventObject.getString("timestamp"));
paramMap.put("timestamp", String.valueOf(DateUtils.ofEpochSecond(timestamp.longValue())));
paramMap.put("environment", eventObject.getString("environment"));
paramMap.put("release", eventObject.getString("release"));
return paramMap;
}
}
2.3、工具類
@Slf4j
public class MessageTemplateUtil {
public static String parseTemplate(String content, Map<String, String> paramMap) {
try {
for (Map.Entry<String, String> entry : paramMap.entrySet()) {
String regex = "\\$\\{" + entry.getKey() + "\\}";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(content);
content = matcher.replaceAll(entry.getValue());
}
} catch (Exception e) {
log.error("解析消息模板出現(xiàn)異常, content={}, paramMap={}", content, JSON.toJSON(paramMap), e);
}
return content;
}
}
2.4娩梨、spring mvc
@Slf4j
@Api(value = "sentry回調(diào)", tags = "sentry回調(diào)")
@RestController
public class SentryCallbackFacade {
@Autowired
private MessageService messageService;
@Autowired
private SentryWebhookService sentryWebhookService;
@PostMapping(value = "/api/sentry/notify")
public ResponseEntity<?> sentryNotify(HttpServletRequest request, HttpServletResponse response)
throws Exception {
// 回調(diào)內(nèi)容沿腰,調(diào)試階段,你通過(guò)log.info()打印輸出
String sentryAlertsRequestJson = IOUtils.toString(request.getInputStream(), request.getCharacterEncoding());
log.debug(sentryAlertsRequestJson);
// 從回調(diào)字段里抽取消息內(nèi)容需要的字段
Map<String, String> paramMap = sentryWebhookService.parseNotify(sentryAlertsRequestJson);
// 接收消息的群組
String group = request.getParameter("group");
// 拼接消息內(nèi)容
final String payload = MessageTemplateUtil.parseTemplate(SentryWebhookService.MSG_TEMPLATE, paramMap);
// 發(fā)送消息
messageService.deliverMessage();
return ResponseEntity.noContent().build();
}
}
3狈定、調(diào)用消息渠道
可以是短信颂龙、企業(yè)微信等渠道,具體不在本文的介紹中纽什。
對(duì)應(yīng)上面的messageService.deliverMessage()