当前位置: 首页 > news >正文

Logback自定义DBAppender保存系统日志到数据库

在系统中采用了spring boot + logback+slf4j的日志框架,将系统日志记录到数据库。
在这里插入图片描述

相关参考来源:

官方文档-DBAppender
Logback输出日志到自定义MySQL数据库(重写DBAppender)
logback日志框架中filter的使用

1. 添加依赖:

从 logback 版本 1.2.8 开始,DBAppender 不再随 logback-classic 一起提供,所以需要单独引入

<dependency><groupId>ch.qos.logback.db</groupId><artifactId>logback-classic-db</artifactId><version>1.2.11.1</version>
</dependency>

2. 自定义表结构:

可以根据实际情况增加或减少和修改字段

CREATE TABLE t_log_logback (`id` VARCHAR ( 64 ) NOT NULL COMMENT '主键',`create_time` VARCHAR ( 32 ) NOT NULL COMMENT '创建时间',`message` TEXT NOT NULL COMMENT '内容',`level_string` VARCHAR ( 254 ) NOT NULL COMMENT '日志等级:TRACE,DEBUG,INFO,WARNING,ERROR,FATAL',`logger_name` VARCHAR ( 254 ) NOT NULL COMMENT '发出日志记录请求的记录器的名称',`thread_name` VARCHAR ( 254 ) COMMENT '线程名称',`reference_flag` INT ( 11 ) COMMENT 'MDC属性',`caller_filename` VARCHAR ( 254 ) NOT NULL COMMENT '发出日志记录请求的文件名',`caller_class` VARCHAR ( 254 ) NOT NULL COMMENT '发出日志记录请求的类',`caller_method` VARCHAR ( 254 ) NOT NULL COMMENT '发出日志记录请求的方法的名称',`caller_line` VARCHAR ( 4 ) NOT NULL COMMENT '发出日志记录请求的行号',
PRIMARY KEY ( `id` ) USING BTREE 
) ENGINE = INNODB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_bin ROW_FORMAT = DYNAMIC COMMENT = 'logback系统日志记录表';

3. 自定义追加器DbLogbackAppender

