持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第14天,点击查看活动详情
背景 最近公司启动一个新项目,我加入项目之后发现团队成员又很多新手,本人作为后端负责人又当爹又当妈,怎么奈团队成员责任心不够,经常出现一些莫名其妙的问题,而他们自己发现问题还不主动去解决,我又来不及每天去做代码review,思来想去只有借助工具了。于是开始着手做一个异常提醒,把日志的异常推送到群里,开发环境只要发生了异常就推送到群里,我就能实时跟进,尽量把问题暴露在前期。话不多说,开干!
步骤 0、定义企业微信推送工具类
public class WeChatUtils {
private static String wechatHook;
private static final String WECHAT_MSG_TYPE = "markdown";
private WeChatUtils(){}
public static synchronized void setWechatHook(String hook) {
wechatHook = hook;
}
public static void pushWechatMsg(String content) {
if(StringUtils.isBlank(wechatHook)) {
return;
}
Map msg = new HashMap();
msg.put("msgtype", WECHAT_MSG_TYPE);
Map contentMap = new HashMap();
contentMap.put("content", content);
msg.put(WECHAT_MSG_TYPE, contentMap);
HttpUtil.post(wechatHook, JSON.toJSONString(msg));
}
}
@Configuration
public class WeChatConfig implements ApplicationContextAware {
@Value("${anychat.consult.wechat-hook}")
private String weChatHook;
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
WeChatUtils.setWechatHook(weChatHook);
}
}
1、捕获全局异常,推送企业微信机器人
@ControllerAdvice
@ResponseBody
public class GlobalExceptionHandler {
public static final String PARAM_VALID_MSG = "字段不合法";
private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
@ExceptionHandler(Exception.class)
public ResultModel handle(Exception e){
if (e instanceof MethodArgumentNotValidException) {
MethodArgumentNotValidException validException = (MethodArgumentNotValidException) e;
List<ObjectError> allErrors = validException.getBindingResult().getAllErrors();
String validMsg = PARAM_VALID_MSG;
if(!allErrors.isEmpty()) {
validMsg = allErrors.get(0).getDefaultMessage();
}
return ResultModel.fail(HttpStatus.HTTP_NOT_ACCEPTABLE, validMsg);
} else {
logger.error("系统异常", e);
WeChatUtils.pushWechatMsg(e.toString());
return ResultModel.fail();
}
}
}
由于我这里使用了hibernate-validator做参数校验,所以这里排除了MethodArgumentNotValidException这种特定的异常不进行异常推送。
轻松2步就搞定了,一旦发生异常,就可以推送到我们开发群里,从此妈妈再也不用担心后端的异常没人管了。
但是用着用着发现有些没有抛出异常的问题还是不能暴露出来,比如很多没抛出异常但是做了异常日志打印的,那这种异常日志怎么能也推送到企业微信。既然有日志输出,那通过日志框架是不是能够解决?经过查找资料,果然logback没有让我失望。
2、在logback配置文件中自定义appender
<appender name="SendWeChatMsgAppender" class="com.***.***.***.util.SendWeChatMsgAppender">
</appender>
<logger name="com..***.***.***" additivity="true" level="INFO">
<appender-ref ref="SendWeChatMsgAppender" />
</logger>
3、定义日志Appender的类,自定义输出级别为ERROR的日志内容,因为有时候异常的堆栈信息太长,所以此处做了长度限制
public class SendWeChatMsgAppender extends UnsynchronizedAppenderBase<ILoggingEvent> {
@Override
protected void append(ILoggingEvent event) {
if (event.getLevel() == Level.ERROR) {
IThrowableProxy iThrowableProxy = event.getThrowableProxy();
StringBuilder sb = new StringBuilder();
if (iThrowableProxy instanceof ThrowableProxy) {
ThrowableProxy throwableProxy = (ThrowableProxy) iThrowableProxy;
Throwable throwable = throwableProxy.getThrowable();
String throwableMsg = throwable.getMessage();
StackTraceElementProxy[] stackTraceElementProxy = iThrowableProxy.getStackTraceElementProxyArray();
sb.append(event.getMessage()).append("\n");
if (StringUtils.isNotEmpty(throwableMsg)) {
sb.append(throwableMsg).append("\n");
}
for (StackTraceElementProxy proxy : stackTraceElementProxy) {
sb.append(proxy.getSTEAsString()).append("\n");
}
} else {
sb.append(event.getMessage());
}
if(sb.length()>4000){
sb.setLength(4000);
}
String msg = sb.toString();
if (StringUtils.isNotEmpty(msg)) {
WeChatUtils.pushWechatMsg(msg);
}
}
}
}
总结 从此之后,看到有异常推送到群里,差不多就能知道问题出在哪里,可以及时@相关同学跟进处理,效率还是比较高的,一定程度上把问题暴露在前期,提高了代码质量,也提高了团队成员的责任心和代码质量。有时候人是有弱点的是比较难自主克服的,所以要靠工具,工具是无情的,它可以推着你前进。