博主
258
258
258
258
专辑

第三十五节 SpringBoot项目自定义Appender记录日志到数据库

亮子 2023-06-02 09:26:27 724 0 0 0

1、自定义Apppender类

package com.shenma2009.logs;

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
import ch.qos.logback.classic.spi.LoggingEvent;
import ch.qos.logback.core.AppenderBase;
import cn.hutool.core.date.DateUtil;
import lombok.Getter;
import lombok.Setter;

import java.util.Date;

/**
 * @author 军哥
 * @version 1.0
 * @description: ShenmaLogAppender2
 * @date 2023/6/1 15:17
 */

@Getter
@Setter
public class ShenmaLogAppender2 extends AppenderBase<LoggingEvent> {
    PatternLayoutEncoder encoder;


    @Override
    public void start() {
        if (this.encoder == null) {
            //name : logback-spring.xml 中 appender 标签 配置的name值
            addError("No encoder set for the appender named [" + name + "].");
            return;
        }
        
        // 连接数据库

        super.start();
    }

    @Override
    public void stop() {
        //释放相关资源,如数据库连接,redis线程池等等
        System.out.println("stop方法被调用");
        if (!isStarted()) {
            return;
        }
        super.stop();
    }

    @Override
    protected void append(LoggingEvent eventObject) {
        Level level = eventObject.getLevel();

        // 日志时间
        Date date = new Date(eventObject.getTimeStamp());
        String format = DateUtil.format(date, "yyyy-MM-dd HH:mm:ss.SSS");
        System.out.println("=> " + format);

        // 线程名
        System.out.println("=> "+eventObject.getThreadName());

        // 日志级别
        System.out.println("=> "+eventObject.getLevel().levelStr);

        // 日志名字
        System.out.println("=> "+eventObject.getLoggerName());

        // 日志消息
        System.out.println("=> "+eventObject.getFormattedMessage());

        StackTraceElement[] callerData = eventObject.getCallerData();

        for (StackTraceElement element : callerData) {
            System.out.println(element.getClassName());
            System.out.println(element.getMethodName());
            System.out.println(element.getFileName());
            System.out.println(element.getLineNumber());
        }
        
        // 把日志信息存入数据库

        /**
         * 指定只有 error 级别的日志,才发记录消息
         * 后续可以根据配置指定,此处暂不实现
         */
        if (Level.ERROR.levelInt == level.levelInt) {

        }
    }
}

2、在resources目录下创建logback-spring.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">
    <!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->
    <property name="LOG_HOME" value="/test/log" />
    <!-- 控制台输出 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
        </encoder>
    </appender>

    <!-- 按照每天生成日志文件 -->
    <appender name="FILE"  class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!--日志文件输出的文件名-->
            <FileNamePattern>${LOG_HOME}/askapi.%d{yyyyMMdd}.%i.log</FileNamePattern>
            <!-- 日志文件最大尺寸 -->
            <maxFileSize>10MB</maxFileSize>
            <!--日志文件保留天数-->
            <MaxHistory>7</MaxHistory>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
        </encoder>
    </appender>

    <appender name="ShenmaLogAppender2" class="com.shenma2009.logs.ShenmaLogAppender2">
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <!-- 日志收集最低日志级别 -->
            <level>TRACE</level>
        </filter>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符 -->
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
        </encoder>
    </appender>


    <!-- 日志输出级别 -->
    <root level="INFO">
        <appender-ref ref="STDOUT" />
        <appender-ref ref="ShenmaLogAppender2" />
    </root>

</configuration>

如图:

图片alt

3、对异常要特殊处理

由于在日志的appender中,格式化异常消息,始终无法令人满意,因此增加了全局异常,来对异常进行单独的数据存储。代码如下:

package com.shenma2009.ex;

import org.apache.tomcat.util.log.SystemLogHandler;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.StringWriter;

/**
 * @author 军哥
 * @version 1.0
 * @description: MyExceptionHandler
 * @date 2023/6/2 15:23
 */

@ControllerAdvice
public class MyExceptionHandler {

    @ExceptionHandler(value =Exception.class)
    @ResponseBody
    public String exceptionHandler(Exception e){
        System.out.println("全局异常捕获>>>:"+e);

        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw);
        e.printStackTrace(pw);
        String msg = sw.toString();
        System.out.println(msg);
        
        // 把异常信息存入数据库
        //

        return "全局异常捕获,错误原因>>>"+msg;
    }
}