网络编程
位置:首页>> 网络编程>> 数据库>> SpringBoot Logback日志记录到数据库的实现方法

SpringBoot Logback日志记录到数据库的实现方法

作者:拉提娜的爸爸  发布时间:2024-01-16 11:58:11 

标签:SpringBoot,Logback,日志

对于日志的处理,有时候需要把符合条件的日志计入数据库中

一、添加pom依赖


   <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-web</artifactId>
   </dependency>
   <!-- 这个依赖必须存在,否则会报java.lang.ClassNotFoundException: org.apache.commons.dbcp.BasicDataSource-->
   <dependency>
     <groupId>commons-dbcp</groupId>
     <artifactId>commons-dbcp</artifactId>
     <version>1.4</version>
   </dependency>
   <dependency>
     <groupId>mysql</groupId>
     <artifactId>mysql-connector-java</artifactId>
     <scope>runtime</scope>
   </dependency>

二、创建logback配置文件


<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">
 <!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->
 <property name="LOG_HOME" value="/home/admin" />

<!-- 控制台输出 -->
 <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="application_file" class="ch.qos.logback.core.rolling.RollingFileAppender">
   <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
     <!--日志文件输出的文件名-->
     <FileNamePattern>${LOG_HOME}/info/info.log.%d{yyyy-MM-dd}.log</FileNamePattern>
     <!--日志文件保留天数-->
     <MaxHistory>30</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>
   <!--日志文件最大的大小-->
   <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
     <MaxFileSize>500MB</MaxFileSize>
   </triggeringPolicy>
 </appender>

<!-- 异常日志文件 -->
 <appender name="error_file" class="ch.qos.logback.core.rolling.RollingFileAppender">
   <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
     <!--日志文件输出的文件名-->
     <FileNamePattern>${LOG_HOME}/error/error.log.%d{yyyy-MM-dd}.log</FileNamePattern>
     <!--日志文件保留天数-->
     <MaxHistory>30</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>
   <!--日志文件最大的大小-->
   <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
     <MaxFileSize>500MB</MaxFileSize>
   </triggeringPolicy>
   <!-- 只打印错误日志 -->
   <filter class="ch.qos.logback.classic.filter.LevelFilter">
     <level>error</level>
     <onMatch>ACCEPT</onMatch>
     <onMismatch>DENY</onMismatch>
   </filter>
 </appender>

<!--连接数据库配置-->
 <appender name="db_classic_mysql_pool" class="ch.qos.logback.classic.db.DBAppender">
   <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://127.0.0.1:3306/logdb?serverTimezone=Asia/Shanghai</url>
       <username>root</username>
       <password>123456</password>
     </dataSource>
   </connectionSource>
 </appender>

<!--myibatis log configure-->
 <logger name="com.apache.ibatis" level="TRACE"/>
 <logger name="java.sql.Connection" level="DEBUG" />
 <logger name="java.sql.Statement" level="DEBUG"/>
 <logger name="java.sql.PreparedStatement" level="DEBUG"/>

<!-- 日志输出级别 -->
 <root level="INFO">
   <appender-ref ref="stdout" />
   <appender-ref ref="application_file" />
   <appender-ref ref="error_file"/>
   <appender-ref ref="db_classic_mysql_pool" />
 </root>

</configuration>

三、创建数据库表

在ch.qos.logback.classic.db包下可以找到对应数据库的表创建语句

SpringBoot Logback日志记录到数据库的实现方法

我用的mysql数据库,前提是要首先自己创建库

mysql的数据库sql语句:


BEGIN;
DROP TABLE IF EXISTS logging_event_property;
DROP TABLE IF EXISTS logging_event_exception;
DROP TABLE IF EXISTS logging_event;
COMMIT;

BEGIN;
CREATE TABLE logging_event
(
 timestmp     BIGINT NOT NULL,
 formatted_message TEXT NOT NULL,
 logger_name    VARCHAR(254) NOT NULL,
 level_string   VARCHAR(254) NOT NULL,
 thread_name    VARCHAR(254),
 reference_flag  SMALLINT,
 arg0       VARCHAR(254),
 arg1       VARCHAR(254),
 arg2       VARCHAR(254),
 arg3       VARCHAR(254),
 caller_filename  VARCHAR(254) NOT NULL,
 caller_class   VARCHAR(254) NOT NULL,
 caller_method   VARCHAR(254) NOT NULL,
 caller_line    CHAR(4) NOT NULL,
 event_id     BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY
);
COMMIT;

