Loading

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 来完成日志系统的配置, 它会按照以下顺序进行配置:

  1. 加载 logback-test.xml、logback.xml 进行配置, 否则执行下一步
  2. 加载 logback-test-spring.xml、logback-spring.xml 进行配置, 否则执行下一步
  3. 进行编程式的默认配置

在 logback 的编程式默认配置是通过 org.springframework.boot.logging.logback.DefaultLogbackConfiguration#apply 来完成的, 通过代码可以看到系统中默认添加了一个向控制台输出的 consoleAppender, 并且会根据对配置文件中的 logging.file.namelogging.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>
posted @ 2023-07-14 14:48  xtyuns  阅读(48)  评论(0编辑  收藏  举报