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

网友投稿 1217 2022-12-22


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

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

一、添加pom依赖

org.springframework.boot

spring-boot-starter-web

commons-dbcp

commons-dbcp

1.4

mysql

mysql-connector-java

runtime

二、创建logback配置文件

%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n

${LOG_HOME}/info/info.log.%d{yyyy-MM-dd}.log

30

%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n

500MB

${LOG_HOME}/error/error.log.%d{yyyy-MM-dd}.log

30

%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n

500MB

error

ACCEPT

DENY

com.mysql.cj.jdbc.Driver

jdbc:mysql://127.0.0.1:3306/logdb?serverTimezone=Asia/Shanghai

root

123456

三、创建数据库表

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

我用的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_namehttp:// 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;

创建好的表

四、测试

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、运行结果

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

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

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

步骤:

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 {

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类

com.mysql.cj.jdbc.Driver

jdbc:mysql://127.0.0.1:3306/logdb?serverTimezone=Asia/Shanghai

root

admin

4、测试运行

1)编写测试代码

@Test

public void contextLoads() {

logger.info("- 数据库日志info")http://;

logger.error("- 数据库日志error");

logger.info("一条不带‘-'的日志,看会不会记录如数据库");

}

2)运行结果

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


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Java Junit单元测试实例详解
下一篇:如何使用HttpClient发送java对象到服务器
相关文章

 发表评论

暂时没有评论,来抢沙发吧~