如何通过SpringBoot的 Logback自定义日志输出,然后记录到数据库,解决方法如下

步骤一:添加pom依赖

<!-- 自定义日志
这个依赖必须存在,否则会报java.lang.ClassNotFoundException: org.apache.commons.dbcp.BasicDataSource-->
<dependency>
    <groupId>commons-dbcp</groupId>
    <artifactId>commons-dbcp</artifactId>
    <version>1.4</version>
</dependency>
<dependency>
    <groupId>org.freemarker</groupId>
    <artifactId>freemarker</artifactId>
    <version>2.3.23</version>
</dependency>


步骤二:配置logback.xml
注意:里面标签配置顺序别弄错了

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
   <!--log存放路径-->
   <property name="LOG_HOME" value="/my-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} %X{address} %-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.TimeBasedRollingPolicy">
         <!--日志文件输出的文件名 -->
         <FileNamePattern>${LOG_HOME}/${APP_NAME}.log.%d{yyyy-MM-dd}.log</FileNamePattern>
         <!--日志文件保留天数 -->
         <MaxHistory>10</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} %X{address} %-5level %logger{50} - %msg%n</pattern>
         <!--<pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern> -->
      </encoder>
   </appender>
   <!--自定义日志记录输出需添加数据库配置
        class:LogDBAppender日志保存操作类(自定义)
        -->
   <appender name="db_classic_mysql_pool" class="com.*.config.LogDBAppender">
      <connectionSource class="ch.qos.logback.core.db.DataSourceConnectionSource">
         <dataSource class="org.apache.commons.dbcp.BasicDataSource">
            <driverClassName>com.mysql.jdbc.Driver</driverClassName>
            <url>jdbc:mysql://*.*.*.*:3306/mydb?serverTimezone=GMT%2B8&amp;characterEncoding=utf8</url>
            <username>*</username>
            <password>*</password>
         </dataSource>
      </connectionSource>
   </appender>

   <!-- 日志输出级别 -->
   <root level="info">
      <appender-ref ref="STDOUT" />
      <appender-ref ref="FILE" />
      <!--引入上面数据库配置-->
      <appender-ref ref="db_classic_mysql_pool" />
   </root>
</configuration>

步骤三: 配置自定义日志类
 

import ch.qos.logback.classic.spi.CallerData;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.db.DBAppenderBase;
import com.alibaba.fastjson.JSONObject;
import org.springframework.context.annotation.Configuration;

import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Timestamp;
/**
 * @ClassName LogDBAppender
 * @Description: 自定义日志保存至数据库
 * @Author LRH
 * @Date 2020/6/15
 * @Version V1.0
 **/
@Configuration
public class LogDBAppender extends DBAppenderBase<ILoggingEvent> {
    protected static final Method GET_GENERATED_KEYS_METHOD;
    //插入sql
    protected String insertSQL;

    //自定义存储字段
    /**
     * menu_type:操作类型,指的是菜单ID
     * record_id:记录ID
     * operation_content:操作内容,自定义编辑
     * */
    static final int MENU_TYPE = 1;
    static final int RECORD_ID = 2;
    static final int OPERATION_CONTENT = 3;

    static final StackTraceElement EMPTY_CALLER_DATA = CallerData.naInstance();

    static {
        // PreparedStatement.getGeneratedKeys() method was added in JDK 1.4
        Method getGeneratedKeysMethod;
        try {
            // the
            getGeneratedKeysMethod = PreparedStatement.class.getMethod("getGeneratedKeys", (Class[]) null);
        } catch (Exception ex) {
            getGeneratedKeysMethod = null;
        }
        GET_GENERATED_KEYS_METHOD = getGeneratedKeysMethod;
    }

    @Override
    public void start() {
        // 将写好的sql语句赋值给insertSQL
        insertSQL = buildInsertSQL();
        super.start();
    }

    // 自己写新增sql语句
    //在数据库中创建一个log表,专门存日志数据
    private static String buildInsertSQL() {
        return "INSERT INTO `log`" +
                "(" +
                "`menu_type`,`record_id`,`operation_content`"+
                ")" +
                "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 {
        // event.getFormattedMessage() 日志打印内容
        String message = event.getFormattedMessage();
        // logger.info("'MENU_TYPE': '{}','RECORD_ID': '{}','OPERATION_CONTENT': '{}'",XXX,XXX,XXX)
        // 如果只想存储上面格式的日志,则可以判断打印数据是否符合要求
        //判断当前日志信息是否属于自定义类型
        int MENU_TYPE_FLAG=message.indexOf("MENU_TYPE");
        int RECORD_ID_FLAG=message.indexOf("RECORD_ID");
        int OPERATION_CONTENT_FLAG=message.indexOf("OPERATION_CONTENT");
        if(MENU_TYPE_FLAG>0&&RECORD_ID_FLAG>0&&OPERATION_CONTENT_FLAG>0){
            //截取用户自定义的日志信息
            JSONObject jsonObject =JSONObject.parseObject(message);
            String menuType=jsonObject.get("MENU_TYPE").toString();
            String recordId=jsonObject.get("RECORD_ID").toString();
            String operationContent=jsonObject.get("OPERATION_CONTENT").toString();

            stmt.setString(MENU_TYPE, menuType);
            stmt.setString(RECORD_ID, recordId);
            stmt.setString(OPERATION_CONTENT, operationContent);
        }
    }

    @Override
    protected void subAppend(ILoggingEvent eventObject, Connection connection, PreparedStatement statement) throws Throwable {
        bindLoggingEventWithInsertStatement(statement, eventObject);
        // This is expensive... should we do it every time?
        int updateCount = statement.executeUpdate();
        if (updateCount != 1) {
            addWarn("Failed to insert loggingEvent");
        }
    }

    @Override
    protected void secondarySubAppend(ILoggingEvent eventObject, Connection connection, long eventId) throws Throwable {
    }
}

步骤四:如何调用执行自定义日志

private static Logger logger = LoggerFactory.getLogger(WxAuthController.class);
//日志消息模板(属性自定义)
public final static String INFO="{\"MENU_TYPE\":\"{}\",\"RECORD_ID\":\"{}\",\"OPERATION_CONTENT\":\"{}\"}";
//调用方式如下(当前配置的日志级别是info)
logger.info(INFO,参数1,参数2,参数3)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值