logback日志打印原理

本文深入解析Java中Logger的初始化机制及其日志打印流程,包括类名解析、logger树构建和appender作用,以及如何通过设置additivity控制日志输出层级。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. logger初始化

logger初始化的时候会根据传入的名字去实例化。以下为实例化的例子

private static final Logger logger = LoggerFactory.getLogger(SClass.class);

启动的时候,LoggerFactory会接收到com.aaa.Sclass的完整的类名字,然后根据点去切分,依次创建对应的logger 并缓存起来,每个logger都是单例。最后的logger会是一棵以roor为核心的树,如下图所示。


2. logger打印过程

调用logger.info(msg)时,首先会定位到是树中哪个logger,由于有的logger是没有appender的(这是在logback.xml中配置),所以比如com.aaa.Class1调用时当前logger不会有输出 ,然后向上找到com.aaa,发现其对应有个appender1则会调用该appender输出日志内容。如果logger设置了additivity="false"则停止打印,否则继续向父节点调用继续输出日志。
<think>我们有一个使用commons-dbutils和logback的项目,需要配置日志输出执行的SQL语句。commons-dbutils本身不提供直接的SQL日志记录,但我们可以通过配置logback来记录SQL语句。通常,这需要数据库驱动或连接层支持日志记录,或者使用像p6spy这样的第三方工具来拦截和记录SQL。 然而,根据用户提供的引用,特别是引用[2]中提到了p6spy的配置,我们可以考虑使用p6spy来拦截SQL并输出日志。同时,用户项目已经使用了logback,所以我们可以将p6spy的日志输出到logback。 步骤: 1. 添加p6spy依赖 2. 配置p6spy(spy.properties) 3. 修改数据库连接配置,使用p6spy驱动 4. 配置logback来输出p6spy的日志 但是,用户特别提到了commons-dbutils,这是一个JDBC的轻量级封装工具。我们不需要修改commons-dbutils的代码,只需要修改数据源配置,将原来的数据库驱动替换为p6spy的驱动,然后p6spy会代理真实的数据库驱动,并拦截SQL语句进行日志输出。 具体步骤: 1. 添加p6spy依赖: 在Maven项目中,添加以下依赖(注意版本,这里使用较新的版本): ```xml <dependency> <groupId>p6spy</groupId> <artifactId>p6spy</artifactId> <version>3.9.1</version> <!-- 请检查最新版本 --> </dependency> ``` 2. 创建spy.properties配置文件(放在资源目录下,如src/main/resources/spy.properties): 内容参考用户引用[2]中的配置,但需要根据实际情况调整。例如: ```properties # 3.2.1以上使用 modulelist=com.p6spy.engine.logging.P6LogFactory,com.p6spy.engine.outage.P6OutageFactory # 自定义日志打印,这里使用用户引用[2]中提到的格式,但注意用户引用[2]中提到了MybatisPlusLogFactory,但我们不是MybatisPlus项目,所以使用默认的或者自定义的格式 # 使用logback,我们可以将appender设置为Slf4JLogger,这样日志会通过slf4j输出,然后由logback配置控制 appender=com.p6spy.engine.spy.appender.Slf4JLogger # 设置日志格式,可以使用自定义格式,但这里我们使用用户引用[2]中的格式,但注意那个格式是MybatisPlus的,我们可以使用默认的或者简单的 # 如果不想使用MybatisPlus的格式,可以去掉logMessageFormat配置,或者使用默认的 # logMessageFormat=com.p6spy.engine.spy.appender.MultiLineFormat # 或者使用自定义格式类(如果需要的话) # 但通常我们可以使用内置的格式,比如:com.p6spy.engine.spy.appender.SingleLineFormat # 使用以下配置来输出单行日志(可选) logMessageFormat=com.p6spy.engine.spy.appender.SingleLineFormat # 使用日志系统记录sql,上面已经配置了Slf4JLogger # 配置记录Log例外(排除一些类别,减少日志量) excludecategories=info,debug,result,commit,resultset,batch # 实际数据库驱动(根据你的数据库配置) driverlist=com.mysql.cj.jdbc.Driver # 这里以MySQL为例,请替换为你的数据库驱动 # 是否开启慢SQL记录 outagedetection=true outagedetectioninterval=2 # 慢SQL阈值(秒) ``` 3. 修改数据源配置:将原来的数据库驱动替换为`com.p6spy.engine.spy.P6SpyDriver`,并将原来的URL加上`jdbc:p6spy:`前缀。 例如,原来的URL可能是:`jdbc:mysql://localhost:3306/mydb` 修改后:`jdbc:p6spy:mysql://localhost:3306/mydb` 4. 配置logback.xml(或logback-spring.xml)来输出p6spy的日志: 在logback配置文件中,为p6spy设置一个logger,指定日志级别为DEBUG或INFO(根据需求)。 例如: ```xml <configuration> <!-- 其他配置 --> <logger name="com.p6spy" level="DEBUG" additivity="false"> <appender-ref ref="CONSOLE" /> <!-- 假设你有一个名为CONSOLE的控制台appender --> <!-- 如果需要同时输出到文件,可以添加文件appender --> </logger> <!-- 其他配置 --> </configuration> ``` 这样配置后,当commons-dbutils执行SQL时,p6spy会拦截SQL语句并通过slf4j记录日志,然后由logback输出。 注意:使用p6spy可能会对性能有一定影响,因为它会拦截并处理所有的数据库操作。在生产环境中,如果日志量很大,请谨慎开启。 另外,如果不想使用p6spy,也可以考虑使用数据库驱动自带的日志功能(如MySQL驱动有logger配置),但配置方式可能因驱动而异,且通常不如p6spy统一和灵活。 根据用户引用[3]中提到了使用Druid连接池,如果用户使用的是Druid连接池,那么Druid本身也提供了SQL日志记录功能(通过Filter)。但是用户问题中指定了commons-dbutils和logback,并且没有明确说使用Druid,所以这里我们采用通用的p6spy方案。 如果用户使用的是Druid,那么可以配置Druid的StatFilter并启用SQL日志记录,然后通过logback输出Druid的日志。但注意,Druid的日志记录的是执行统计信息,而不是每条SQL的完整语句(除非配置了logFilter)。不过,用户引用[3]中并没有详细说明如何配置Druid来记录SQL语句,所以我们不展开。 综上所述,使用p6spy是相对通用的方法。 相关问题: 1. 在使用p6spy时,如何排除某些特定的SQL语句不被记录? 2. p6spy对性能的影响有多大?如何优化? 3. 除了p6spy,还有哪些方法可以记录SQL日志? 4. 如何配置logback只输出SQL日志到单独的文件? 5. 在Spring项目中如何集成p6spy?</think>要配置commons-dbutils和logback输出执行的SQL语句,可通过以下步骤实现: ### 解决方案 #### 1. **添加P6Spy依赖(SQL拦截工具)** 在`pom.xml`中添加依赖(替代原生JDBC驱动): ```xml <dependency> <groupId>p6spy</groupId> <artifactId>p6spy</artifactId> <version>3.9.1</version> <!-- 使用最新版本 --> </dependency> ``` P6Spy会拦截真实数据库驱动,记录SQL并输出日志[^2]。 #### 2. **配置P6Spy代理** 创建`src/main/resources/spy.properties`: ```properties # 指定真实数据库驱动(如MySQL) driverlist=com.mysql.cj.jdbc.Driver # 使用SLF4J输出日志(与logback集成) appender=com.p6spy.engine.spy.appender.Slf4JLogger # 自定义日志格式(显示SQL和执行时间) logMessageFormat=com.p6spy.engine.spy.appender.CustomLineFormat customLogMessageFormat=%(executionTime)ms | %(category) | SQL: %(sqlSingleLine) # 启用慢查询检测(超过2秒报警) outagedetection=true outagedetectioninterval=2 ``` 此配置将SQL日志重定向到SLF4J,由logback处理[^2]。 #### 3. **修改数据库连接配置** 将原JDBC连接替换为P6Spy代理: ```diff - url: jdbc:mysql://localhost:3306/db + url: jdbc:p6spy:mysql://localhost:3306/db - driver: com.mysql.cj.jdbc.Driver + driver: com.p6spy.engine.spy.P6SpyDriver ``` P6Spy会拦截所有SQL操作并记录[^2][^3]。 #### 4. **配置logback输出SQL日志** 在`logback.xml`中增加: ```xml <!-- 单独记录SQL日志到文件 --> <appender name="SQL_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>logs/sql.log</file> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss} %msg%n</pattern> </encoder> <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> <fileNamePattern>logs/sql.%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern> <maxFileSize>50MB</maxFileSize> </rollingPolicy> </appender> <!-- 设置P6Spy日志级别 --> <logger name="com.p6spy" level="DEBUG" additivity="false"> <appender-ref ref="SQL_FILE"/> <!-- 输出到文件 --> <appender-ref ref="CONSOLE"/> <!-- 可选:同时输出到控制台 --> </logger> ``` 此时执行的SQL会以如下格式记录: ``` 2023-05-01 12:30:45 5ms | statement | SQL: SELECT * FROM users WHERE id=? ``` ### 关键点说明 1. **原理** P6Spy作为代理驱动,拦截所有JDBC操作,将SQL通过SLF4J传递给logback[^2]。 2. **事务安全** 日志记录不影响实际事务提交/回滚机制[^3][^4]。 3. **性能影响** 生产环境建议: - 关闭结果集日志:`excludecategories=resultset` - 仅记录慢查询:设置`outagedetectioninterval=500`(500ms) ### 相关问题 1. **如何排除特定SQL不记录?** 在`spy.properties`中使用`excludecategories`过滤`batch,info`等操作[^2]。 2. **P6Spy与Druid连接池如何共存?** 需将Druid的驱动改为P6Spy驱动,保持连接池配置不变[^3]。 3. **如何格式化输出的SQL语句?** 自定义`logMessageFormat`实现类,或使用内置的`MultiLineFormat`(需添加`%b`换行符)。 4. **日志中出现乱码如何解决?** 在logback的`<encoder>`中增加`<charset>UTF-8</charset>`声明编码。 5. **能否不引入P6Spy直接记录SQL?** Commons-DButils无内置日志能力,需依赖第三方工具(如P6Spy)或扩展`QueryRunner`类重写方法。 [^1]: 日志整合是开发和运维的关键环节。 [^2]: P6Spy通过代理驱动实现SQL拦截和日志输出。 [^3]: JDBC连接配置的变更是实现代理的核心步骤。 [^4]: 日志工具不应影响实际事务执行逻辑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值