评论

收藏

[Linux] 扩展logback日志来发送异常信息邮件

服务系统 服务系统 发布于:2022-09-01 11:22 | 阅读数:526 | 评论:0

系统异常了,上篇是通过在全局异常中通过调用发送邮件的处理器代码进行邮件的发送,总是觉得还不那么优雅。
这篇是通过扩展 logback 的日志插件来处理 err 级别的日志异常信息来发送邮件的。
通过这篇的学习,可以掌握如何扩展 logback 的日志类,来实现自己不可告人的目的。
下面直接上代码。
首先自定义一个日志处理处理类 wlcLogLogbackAppender。
import ch.qos.logback.classic.spi.LoggingEvent;
import ch.qos.logback.classic.spi.ThrowableProxy;
import ch.qos.logback.core.AppenderBase;
import com.handler.WlcAsyncHandler;
import com.utils.SpringContextUtil;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.Objects;
/**
 * 描述: 自定义日志处理类 
 * 时间: 2021-07-01 11:11  
 * 作者:IT学习道场
 */
public class wlcLogLogbackAppender extends AppenderBase{
  @Override
  protected void append(LoggingEvent eventObject) {
    if(eventObject instanceof LoggingEvent){
      LoggingEvent loggingEvent = (LoggingEvent)eventObject;
      //拿到ThrowableProxy
      ThrowableProxy throwableProxy = (ThrowableProxy) loggingEvent.getThrowableProxy();
      if (Objects.nonNull(throwableProxy)) {
        //获取 throwable 顶级异常
        Throwable throwable = throwableProxy.getThrowable();
        //获取log的msg
        String formattedMessage = loggingEvent.getFormattedMessage();
        //获取请求request
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder
            .getRequestAttributes()).getRequest();
        //获取spring的spring.mail.enable属性值,下面的逻辑你也可以自己根据想法自己玩也行
        String mailEnableProperty = SpringContextUtil.getEnvironmentProperty("spring.mail.enable");
        mailEnableProperty = (mailEnableProperty == null) ? "false" : mailEnableProperty;
        boolean mailEnable = Boolean.valueOf(mailEnableProperty);
        if (mailEnable){
          //获取邮件的处理类
          WlcAsyncHandler emailHandler = SpringContextUtil.getBean(WlcAsyncHandler.class);
          emailHandler.handle(formattedMessage, throwable, request);
        }
      }
    }
    super.doAppend(eventObject);
  }
}
自定义的日志处理类搞完了,剩下的就是在logback-spring.xml中配置下就行,配置级别是 error 级别。
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <!-- 修改一下路径-->
  <property name="PATH" value="./log"></property>
  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <!--      <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %highlight(%-5level) %blue(%-50logger{50}:%-4line) %thread %green(%-18X{LOG_ID}) %msg%n</Pattern>-->
      <Pattern>%d{ss.SSS} %highlight(%-5level) %blue(%-30logger{30}:%-4line) %thread %green(%-18X{LOG_ID}) %msg%n</Pattern>
    </encoder>
  </appender>
  <appender name="TRACE_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>${PATH}/trace/trace.log</file>
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
      <FileNamePattern>${PATH}/trace/trace.%d{yyyy-MM-dd}.%i.log</FileNamePattern>
      <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
        <maxFileSize>10MB</maxFileSize>
      </timeBasedFileNamingAndTriggeringPolicy>
      <!--因为 FileNamePattern 配置规则是yyyy-MM-dd,就是天,所以maxHistory代表多少天-->
      <cleanHistoryOnStart>true</cleanHistoryOnStart>
      <!--maxHistory生效必须加 <cleanHistoryOnStart>true</cleanHistoryOnStart>-->
      <maxHistory>15</maxHistory>
    </rollingPolicy>
    <layout>
      <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %-50logger{50}:%-4line %green(%-18X{LOG_ID}) %msg%n</pattern>
    </layout>
  </appender>
  <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>${PATH}/error/error.log</file>
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
      <FileNamePattern>${PATH}/error/error.%d{yyyy-MM-dd}.%i.log</FileNamePattern>
      <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
        <maxFileSize>10MB</maxFileSize>
      </timeBasedFileNamingAndTriggeringPolicy>
      <cleanHistoryOnStart>true</cleanHistoryOnStart>
      <maxHistory>15</maxHistory>
    </rollingPolicy>
    <layout>
      <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %-50logger{50}:%-4line %green(%-18X{LOG_ID}) %msg%n</pattern>
    </layout>
    <filter class="ch.qos.logback.classic.filter.LevelFilter">
      <level>ERROR</level>
      <onMatch>ACCEPT</onMatch>
      <onMismatch>DENY</onMismatch>
    </filter>
  </appender>
  <!--配置自定义的日志处理了-->
  <appender name="WlcLog" class="com.logback.wlcLogLogbackAppender">
    <filter class="ch.qos.logback.classic.filter.LevelFilter">
      <level>ERROR</level>
      <onMatch>ACCEPT</onMatch>
      <onMismatch>DENY</onMismatch>
    </filter>
  </appender>
  <!--ERROR级别调用-->
  <root level="ERROR">
    <appender-ref ref="ERROR_FILE" />
    <appender-ref ref="WlcLog" />
  </root>
  <root level="TRACE">
    <appender-ref ref="TRACE_FILE" />
  </root>
  <root level="INFO">
    <appender-ref ref="STDOUT" />
  </root>
</configuration>
当然由于:
判断了异常不为空时,想要进去判断,就需要在log输出日志时,要注入 Throwable。
如下:
必须用 log.error("这是一个日志msg", e)。
这样 :
ThrowableProxy throwableProxy = (ThrowableProxy) loggingEvent.getThrowableProxy();
throwableProxy 就不等于 null。
像 log.error("这是一个日志msg")。
throwableProxy 就等于 null。
这样自定义一个日志处理处理类 wlcLogLogbackAppender 就生效了。
你可以 wlcLogLogbackAppender 在里面你可以拿到日志信息,做一些自己想做的事情。比如我这边就是在里面发送邮件,当然你可以做任何事。