提交 c3aa5731 authored 作者: Edwin's avatar Edwin

feat: 优化告警服务

上级 c17c3248
...@@ -3,6 +3,7 @@ package com.ebaiyihui.alarm.server.service.Impl; ...@@ -3,6 +3,7 @@ package com.ebaiyihui.alarm.server.service.Impl;
import com.ebaiyihui.alarm.server.config.ProjProperties; import com.ebaiyihui.alarm.server.config.ProjProperties;
import com.ebaiyihui.alarm.server.config.ServiceInfo; import com.ebaiyihui.alarm.server.config.ServiceInfo;
import com.ebaiyihui.alarm.server.entity.AlarmMessage; import com.ebaiyihui.alarm.server.entity.AlarmMessage;
import com.ebaiyihui.alarm.server.entity.Tag;
import com.ebaiyihui.alarm.server.service.AlarmService; import com.ebaiyihui.alarm.server.service.AlarmService;
import com.ebaiyihui.alarm.server.util.HttpKit; import com.ebaiyihui.alarm.server.util.HttpKit;
import com.ebaiyihui.framework.utils.StringUtil; import com.ebaiyihui.framework.utils.StringUtil;
...@@ -18,7 +19,10 @@ import javax.crypto.spec.SecretKeySpec; ...@@ -18,7 +19,10 @@ import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidKeyException; import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.*; import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
...@@ -33,6 +37,30 @@ public class AlarmServiceImpl implements AlarmService { ...@@ -33,6 +37,30 @@ public class AlarmServiceImpl implements AlarmService {
private static final String ENDPOINT_RELATION = "ENDPOINT_RELATION"; private static final String ENDPOINT_RELATION = "ENDPOINT_RELATION";
private static final String SERVICE = "SERVICE"; private static final String SERVICE = "SERVICE";
private static final Pattern SERVICE_INSTANCE_RESPONSE_TIME_PATTERN = Pattern.compile(
"Response time of service instance (.+) of (.+) is more than (.+) in (.+) of last (.+)",
Pattern.CASE_INSENSITIVE
);
private static final Pattern SERVICE_RESPONSE_TIME_PATTERN = Pattern.compile(
"Response time of service (.+) is more than (.+) in (.+) of last (.+)",
Pattern.CASE_INSENSITIVE
);
private static final Pattern ENDPOINT_RESPONSE_TIME_PATTERN = Pattern.compile(
"Response time of endpoint (.+) in service (.+) is more than (.+) in (.+) of last (.+)",
Pattern.CASE_INSENSITIVE
);
private static final Pattern SERVICE_ERROR_RATE_PATTERN = Pattern.compile(
"Error rate of service (.+) is more than (.+) in (.+) of last (.+)",
Pattern.CASE_INSENSITIVE
);
private static final Pattern ENDPOINT_ERROR_RATE_PATTERN = Pattern.compile(
"Error rate of endpoint (.+) in service (.+) is more than (.+) in (.+) of last (.+)",
Pattern.CASE_INSENSITIVE
);
private static final Pattern SERVICE_INSTANCE_DOWN_PATTERN = Pattern.compile(
"Service instance (.+) of (.+) is down in (.+) of last (.+)",
Pattern.CASE_INSENSITIVE
);
@Value("${webHookUrl}") @Value("${webHookUrl}")
private String webHookUrl; private String webHookUrl;
...@@ -87,14 +115,12 @@ public class AlarmServiceImpl implements AlarmService { ...@@ -87,14 +115,12 @@ public class AlarmServiceImpl implements AlarmService {
} }
private String buildNotifyMessage(AlarmMessage alarmMessage) { private String buildNotifyMessage(AlarmMessage alarmMessage) {
String message = alarmMessage.getAlarmMessage(); String rawMessage = alarmMessage.getAlarmMessage();
if (StringUtil.isBlank(message)) { if (StringUtil.isBlank(rawMessage)) {
return ""; return "";
} }
String serviceName = extractServiceName(alarmMessage.getName()); String serviceName = extractServiceName(alarmMessage.getName());
if (StringUtil.isBlank(serviceName)) { String message = formatReadableMessage(alarmMessage, serviceName, rawMessage);
return message;
}
List<ServiceInfo> serviceInfos = projProperties.getServiceInfo(); List<ServiceInfo> serviceInfos = projProperties.getServiceInfo();
if (serviceInfos == null || serviceInfos.isEmpty()) { if (serviceInfos == null || serviceInfos.isEmpty()) {
return message; return message;
...@@ -112,6 +138,141 @@ public class AlarmServiceImpl implements AlarmService { ...@@ -112,6 +138,141 @@ public class AlarmServiceImpl implements AlarmService {
return message; return message;
} }
private String formatReadableMessage(AlarmMessage alarmMessage, String serviceName, String rawMessage) {
StringBuilder builder = new StringBuilder();
builder.append("【SkyWalking 告警】");
if (!StringUtil.isBlank(alarmMessage.getScope())) {
builder.append("\n范围: ").append(alarmMessage.getScope());
}
if (!StringUtil.isBlank(serviceName)) {
builder.append("\n服务: ").append(serviceName);
} else if (!StringUtil.isBlank(alarmMessage.getName())) {
builder.append("\n对象: ").append(alarmMessage.getName());
}
if (!StringUtil.isBlank(alarmMessage.getId0())) {
builder.append("\nID0: ").append(alarmMessage.getId0());
}
if (!StringUtil.isBlank(alarmMessage.getId1())) {
builder.append("\nID1: ").append(alarmMessage.getId1());
}
if (!StringUtil.isBlank(alarmMessage.getRuleName())) {
builder.append("\n规则: ").append(alarmMessage.getRuleName());
}
String startTime = formatStartTime(alarmMessage.getStartTime());
if (!StringUtil.isBlank(startTime)) {
builder.append("\n触发时间: ").append(startTime);
}
List<String> tagList = Tag.Util.toStringList(alarmMessage.getTags());
if (!tagList.isEmpty()) {
builder.append("\n标签: ").append(String.join(", ", tagList));
}
if (appendKnownAlarmDetail(builder, serviceName, rawMessage)) {
return builder.toString();
}
builder.append("\n详情: ").append(rawMessage);
return builder.toString();
}
private boolean appendKnownAlarmDetail(StringBuilder builder, String serviceName, String rawMessage) {
Matcher matcher = SERVICE_INSTANCE_RESPONSE_TIME_PATTERN.matcher(rawMessage);
if (matcher.find()) {
builder.append("\n类型: 响应时间过高");
builder.append("\n实例: ").append(matcher.group(1));
if (StringUtil.isBlank(serviceName)) {
builder.append("\n服务: ").append(matcher.group(2));
}
builder.append("\n阈值: > ").append(matcher.group(3));
builder.append("\n窗口: 最近").append(normalizeDuration(matcher.group(5)))
.append("内有").append(normalizeDuration(matcher.group(4))).append("超过阈值");
return true;
}
matcher = SERVICE_RESPONSE_TIME_PATTERN.matcher(rawMessage);
if (matcher.find()) {
builder.append("\n类型: 服务响应时间过高");
if (StringUtil.isBlank(serviceName)) {
builder.append("\n服务: ").append(matcher.group(1));
}
builder.append("\n阈值: > ").append(matcher.group(2));
builder.append("\n窗口: 最近").append(normalizeDuration(matcher.group(4)))
.append("内有").append(normalizeDuration(matcher.group(3))).append("超过阈值");
return true;
}
matcher = ENDPOINT_RESPONSE_TIME_PATTERN.matcher(rawMessage);
if (matcher.find()) {
builder.append("\n类型: 接口响应时间过高");
builder.append("\n接口: ").append(matcher.group(1));
if (StringUtil.isBlank(serviceName)) {
builder.append("\n服务: ").append(matcher.group(2));
}
builder.append("\n阈值: > ").append(matcher.group(3));
builder.append("\n窗口: 最近").append(normalizeDuration(matcher.group(5)))
.append("内有").append(normalizeDuration(matcher.group(4))).append("超过阈值");
return true;
}
matcher = SERVICE_ERROR_RATE_PATTERN.matcher(rawMessage);
if (matcher.find()) {
builder.append("\n类型: 服务错误率过高");
if (StringUtil.isBlank(serviceName)) {
builder.append("\n服务: ").append(matcher.group(1));
}
builder.append("\n阈值: > ").append(matcher.group(2));
builder.append("\n窗口: 最近").append(normalizeDuration(matcher.group(4)))
.append("内有").append(normalizeDuration(matcher.group(3))).append("超过阈值");
return true;
}
matcher = ENDPOINT_ERROR_RATE_PATTERN.matcher(rawMessage);
if (matcher.find()) {
builder.append("\n类型: 接口错误率过高");
builder.append("\n接口: ").append(matcher.group(1));
if (StringUtil.isBlank(serviceName)) {
builder.append("\n服务: ").append(matcher.group(2));
}
builder.append("\n阈值: > ").append(matcher.group(3));
builder.append("\n窗口: 最近").append(normalizeDuration(matcher.group(5)))
.append("内有").append(normalizeDuration(matcher.group(4))).append("超过阈值");
return true;
}
matcher = SERVICE_INSTANCE_DOWN_PATTERN.matcher(rawMessage);
if (matcher.find()) {
builder.append("\n类型: 实例存活异常");
builder.append("\n实例: ").append(matcher.group(1));
if (StringUtil.isBlank(serviceName)) {
builder.append("\n服务: ").append(matcher.group(2));
}
builder.append("\n窗口: 最近").append(normalizeDuration(matcher.group(4)))
.append("内有").append(normalizeDuration(matcher.group(3))).append("不可用");
return true;
}
return false;
}
private String normalizeDuration(String value) {
if (StringUtil.isBlank(value)) {
return "";
}
return value.trim()
.replace(" minutes", "分钟")
.replace(" minute", "分钟")
.replace(" seconds", "秒")
.replace(" second", "秒");
}
private String formatStartTime(long startTime) {
if (startTime <= 0) {
return "";
}
long timestamp = startTime;
if (String.valueOf(startTime).length() == 10) {
timestamp = startTime * 1000;
}
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(timestamp));
}
private String extractServiceName(String name) { private String extractServiceName(String name) {
if (StringUtil.isBlank(name)) { if (StringUtil.isBlank(name)) {
return ""; return "";
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论