异常推送企业微信,让bug无处藏身

353 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 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);
            }
        }
    }

}

总结 从此之后,看到有异常推送到群里,差不多就能知道问题出在哪里,可以及时@相关同学跟进处理,效率还是比较高的,一定程度上把问题暴露在前期,提高了代码质量,也提高了团队成员的责任心和代码质量。有时候人是有弱点的是比较难自主克服的,所以要靠工具,工具是无情的,它可以推着你前进。