springboot中logback自动发送error日志告警到钉钉

1、自定义appender,先在logback.xml中配置

  <appender name="SendErrorMsgAppender"
              class="com.xxx.xxx.xxx.common.SendErrorMsgAppender"></appender>

2、配置Appender引用,这步不能少,少了Appender不启作用

<logger name="root" level="info" additivity="false">
        <appender-ref ref="CONSOLE"/>
        <appender-ref ref="ASYNC"/>
        <appender-ref ref="SendErrorMsgAppender"/>
    </logger>

    <logger name="com.xxx" level="debug"
            additivity="false">
        <appender-ref ref="CONSOLE"/>
        <appender-ref ref="ASYNC"/>
        <appender-ref ref="SendErrorMsgAppender"/>
    </logger>

 

3、extends UnsynchronizedAppenderBase 用于异步处理,不阻塞主线程;例如自定义发送日志到消息队列。

需要在钉钉群创建机器人,并在电脑客户端获取access_token

@Slf4j
public class SendErrorMsgAppender extends UnsynchronizedAppenderBase<ILoggingEvent> {

    private static final String url = "https://oapi.dingtalk.com/robot/send?access_token=%s";

    private HttpHeaders headers;

    public SendErrorMsgAppender() {
        headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
    }

    @Override
    public void append(ILoggingEvent event) {
        if (event.getLevel() == Level.ERROR) {
            SysProperties sysProperties = getApplicationContext().getBean("sysProperties", SysProperties.class);
            //没有启用
            if (!sysProperties.getWaringDingdingEnable()) {
                return;
            }
            IThrowableProxy iThrowableProxy = event.getThrowableProxy();
            StringBuilder sb = new StringBuilder();
            if (iThrowableProxy != null && iThrowableProxy instanceof ThrowableProxy) {
                ThrowableProxy throwableProxy = (ThrowableProxy) iThrowableProxy;
                Throwable throwable = throwableProxy.getThrowable();
                String throwableMsg = throwable.getMessage();
                StackTraceElementProxy[] stackTraceElementProxy = iThrowableProxy.getStackTraceElementProxyArray();
                //获取服务器Ip,告知哪台服务器抛异常
                String ip = Context.getContext().getIp();
                if (null != ip) {
                    sb.append("服务器:").append(ip).append("\n");
                }
                sb.append(event.getMessage()).append("\n");
                if (StringUtils.isNotEmpty(throwableMsg)) {
                    sb.append(throwableMsg).append("\n");
                }
                int i = 0;
                for (StackTraceElementProxy proxy : stackTraceElementProxy) {
                    //只打印40行的堆栈
                    if (i < 40) {
                        sb.append(proxy.getSTEAsString()).append("\n");
                    } else {
                        break;
                    }
                    i++;
                }
            } else {
                sb.append(event.getMessage());
            }
            String msg = sb.toString();
            if (StringUtils.isNotEmpty(msg)) {
                sendMsgToDingDing(msg);
            }
        }
    }


    /**
     * @param msg
     * @return
     */
    private Map<String, Object> sendMsgToDingDing(String msg) {
        RestTemplate restTemplate = getApplicationContext().getBean("restTemplate", RestTemplate.class);
        SysProperties sysProperties = getApplicationContext().getBean("sysProperties", SysProperties.class);
        ObjectMapper objectMapper = getApplicationContext().getBean("jacksonObjectMapper", ObjectMapper.class);
        Text text = new Text();
        text.setContent(msg);
        DdMsgBody msgBody = DdMsgBody.builder().msgtype("text").text(text).build();
        String json = null;
        try {
            json = objectMapper.writeValueAsString(msgBody);
        } catch (JsonProcessingException e) {
            //不记录日志,有可能死循环
            //log.error("error", e);
        }
        if (null == json) {
            return null;
        }
        HttpEntity<String> formEntity = new HttpEntity<>(json, headers);
        String formatUrl = String.format(url, sysProperties.getWaringDingdingToken());
        Map<String, Object> result = restTemplate.postForObject(formatUrl, formEntity, Map.class);
        return result;
    }

    private ApplicationContext getApplicationContext() {
        return ApplicationContextUtils.getApplicationContext();
    }

    @Builder
    @Data
    private static class DdMsgBody {
        private String msgtype;
        private Text text;
    }

    @Data
    private class Text {
        private String content;
    }

}

 

  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值