在搞清楚三者之间关系之前首先要理解一个设计模式--门面模式,便于理解slf4j
外观模式是一种结构型设计模式, 能为程序库、 框架或其他复杂类提供一个简单的接口。
外观模式定义了一个高层接口,这个接口使得子系统更加容易使用。该模式隐藏了系统的复杂性,对客户端来说,只需要知道门面接口即可,无需关心子系统内部的具体实现和细节。
为什么要使用外观模式?
假设你必须在代码中使用某个复杂的库或框架中的众多对象。 正常情况下, 你需要负责所有对象的初始化工作、 管理其依赖关系并按正确的顺序执行方法等。最终, 程序中类的业务逻辑将与第三方类的实现细节紧密耦合, 使得理解和维护代码的工作很难进行。
单日志门面(Simple Logging Facade For Java) SLF4J主要是为了给Java日志访问提供一套标准、规范 的API框架,其主要意义在于提供接口,具体的实现可以交由其他日志框架,例如log4j2和logback等。 当然slf4j自己也提供了功能较为简单的实现,但是一般很少用到。对于一般的Java项目而言,日志框架 会选择slf4j-api作为门面,配上具体的实现框架(log4j2、logback等),中间使用桥接器完成桥接。
拿slf4j和logback组合使用为例
<!--日志框架接口-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<!--日志框架接口实现-->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</dependency>
<!--日志框架核心组件-->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
</dependency>
在 logback.xml
中,我们可以定义日志输出的格式、路径、控制台输出格式、文件大小、保存时长等等。
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!--默认日志配置-->
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>
<!-- 控制台日志 -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder charset="UTF-8">
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
</encoder>
</appender>
<!-- Info日志 -->
<appender name="FILE-INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_PATH}/${LOG_FILE}-info.log</file>
<append>true</append>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>NEUTRAL</onMismatch>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_PATH}/${LOG_FILE}-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern> <!-- 日志文件的路径和名称 -->
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>200MB</maxFileSize> <!-- 单个日志文件的最大大小 -->
</timeBasedFileNamingAndTriggeringPolicy>
<maxHistory>15</maxHistory> <!-- 保留的历史日志文件数量 -->
<totalSizeCap>2GB</totalSizeCap> <!-- 所有日志文件的总大小上限 -->
<cleanHistoryOnStart>true</cleanHistoryOnStart> <!-- 在启动时清除历史日志文件 -->
</rollingPolicy>
<encoder charset="UTF-8">
<pattern>${FILE_LOG_PATTERN}</pattern>
</encoder>
</appender>
<!-- Warn日志 -->
<appender name="FILE-WARN" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_PATH}/${LOG_FILE}-warn.log</file>
<append>true</append>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>WARN</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_PATH}/${LOG_FILE}-warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern> <!-- 日志文件的路径和名称 -->
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>200MB</maxFileSize> <!-- 单个日志文件的最大大小 -->
</timeBasedFileNamingAndTriggeringPolicy>
<maxHistory>15</maxHistory> <!-- 保留的历史日志文件数量 -->
<totalSizeCap>2GB</totalSizeCap> <!-- 所有日志文件的总大小上限 -->
<cleanHistoryOnStart>true</cleanHistoryOnStart> <!-- 在启动时清除历史日志文件 -->
</rollingPolicy>
<encoder charset="UTF-8">
<pattern>${FILE_LOG_PATTERN}</pattern>
</encoder>
</appender>
<!-- Error日志 -->
<appender name="FILE-ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_PATH}/${LOG_FILE}-error.log</file>
<append>true</append>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_PATH}/${LOG_FILE}-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>200MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<maxHistory>15</maxHistory>
<totalSizeCap>2GB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder charset="UTF-8">
<pattern>${FILE_LOG_PATTERN}</pattern>
</encoder>
</appender>
<!-- 异步输出 -->
<appender name="info-asyn" class="ch.qos.logback.classic.AsyncAppender">
<appender-ref ref="FILE-INFO"/>
<queueSize>512</queueSize> <!-- 异步队列的大小 -->
</appender>
<appender name="warn-asyn" class="ch.qos.logback.classic.AsyncAppender">
<appender-ref ref="FILE-WARN"/>
<queueSize>512</queueSize> <!-- 异步队列的大小 -->
</appender>
<appender name="error-asyn" class="ch.qos.logback.classic.AsyncAppender">
<appender-ref ref="FILE-ERROR"/>
<queueSize>512</queueSize>
</appender>
<!-- 应用日志 -->
<logger name="com.improve.fuqige.bronze" additivity="false">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="FILE-INFO"/>
<appender-ref ref="FILE-WARN"/>
<appender-ref ref="FILE-ERROR"/>
</logger>
<!-- 总日志出口 -->
<root level="${logging.level.root}">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="info-asyn"/>
<appender-ref ref="warn-asyn"/>
<appender-ref ref="error-asyn"/>
</root>
</configuration>
Spring Boot 对 slf4j 支持的很好,内部已经集成了 slf4j,一般我们在使用的时候,会对slf4j 做一下配置。
logging.file=fuqige-bronze
logging.path=XXXXXX/Logs/XXXXXX
logging.level.root=info
logging.level.com.improve.fuqige.bronze=info
logging.pattern.console=%cyan(%d{yyyy-MM-dd HH:mm:ss.SSS}) %yellow([%thread]) %highlight(%-5level) %boldGreen(%logger{80}[LineNumber:%L]): %highlight(%msg%n)
logging.pattern.file=%d{yyyy-MM-dd HH:mm:ss.SSS} [%X{requestId}] %-5level --- [%thread] %logger{80}
@Slf4j
@RestController
@RequestMapping("/test")
public class TestController {
@GetMapping("/hello")
public String hello() {
log.info("进来了!");
log.warn("进来了!");
log.error("进来了!");
return "hello, world! requestId=" + MDC.get("requestId");
}
}
总的来说,本文对 slf4j ,log4j2和logback做了简单区分,并且对 Spring Boot 中如何使用 slf4j 输出日志做了详细的说明,分析了 logback.xml
文件中对日志相关信息的配置,。最后针对这些配置,在代码中使用 Logger 打印出一些进行测试。
因篇幅问题不能全部显示,请点此查看更多更全内容