BEGIN;
CREATE TABLE logging_event_property
(
 event_id     BIGINT NOT NULL,
 mapped_key    VARCHAR(254) NOT NULL,
 mapped_value   TEXT,
 PRIMARY KEY(event_id, mapped_key),
 FOREIGN KEY (event_id) REFERENCES logging_event(event_id)
);
COMMIT;

BEGIN;
CREATE TABLE logging_event_exception
(
 event_id     BIGINT NOT NULL,
 i        SMALLINT NOT NULL,
 trace_line    VARCHAR(254) NOT NULL,
 PRIMARY KEY(event_id, i),
 FOREIGN KEY (event_id) REFERENCES logging_event(event_id)
);
COMMIT;

SpringBoot Logback日志记录到数据库的实现方法

创建好的表

四、测试

1、编写测试代码


@RunWith(SpringRunner.class)
@SpringBootTest
public class Springboot02MybatisApplicationTests {

private final Logger logger = LoggerFactory.getLogger(Springboot02MybatisApplicationTests.class);
 @Test
 public void contextLoads() {
   logger.info("数据库日志info");
   logger.error("数据库日志error");
 }
}

2、运行结果

SpringBoot Logback日志记录到数据库的实现方法

默认存储所有符合当前级别的日志记录

五、自定义数据库表字段和存储内容

当然,默认的表字段那么多,存储了很多内容,但是我们很多时候只是自己打印的日志内容,为了节省磁盘空间,这个时候可以自定义存储字段和存储内容

步骤:

1、创建数据库表


DROP TABLE IF EXISTS `logging`;
CREATE TABLE `logging` (
`id` BIGINT(20) NOT NULL AUTO_INCREMENT,
`message` VARCHAR(300) NOT NULL COMMENT '内容',
`level_string` VARCHAR(254) NOT NULL COMMENT '级别',
`created_time` DATETIME NOT NULL COMMENT '时间',
`logger_name` VARCHAR(300) NOT NULL COMMENT '全类名',
PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8 COMMENT='自定义日志记录表'

2、重写DBAppender类为LogDBAppender类


package com.me.study.springboot02mybatis.config;

import ch.qos.logback.classic.spi.CallerData;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.db.DBAppenderBase;
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;

@Configuration
public class LogDBAppender extends DBAppenderBase<ILoggingEvent> {

protected static final Method GET_GENERATED_KEYS_METHOD;
 //插入sql
 protected String insertSQL;
 // message 日志内容
 static final int MESSAGE = 1;
 // level_string
 static final int LEVEL_STRING = 2;
 // created_time 时间
 static final int CREATE_TIME = 3;
 // logger_name 全类名
 static final int LOGGER_NAME = 4;

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语句
 private static String buildInsertSQL() {
   return "INSERT INTO `logging`(`message`,`level_string`,`created_time`,`logger_name`)" +
       "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("- XXXX")
   if(message.startsWith("-")){ // 判断日志消息首字母为 - 的日志,记录到数据库表
     stmt.setString(MESSAGE, message);
     // event.getLevel().toString() 日志级别
     stmt.setString(LEVEL_STRING, event.getLevel().toString());
     // new Timestamp(event.getTimeStamp()) 时间
     stmt.setTimestamp(CREATE_TIME, new Timestamp(event.getTimeStamp()));
     // event.getLoggerName() 全类名
     stmt.setString(LOGGER_NAME, event.getLoggerName());
   }

}

@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 {
 }
}

3、修改logback日志文件,引用自定义的LogDBAppender类


 <!--连接数据库配置-->
 <appender name="db_classic_mysql_pool" class="com.me.study.springboot02mybatis.config.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://127.0.0.1:3306/logdb?serverTimezone=Asia/Shanghai</url>
       <username>root</username>
       <password>admin</password>
     </dataSource>
   </connectionSource>
 </appender>

4、测试运行

1)编写测试代码


 @Test
 public void contextLoads() {
   logger.info("- 数据库日志info");
   logger.error("- 数据库日志error");
   logger.info("一条不带‘-'的日志,看会不会记录如数据库");
 }

2)运行结果

SpringBoot Logback日志记录到数据库的实现方法

数据库存储结果只存储了自定义的日志记录

来源:https://www.jianshu.com/p/d8eea65626fc

0
投稿

猜你喜欢

手机版 网络编程 asp之家 www.aspxhome.com