import ch.qos.logback.classic.spi.CallerData;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.db.DBAppenderBase;import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;/*** <p>* 	自定义DB日志追加器,参考实现类 {@link ch.qos.logback.classic.db.DBAppender}*  参考来源:https://blog.csdn.net/qq_20914913/article/details/92830914* </p>*/
public class DbLogbackAppender extends DBAppenderBase<ILoggingEvent> {private String insertSQL;private static final Method GET_GENERATED_KEYS_METHOD;// 对应于数据库字段的插入数据序号private static final int ID_INDEX = 1;private static final int CREATE_TIME_INDEX = 2;private static final int MESSAGE_INDEX = 3;private static final int LEVEL_STRING_INDEX = 4;private static final int LOGGER_NAME_INDEX = 5;private static final int THREAD_NAME_INDEX = 6;private static final int REFERENCE_FLAG_INDEX = 7;private static final int CALLER_FILENAME_INDEX = 8;private static final int CALLER_CLASS_INDEX = 9;private static final int CALLER_METHOD_INDEX = 10;private static final int CALLER_LINE_INDEX = 11;private static final StackTraceElement EMPTY_CALLER_DATA = CallerData.naInstance();// 处理主键的自动生成,这里我们使用手工生成,因此下面代码可忽略static {// PreparedStatement.getGeneratedKeys() method was added in JDK 1.4Method getGeneratedKeysMethod;try {// thegetGeneratedKeysMethod = PreparedStatement.class.getMethod("getGeneratedKeys", (Class[]) null);} catch (Exception ex) {getGeneratedKeysMethod = null;}GET_GENERATED_KEYS_METHOD = getGeneratedKeysMethod;}@Overridepublic void start() {insertSQL = buildInsertSQL();cnxSupportsBatchUpdates = connectionSource.supportsBatchUpdates();// super.start();super.started = true;}// 核心代码,构建插入语句,并对应数据库字段private static String buildInsertSQL() {return "INSERT INTO t_log_logback " +"(id, create_time, message, level_string, logger_name, thread_name, " +"reference_flag, caller_filename, caller_class, caller_method, caller_line) "+"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";}// 管理每个字段插入的数据private void bindLoggingEventWithInsertStatement(PreparedStatement stmt, ILoggingEvent event) throws SQLException {// TODO 手工处理ID的生成stmt.setString(ID_INDEX, IdUtils.simpleUUID());stmt.setString(CREATE_TIME_INDEX, LocalDateTime.ofInstant(Instant.ofEpochMilli(event.getTimeStamp()),ZoneId.systemDefault()).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));stmt.setString(MESSAGE_INDEX, event.getFormattedMessage());stmt.setString(LEVEL_STRING_INDEX, event.getLevel().toString());stmt.setString(LOGGER_NAME_INDEX, event.getLoggerName());stmt.setString(THREAD_NAME_INDEX, event.getThreadName());}// 管理每个字段插入的数据private void bindCallerDataWithPreparedStatement(PreparedStatement stmt, StackTraceElement[] callerDataArray) throws SQLException {StackTraceElement caller = extractFirstCaller(callerDataArray);stmt.setInt(REFERENCE_FLAG_INDEX, 0);stmt.setString(CALLER_FILENAME_INDEX, caller.getFileName());stmt.setString(CALLER_CLASS_INDEX, caller.getClassName());stmt.setString(CALLER_METHOD_INDEX, caller.getMethodName());stmt.setString(CALLER_LINE_INDEX, Integer.toString(caller.getLineNumber()));}// 核心方法,插入具体日志数据@Overrideprotected void subAppend(ILoggingEvent event, Connection connection, PreparedStatement insertStatement) throws Throwable {bindLoggingEventWithInsertStatement(insertStatement, event);// This is expensive... should we do it every time?bindCallerDataWithPreparedStatement(insertStatement, event.getCallerData());int updateCount = insertStatement.executeUpdate();if (updateCount != 1) {addWarn("Failed to insert loggingEvent");}}private StackTraceElement extractFirstCaller(StackTraceElement[] callerDataArray) {StackTraceElement caller = EMPTY_CALLER_DATA;if (hasAtLeastOneNonNullElement(callerDataArray))caller = callerDataArray[0];return caller;}private boolean hasAtLeastOneNonNullElement(StackTraceElement[] callerDataArray) {return callerDataArray != null && callerDataArray.length > 0 && callerDataArray[0] != null;}@Overrideprotected Method getGeneratedKeysMethod() {return GET_GENERATED_KEYS_METHOD;}@Overrideprotected String getInsertSQL() {return insertSQL;}protected void secondarySubAppend(ILoggingEvent event, Connection connection, long eventId) throws Throwable {}@Overrideprotected long selectEventId(PreparedStatement insertStatement, Connection connection) throws SQLException, InvocationTargetException {return 0;}
}

4. logback-spring.xml配置关联

添加自定义的追加器DbLogbackAppender

<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false"><!-- 获取springboot中的数据库配置 --><springProperty scope="context" name="driverClassName" source="spring.datasource.master.driverClassName" defaultValue="driverClassName"/><springProperty scope="context" name="url" source="spring.datasource.master.url" defaultValue="url"/><springProperty scope="context" name="username" source="spring.datasource.master.username" defaultValue="username"/><springProperty scope="context" name="encryptPassword" source="spring.datasource.master.encryptPassword" defaultValue="encryptPassword"/><!-- 添加自定义DbLogbackAppender --><appender name="DB" class="com.xxx.DbLogbackAppender"><connectionSource class="ch.qos.logback.core.db.DriverManagerConnectionSource"><driverClass>${driverClassName}</driverClass><url>${url}</url><user>${username}</user><password>${password}</password></connectionSource><!--临界值过滤。只记录指定级别以及高于该级别的日志--><filter class="ch.qos.logback.classic.filter.ThresholdFilter"><level>WARN</level></filter></appender><root level="DEBUGE"><appender-ref ref="DB" /></root>
</configuration>

