SLF4J 日志框架
SLF4J 是一个相对成熟的日志框架, 它基于外观模式(门面模式)实现了插拔式的日志实现替换功能, 而且还提供了其他日志框架的桥接方案。
本文中提到的日志框架指的是日志门面,而日志实现是日志框架下面真正完成日志打印功能的依赖包。
桥接方案
目的 | 依赖库 | 备注 |
---|---|---|
将 Apache Commons Logging(jcl) 框架打印的日志桥接至 SLF4J 框架 | jcl-over-slf4j | 需要在构建工具中排除 jcl 的依赖 |
将 java.util.logging(jul) 的日志派发至 SLF4J 框架 | jul-to-slf4j | 需要调用 SLF4JBridgeHandler.removeHandlersForRootLogger(); 卸载 jul 中默认的 ConsoleHandler , 并且调用 SLF4JBridgeHandler.install(); 来注册 SLF4JBridgeHandler |
将 log4j2 日志实现打印的日志派发至 SLF4J 框架 | log4j-over-slf4j | 需要在构建工具中排除 log4j2 的依赖 |
将 Java Platform Logging 框架打印的日志桥接至 SLF4J 框架 | slf4j-jdk-platform-logging | Java Platform Logging 是在 JEP 264 中为 Java9 引入的日志框架 |
基于 OSGI 的 SLF4J | osgi-over-slf4j | (没有遇到过 OSGI 的使用场景, 这个了解的不多) |
日志实现
日志实现 | 依赖库 | 备注 |
---|---|---|
logback | logback-classic | |
log4j2 | log4j-slf4j2-impl | 由 Apache Log4j2 项目提供 |
log4j1 | / | 已弃用, 由于 log4j1 仍然存在一些安全漏洞, 因此推荐使用 reload4j 来代替 log4j1 |
reload4j | slf4j-reload4j | reload4j 是一个基于 log4j1 的分支实现, 它修复了 log4j1 中存在的已知安全漏洞 |
jul | slf4j-jdk14 | 不要和 jul-to-slf4j 同时使用, 否则会陷入鸡生蛋、蛋生鸡的问题 |
slf4j-simple | slf4j-simple | 向标准输出流或文件进行输出的简单日志功能实现 |
slf4j-nop | slf4j-nop | 直接丢弃日志, 不进行任何记录操作 |
实现原理
slf4j-api 2.0 之前是通过反射获取固定的 Class 来实现与日志实现库绑定的,在 2.0 中 SLF4J 的这个机制替换为了 SPI,因此在 2.0 之前日志实现库被称作 binding 而在 2.0 及以后日志实现库被称作 provider。
与 Spring 的集成
SpirngFramework 中主要使用的是一个基于 jcl 简化的日志框架: spring-jcl, 它通过检查 classpath 下的相关 Class 来实现与 SLF4J、log4j2 或 JUL 的绑定,在 SpringBoot 中也提供了使用 logback(slf4j-api) 来作为日志实现的 spring-boot-starter-logging。
配置
SpringBoot 中通过 org.springframework.boot.context.logging.LoggingApplicationListener#initializeSystem
来委派给对应的日志系统来完成配置,如 logback 通过 org.springframework.boot.logging.logback.LogbackLoggingSystem#initialize
-> org.springframework.boot.logging.AbstractLoggingSystem#initializeWithConventions
来完成日志系统的配置, 它会按照以下顺序进行配置:
- 加载 logback-test.xml、logback.xml 进行配置, 否则执行下一步
- 加载 logback-test-spring.xml、logback-spring.xml 进行配置, 否则执行下一步
- 进行编程式的默认配置
在 logback 的编程式默认配置是通过 org.springframework.boot.logging.logback.DefaultLogbackConfiguration#apply
来完成的, 通过代码可以看到系统中默认添加了一个向控制台输出的 consoleAppender, 并且会根据对配置文件中的 logging.file.name
或 logging.file.path
属性的判断添加一个使用 SizeAndTimeBasedRollingPolicy 的 fileAppender。
SpringBoot 中 root logger 的默认打印级别是 info, 可以在配置文件中通过 logging.level.root 属性修改其日志级别。SpringBoot 中还提供了 logger 分组功能, 默认有 web, sql 两个分组, 因此也可以通过 logging.level.web 和 logging.level.sql 修改相关 logger 的日志级别。
SpringBoot 中默认配置的两个 appender 基本可以满足大多数的使用需求, 且在默认配置中也做了许多配置调整, 因此推荐使用 Spring 属性配置文件或者编程式微调相关属性而不是直接使用 logback.xml 覆盖默认配置。
附上一份简单通用的 logback.xml 配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false" scan="false" scanPeriod="1 minute" packagingData="false">
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>TRACE</level>
</filter>
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
<file>app.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>app.log.%d{yyyy-MM-dd}.%i.gz</fileNamePattern>
<maxFileSize>10MB</maxFileSize>
<totalSizeCap>0</totalSizeCap>
<maxHistory>7</maxHistory>
</rollingPolicy>
</appender>
<root level="INFO">
<appender-ref ref="CONSOLE" />
<appender-ref ref="FILE" />
</root>
</configuration>