关于springboot默认日志框架Slf4j+logback,自定义Appender问题

第一种:

import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.filter.ThresholdFilter;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.classic.spi.IThrowableProxy;
import ch.qos.logback.classic.spi.StackTraceElementProxy;
import ch.qos.logback.core.CoreConstants;
import ch.qos.logback.core.UnsynchronizedAppenderBase;
import ch.qos.logback.core.helpers.Transform;
import com.test.domain.ErrorLog;
import com.test.service.ErrorLogService;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.Date;

@Component
public class DbErrorLogAppender extends UnsynchronizedAppenderBase<ILoggingEvent> {

    /**
     * 错误日志数据库增删改查服务
     */
    @Autowired
    private ErrorLogService errorLogService;


    /**
     * DbErrorLogAppender初始化
     */
    @PostConstruct
    public void init() {
        LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();

        ThresholdFilter filter = new ThresholdFilter();
        filter.setLevel("ERROR");
        filter.setContext(context);
        filter.start();
        this.addFilter(filter);
        this.setContext(context);

        context.getLogger("ROOT").addAppender(DbErrorLogAppender.this);

        super.start();
    }

    /**
     * 错误日志拼装成实体类,写入数据库
     */
    @Override
    protected void append(ILoggingEvent loggingEvent) {
        IThrowableProxy tp = loggingEvent.getThrowableProxy();

        // ErrorLogPO数据表实体类
        ErrorLog errorLog = new ErrorLog();
        errorLog.setLevel(1);
        errorLog.setReason("reason");
        errorLog.setClassName("setClassName");
        errorLog.setContent("content");
        errorLog.setCreateTime(new Date(loggingEvent.getTimeStamp()));

        try {
            // 错误日志实体类写入数据库
            errorLogService.addErrorLog(errorLog);
        } catch (Exception ex) {
            this.addError("上报错误日志失败:" + ex.getMessage());
        }
    }

}

该类会在报错之后调用,无需配置,写入数据库,直接继承UnsynchronizedAppenderBase<ILoggingEvent>。

 第二种:

import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.classic.spi.IThrowableProxy;
import ch.qos.logback.core.db.DBAppenderBase;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Timestamp;

@Component
public class LogDBAppender extends DBAppenderBase<ILoggingEvent> {

    protected static final Method GET_GENERATED_KEYS_METHOD;

    //插入sql
    protected String insertSQL;

    static final int LEVEL = 1;

    static final int REASON = 2;

    static final int CLASS_NAME = 3;

    static final int CONTENT = 4;

    static final int CREATE_TIME = 5;

    //static final StackTraceElement EMPTY_CALLER_DATA = CallerData.naInstance();

    static {
        Method getGeneratedKeysMethod;
        try {
            getGeneratedKeysMethod = PreparedStatement.class.getMethod("getGeneratedKeys", (Class[]) null);
        } catch (Exception ex) {
            getGeneratedKeysMethod = null;
        }
        GET_GENERATED_KEYS_METHOD = getGeneratedKeysMethod;
    }

    @Override
    public void start() {
        insertSQL = buildInsertSQL();
        super.start();
    }

    private static String buildInsertSQL() {
        return "INSERT INTO `error_log`(`level`,`reason`,`class_name`,`content`,`create_time`) VALUES (?,?,?,?,?)";
    }

    @Override
    protected Method getGeneratedKeysMethod() {
        return GET_GENERATED_KEYS_METHOD;
    }

    @Override
    protected String getInsertSQL() {
        return insertSQL;
    }

    /**
     * 主要修改的方法
     *
     * @param stmt
     * @param event
     * @throws SQLException
     */
    private void bindLoggingEventWithInsertStatement(PreparedStatement stmt, ILoggingEvent event) throws SQLException {
        String message = event.getFormattedMessage();
        Object[] argumentArray = event.getArgumentArray();
//        stmt.setString(LEVELevent.getLevel().toString());
        if(argumentArray.length>0){
            stmt.setString(LEVEL, String.valueOf(argumentArray[0]));
            stmt.setString(REASON, String.valueOf(argumentArray[1]));
        }else{
            stmt.setString(LEVEL, "未填写");
            stmt.setString(REASON, "未填写");
        }
        stmt.setString(CLASS_NAME, event.getLoggerName());
        IThrowableProxy throwableProxy = event.getThrowableProxy();
        if(throwableProxy!=null){
            StringBuffer s = new StringBuffer(throwableProxy.getClassName());
            s.append(throwableProxy.getMessage());
            stmt.setString(CONTENT, s.toString());
        }else{
            stmt.setString(CONTENT, "未传入异常");
        }
        stmt.setTimestamp(CREATE_TIME, new Timestamp(event.getTimeStamp()));
    }

    @Override
    protected void subAppend(ILoggingEvent eventObject, Connection connection, PreparedStatement statement) throws Throwable {
        bindLoggingEventWithInsertStatement(statement, eventObject);
        int updateCount = statement.executeUpdate();
        if (updateCount != 1) {
            addWarn("Failed to insert loggingEvent");
        }
    }

    @Override
    protected void secondarySubAppend(ILoggingEvent eventObject, Connection connection, long eventId) throws Throwable {
    }
}
继承DBAppenderBase<ILoggingEvent>,需配置logback.xml
<configuration scan="true" scanPeriod="60 seconds" debug="false">

    <property name="LOG_HOME" value="D:/test_log"/>
    <property name="LOG_NAME" value="testLog"/>

    <!--输出到控制台-->
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} : %msg%n</pattern>
            <charset>UTF-8</charset>
        </encoder>
    </appender>
    <appender name="error_db_appender" class="com.test.LogDBAppender">
        <connectionSource class="ch.qos.logback.core.db.DataSourceConnectionSource">
            <dataSource class="org.apache.commons.dbcp.BasicDataSource">
                <driverClassName>com.mysql.cj.jdbc.Driver</driverClassName>
                <url>jdbc:mysql://localhost:3306/test</url>
                <username>root</username>
                <password>****</password>
            </dataSource>
        </connectionSource>
        <!-- 只打印错误日志 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>error</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>


    <!--根节点-->
    <root level="INFO">
        <appender-ref ref="console"/>
        <appender-ref ref="error_db_appender" />
    </root>

</configuration>

 

posted @ 2020-05-20 15:14  晨风啊  阅读(3008)  评论(1编辑  收藏  举报