到这里,就配置完成了,重启系统,访问日志,会将warn级别以上的日志记录到数据库表。

由于数据源是使用logback的LogbackConnectionSource,如果要自定义数据源,请往下看

5.自定义数据源

创建类LogbackConnectionSource.java,继承ConnectionSourceBase


import ch.qos.logback.core.db.ConnectionSourceBase;import java.sql.Connection;
import java.sql.SQLException;/*** <p>*  获取数据库连接用于logback,并提供DbLogbackAppender使用*  参考类:ch.qos.logback.core.db.DriverManagerConnectionSource* </p>*/
public class LogbackConnectionSource extends ConnectionSourceBase {public Connection getConnection() {获取数据库连接Connection connection = null;// 自行构建连接// ...return connection;}
}

修改logback-spring.xml配置为如下

	<!-- 添加自定义DbLogbackAppender --><appender name="DB" class="com.xxx.DbLogbackAppender"><!-- 添加自定义的数据源 --><connectionSource class="com.xxx.LogbackConnectionSource"><!-- <driverClass>${driverClassName}</driverClass><url>${url}</url><user>${username}</user><password>${password}</password>--></connectionSource><!--临界值过滤。只记录指定级别以及高于该级别的日志--><filter class="ch.qos.logback.classic.filter.ThresholdFilter"><level>WARN</level></filter></appender>

相关文章:

Logback自定义DBAppender保存系统日志到数据库

在系统中采用了spring boot logback&#xff0b;slf4j的日志框架&#xff0c;将系统日志记录到数据库。 相关参考来源&#xff1a; 官方文档-DBAppender Logback输出日志到自定义MySQL数据库&#xff08;重写DBAppender&#xff09; logback日志框架中filter的使用 1. 添加依…...

云原生之使用Docker部署LimeSurvey在线调查工具

云原生之使用Docker部署LimeSurvey在线调查工具 一、LimeSurvey介绍1.1 LimeSurvey简介1.2 LimeSurvey特点1.3 LimeSurvey使用场景1.4 LimeSurvey支持版本二、本地环境介绍2.1 本地环境规划2.2 本次实践介绍三、本地环境检查3.1 检查Docker服务状态3.2 检查Docker版本3.检查doc…...

sdbusplus:添加ObjectManager interface

ObjectManager接口可以一次性拿到对象及子对象的所有property,在交互中经常会用到。 sdbusplus提供了add_manager完成该接口的添加: //server_obj.cpp #include <sdbusplus/asio/connection.hpp> #include <sdbusplus/asio/object_server.hpp> #include <sd…...

“RAID0 vs RAID1 vs RAID5 vs RAID6 vs RAID10:哪种RAID级别最适合你的需求?“

概要&#xff1a; RAID&#xff08;Redundant Array of Independent Disks&#xff09;是一种数据存储技术&#xff0c;可以将多个硬盘组合起来以提高性能、可靠性和容错能力。下面是几种常见的RAID级别&#xff0c;以及它们的用途和特点。 目录 RAID 0RAID 1RAID 5RAID 6RAID…...

【MySQL】Mycat

文章目录 什么是Mycat为什么要用Mycatmycat能干什么各数据库中间件对比Mycat原理数据库中间件逻辑库逻辑表分片表分片规则全局表ER表非分片表分片节点节点主机mycat安装mycat核心配置schema.xmlserver.xmlrule.xml加密明文密码&#xff08;可选&#xff09; MyCat读写分离垂直拆…...

Netty中ServerBootstrap类介绍

一、Netty基本介绍 Netty是由JBOSS提供的一个java开源框架。Netty提供异步的、事件驱动的网络应用程序框架和工具&#xff0c;用以快速开发高性能、高可靠性的网络服务器和客户端程序。Netty 在保证易于开发的同时还保证了其应用的性能&#xff0c;稳定性和伸缩性。 Netty 是一…...

数字图像处理实验报告

目录 实验二、图像在空间域上的处理方法 实验三、图像在频率域上的处理方法 实验二、图像在空间域上的处理方法 一、实验目的 了解图像亮&#xff08;灰&#xff09;度变换与空间滤波的意义和手段&#xff1b;熟悉图像亮&#xff08;灰&#xff09;度变换与空间滤波的MATLA…...

【C51】10-基础51单片机的小车项目(51完结)

10.1小车的安装 10.2电机模块的开发&#xff08;L9110S&#xff09; 接通 VCC &#xff0c; GND 模块电源指示灯亮&#xff0c; 以下资料来源官方&#xff0c;但是不对&#xff0c;根据下节课实际调试 IA1 输入高电平&#xff0c; IA1 输入低电平&#xff0c;【 OA1 OB1 】电…...

进程、线程、锁阶段总结汇总

目录 进程 线程 锁 由于进程线程和锁的方面比较陌生&#xff0c;并且繁杂&#xff0c;所以简单总结一下学习到的函数API 进程 子进程创建 fork(); 进程结束 exit(); 进程回收 wait(); 进程回收 waitpad(); //函数可以指定进程组中的任意子进程&#xff0c;可以设置特殊…...

Filters.jar图片转素描

链接&#xff1a;https://pan.baidu.com/s/1ATlC2l1I83TPYFomHiWuFg?pwd2vm5 提取码&#xff1a;2vm5...

将MSYS2 MinGW集成到Windows终端

微软开发了一款Windows终端的开源软件&#xff0c;非常好用。安装后在Win7及以上系统会在右键菜单中添加一条“在终端中打开”的命令&#xff0c;非常方便。它默认配置了Windows命令行以及PowerShell&#xff0c;如果安装了Visual Studio 2022还会配置Visual Studio 2022的命令…...

SpringBoot项目使用slf4j的MDC日志打点功能

SpringBoot项目使用slf4j的MDC日志打点功能 物料准备&#xff1a; 1.自定义1个线程MDC打点工具类 2.配置logback打印MDC打点的traceId 3.配置webMVC使用MDC打点 4.配置ThreadPoolTaskExecutor使用MDC打点 5.配置HttpClient使用MDC打点 6.测试MDC日志打点效果 线程mdc打…...

宝塔修改默认端口后面板打不开

1、查看防火墙开启的端口&#xff0c;发现没有开启8888 [rootVM-12-12-centos ~]# firewall-cmd --list-ports 20/tcp 21/tcp 22/tcp 80/tcp 888/tcp 8081/tcp 39000-40000/tcp 8081/udp 2、防火墙开启8888端口 [rootVM-12-12-centos ~]# firewall-cmd --zonepublic --add-por…...

tinkerCAD案例:3.基本按钮

基本按钮 在本课中&#xff0c;您将学习制作具有圆柱形状的基本按钮。 说明 将圆柱体拖动到工作平面。 将其缩小到 2 毫米的高度。 提示&#xff1a; 您可以使用圆柱形状顶部的白点缩小圆柱体。 将其缩小到直径 16 毫米。 这将是按钮的主要形状。 现在我们可以创建允许将纽…...

客户线上反馈:从信息搜集到疑难 bug 排查全流程经验分享

写在前面&#xff1a;本文是我在前端团队的第三次分享&#xff0c;应该很少会有开发者写客户反馈处理流程以及 bug 排查的心得技巧&#xff0c;全文比较长&#xff0c;写了一个多星期大概1W多字&#xff08;也是我曾经2年工作的总结&#xff09;&#xff0c;如果你有耐心阅读&a…...

悲观锁、乐观锁、自旋锁

悲观锁、乐观锁、自旋锁 &#xff08;1&#xff09;乐观锁 乐观锁是一种乐观的思想&#xff0c;即认为读多写少&#xff0c;遇到并发的可能性低&#xff0c;每次拿数据时都认为别人不会修改&#xff0c;所以不会上锁&#xff0c;但是在更新的时候会判断一下在此期间别人有没有…...

七、进程地址空间

一、环境变量 &#xff08;一&#xff09;概念 环境变量(environment variables)&#xff1a;系统当中用做特殊用途的系统变量。 如&#xff1a;我们在编写C/C代码的时候&#xff0c;在链接的时候&#xff0c;从来不知道我们的所链接的动态静态库在哪里&#xff0c;但是照样可…...

浅谈智能微电网供电系统的谐波治理

摘要&#xff1a;智能微电网供电系统的特性容易引发谐波&#xff0c;而谐波导致电力损耗加大&#xff0c;降低供电质量。本文从谐波的产 生原因和危害做出详细阐述&#xff0c;并结合智能微电网提出了治 理谐波的方法和措施。 关键词&#xff1a;智能微电网&#xff1b;谐波危害…...

springboot项目的社区/博客系统

课前导读&#xff1a; 你学完一篇&#xff0c;你就多会一项技能&#xff0c;多多少少对你还是有点帮助的不是吗&#xff1f;~~~ 这是博主网页的url&#xff1a;优文共享社区 开发环境&#xff1a;JDK1.8&#xff0c;IDEA2021&#xff0c;MySQL5.7&#xff0c;Windows11 开发技术…...

go语言基础——函数、结构体、接口

由于go不是一门面向对象的语言&#xff0c;因此在有一些特性上和java是有一些区别的&#xff0c;比如go中就没有类这样的概念。下面来介绍一下go的一些特性。 结构体 结构体类似与java中的类&#xff0c;但又不完全一样。在类中&#xff0c;可以定义字段和方法&#xff0c;但…...

项目集管理—项目集治理

一、概述 项目集治理是实现和执行项目集决策&#xff0c;为支持项目集而制定实践&#xff0c;并维持项目集监督的绩效领域。 本章包括&#xff1a; 项目集治理实践项目集治理角色项目集治理设计与实施 项目集治理包括为了满足组织战略和运营目标的要求&#xff0c;对项目集实…...

MySQL了解之复制(一)

1.1、复制解决的问题 数据复制技术有以下一些特点&#xff1a; (1) 数据分布 (2) 负载平衡(load balancing) (3) 备份 (4) 高可用性(high availability)和容错 1.2、复制如何工作 从高层来看&#xff0c;复制分成三步&#xff1a; (1) master将改变记录到二进制…...

Halcon得出三角形内切圆

Halcon得出三角形内切圆 news2023/5/27 7:14: 目录 一、得出三角形的三个角点二、用类似尺规作图法得出三角形圆心 1、以三角形三角点画出圆形轮廓2、求出三角形轮廓与圆形轮廓之间的交点3、获得角平分线&#xff0c;三边角平分线交点为圆心三、求出圆心到边最短距离即半径 …...

2023年6月北京/广州/深圳CDGA/CDGP数据治理认证招生

DAMA认证为数据管理专业人士提供职业目标晋升规划&#xff0c;彰显了职业发展里程碑及发展阶梯定义&#xff0c;帮助数据管理从业人士获得企业数字化转型战略下的必备职业能力&#xff0c;促进开展工作实践应用及实际问题解决&#xff0c;形成企业所需的新数字经济下的核心职业…...

KMP 算法(Knuth-Morris-Pratt)

tip&#xff1a;作为程序员一定学习编程之道&#xff0c;一定要对代码的编写有追求&#xff0c;不能实现就完事了。我们应该让自己写的代码更加优雅&#xff0c;即使这会费时费力。 推荐&#xff1a;体系化学习Java&#xff08;Java面试专题&#xff09; 文章目录 一、什么是 …...

Java泛型详解

泛型的理解 泛型的概念 所谓泛型&#xff0c;就是允许在定义类、接口时通过一个标识表示类中某个属性的类型 或者是 某个方法的返回值类型及参数类型。这个类型参数将在使用时&#xff08;例如&#xff0c;继承或实现这个接口&#xff0c;用这个类型声明变量、创建对象时&#…...

2023上海国际嵌入式展 | 如何通过人工智能驱动的自动化测试工具提升嵌入式开发效率

2023年6月14日到16日&#xff0c;龙智将在2023上海国际嵌入式展&#xff08;embedded world China 2023&#xff09;A055展位亮相。同时&#xff0c;6月14日下午3:00-3:30&#xff0c;龙智资深DevSecOps顾问巫晓光将于创新技术及应用发展论坛第二论坛区&#xff08;A325展位&am…...

微信小程序个人心得

首先从官方文档给的框架说起,微信小程序官方文档给出了app.js, app.json, app.wxss. 先从这三个文件说起. 复制 app.js 这个文件是整个小程序的入口文件,开发者的逻辑代码在这里面实现,同时在这个文件夹里面可以定义全局变量.app.json 这个文件可以对小程序进行全局配置,决定…...

苹果MacOS系统傻瓜式本地部署AI绘画Stable Diffusion教程

Stable Diffusion的部署对小白来说非常麻烦&#xff0c;特别是又不懂技术的人。今天分享两个一键傻瓜式安装包&#xff0c;对小白来说非常有用。下面两个任选一个安装就可以。 一、DiffusionBee 简单介绍 DiffusionBee是基于stable diffusion的一个安装包&#xff0c;有图形…...

DBA之路-- 闪回恢复区FRA(Flash recovery area)与闪回特性(flashback)[待更新]

闪回恢复区FRA&#xff08;Flash recovery area&#xff09;与闪回特性&#xff08;flashback&#xff09; 1、闪回特性FB 用于快速简单恢复数据库中出现的认为误操作等逻辑错误 Flashback由undo表空间的撤销段内容为基础&#xff0c;受限于UNDO_RETENTON参数。要使用flashb…...

国外免费做网站软件/福州整站优化

1、安装git 参考&#xff1a;Git 详细安装教程&#xff08;详解 Git 安装过程的每一个步骤&#xff09;_mukes的博客-CSDN博客_git安装 2、下载并安装VS2019 点击官网链接下载community版本&#xff0c;在安装界面勾选C&#xff0c;默认安装路径是C盘&#xff0c;C盘空间不够…...

天津市网站建设/友情链接出售平台

在学习c/c过程中&#xff0c;指针是一个比较让人头痛的问题&#xff0c;稍微不注意将会是程序编译无法通过&#xff0c;甚至造成死机。在程序设计过程中&#xff0c;指针也往往是产生隐含bug的原因。下面就来谈谈指针的应用以及需要注意的一些问题&#xff0c;里面也许就有你平…...

网站建设与维护的软件/常德网站seo

原文链接: 1, http://blog.csdn.net/phoebin/article/details/3864590 2, http://blog.csdn.net/hancunai0017/article/details/7032383转载于:https://www.cnblogs.com/qingyuanjushi/p/5911431.html...

做彩票网站代理犯法吗6/aso排名优化知识

在以往的工作经历中&#xff0c;虽然也会出现公司的一些规章制度&#xff0c;但我鲜少与其打交道&#xff0c;也极少听说。但是来KB这里&#xff0c;突然发现公司居然并没有给我配备电脑&#xff01;&#xff01;原因是制度上并没有写IT人员入职需要配备电脑&#xff0c;尔后通…...

ssm框架做网站的优势/企业营销网站建设系统

本文实例为大家分享了Java实现寻找迷宫出路的具体代码&#xff0c;供大家参考&#xff0c;具体内容如下项目名称寻找迷宫出路项目描述给定一个自定义迷宫&#xff0c;0表示能通过&#xff0c;1表示不能通过。通过程序找出正确的迷宫出路&#xff0c;并将正确的路线改为2输出。代…...

郑州做网站公司 汉狮网络专业/uc浏览器网页版入口

var testString:String "wo shi string"var utf8String (testString as NSString).UTF8String 转载于:https://www.cnblogs.com/MartinLi841538513/p/3825574.html...