日志框架简介-Slf4j+Logback入门实践 | 京东云技术团队
前言
随着互联网和大数据的迅猛发展,分布式日志系统和日志分析系统已广泛应用,几乎所有应用程序都使用各种日志框架记录程序运行信息。因此,作为工程师,了解主流的日志记录框架非常重要。虽然应用程序的运行结果不受日志的有无影响,但没有日志的应用程序是不完整的,甚至可以说是有缺陷的。优秀的日志系统可以记录操作轨迹、监控系统运行状态和解决系统故障。
Java 日志框架进化史
早期 Java 日志框架没有制定统一的标准,使得很多应用程序会同时使用多种日志框架。Java 日志框架的发展历程大致可分为以下几个阶段:

日志框架介绍
在上文中已经提及,目前常用的日志框架有 Log4j,Log4j 2,Commons Logging,Slf4j,Logback,JUL。这些日志框架可以分为两种类型:门面日志和日志系统。
日志门面
日志门面(Logging Facade)是一种设计模式,用于在应用程序中实现日志记录的抽象层。它提供了一组统一的接口和方法,即相应的 API,而不提供具体的接口实现。日志门面在使用时,可以动态或者静态地指定具体的日志框架实现,解除了接口和实现的耦合,使用户可以灵活地选择日志的具体实现框架。
日志系统
日志系统(Logging System)是指用于记录和管理应用程序运行时产生的日志信息的软件工具或框架。与日志门面相对,它提供了具体的日志接口实现,应用程序通过它执行日志打印的功能,如日志级别管理、日志格式化、日志输出目标设置等。常见的日志系统包括Log4j、Logback、Java Util Logging等。

通过使用日志门面,我们可以在应用程序中使用统一的API进行日志记录,而具体的日志实现可以根据需要选择和配置。这样,我们可以根据项目需求和团队喜好来灵活选择、切换和配置日志系统,而不会对应用程序代码造成太大影响。
避免环形依赖
Slf4j 的作者 Ceki Gülcü 当年因为觉得 Commons-Logging 的 API 设计的不好,性能也不够高,因而设计了 Slf4j。而他为了 Slf4j 能够兼容各种类型的日志系统实现,还设计了相当多的 adapter 和 bridge 来连接,如下图所示:

鉴于此,在引入日志框架依赖的时候要尽力避免,比如以下组合就不能同时出现:
日志框架的使用选择
常用的组合使用方式是 Slf4j & Logback 组合使用,Commons Logging & Log4j 组合使用。
推荐:
Slf4j & Logback
原因:
1. Slf4j 实现机制决定 Slf4j 限制较少,使用范围更广。相较于 Commons-Logging,Slf4j 在编译期间便静态绑定本地的 Log 库,其通用性要好得多;
2. Logback 拥有更好的性能。Logback 声称:某些关键操作,比如判定是否记录一条日志语句的操作,其性能得到了显著的提高,这个操作在 Logback 中只需 3 ns,而在 Log4j 则需要 30 ns;
3. Slf4j 支持参数化,使用占位符号,代码更为简洁,如下例子:
// 在使用 Commons-Logging 时,通常的做法是
if(log.isDebugEnabled()){
log.debug("User name: " + user.getName() + " buy goods id :" + good.getId());
}
// 在 Slf4j 阵营,你只需这么做:
log.debug("User name:{} ,buy goods id :{}", user.getName(),good.getId());
4. Logback 的所有文档是免费提供的,Log4j 只提供部分免费文档而需要用户去购买付费文档;
5. MDC (Mapped Diagnostic Contexts) 用 Filter,将当前用户名等业务信息放入 MDC 中,在日志 format 定义中即可使用该变量。具体而言,在诊断问题时,通常需要打出日志。如果使用 Log4j,则只能降低日志级别,但是这样会打出大量的日志,影响应用性能;如果使用 Logback,保持原定日志级别而过滤某种特殊情况,如 Alice 这个用户登录,日志将打在 DEBUG 级别而其它用户可以继续打在 WARN 级别。实现这个功能只需加 4 行 XML 配置;
6. 自动压缩日志。RollingFileAppender 在产生新文件的时候,会自动压缩已经打出来的日志文件。压缩过程是异步的,因此在压缩过程中应用几乎不会受影响。
Slf4j+Logback入门实践
maven依赖
pom.xml
<!--日志框架接口-->
<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>
<!--自动化注解工具-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.16</version>
</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>
applicantion.properties
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}[LineNumber:%L]: %msg%n
测试用例
@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");
}
}
参考资料
Java 日志框架: https://zhuanlan.zhihu.com/p/365154773
SLF4J框架常见的用法和最佳实践: https://juejin.cn/post/7215569601161166906
作者:京东零售 张洪
来源:京东云开发者社区 转载请注明来源
日志框架简介-Slf4j+Logback入门实践 | 京东云技术团队的更多相关文章
- 在android中使用logback-android日志框架配置 slf4j + logback
为什么使用 slf4j + logback logbak定位于log4j的替代者,logback同样支持slf4j,方便被替换.在Android平台上,我在使用log4中遇到tag混乱的问题.相比lo ...
- springboot升级过程中踩坑定位分析记录 | 京东云技术团队
作者:京东零售 李文龙 1.背景 " 俗话说:为了修复一个小bug而引入了一个更大bug " 因所负责的系统使用的spring框架版本5.1.5.RELEASE在线上出过一个偶发的 ...
- springboot日志框架学习------slf4j和log4j2
springboot日志框架学习------slf4j和log4j2 日志框架的作用,日志框架就是用来记录系统的一些行为的,可以通过日志发现一些问题,在出现问题之后日志是好的一个帮手. 市面上的日志框 ...
- Java日志框架:SLF4J,Common-Logging,Log4J,Logback说明
Log4j Apache的一个开放源代码项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台.文件.GUI组件.甚至是套接口服务 器.NT的事件记录器.UNIX Syslog守护进程等 ...
- Java日志框架:slf4j作用及其实现原理
简单回顾门面模式 slf4j是门面模式的典型应用,因此在讲slf4j前,我们先简单回顾一下门面模式, 门面模式,其核心为外部与一个子系统的通信必须通过一个统一的外观对象进行,使得子系统更易于使用.用一 ...
- java的几个日志框架log4j、logback、common-logging
开发工作中每个系统都需要记录日志,常见的日志工具有log4j(用的最多),slf4j,commons-loging,以及最近比较流行的logback 以前只是在项目中用log4j,更多的是参考下配置文 ...
- IDEA整合日志框架Log4j2+Slf4j详细配置过程
日志框架这么多,他们之间到底是什么关系呢?笼统的讲就是slf4j是一系列的日志接口,而log4j2.logback是具体实现了接口功能的日志框架.现在的主流日志接口都使用slf4j,而日志的实现就见仁 ...
- Log4j2日志框架集成Slf4j日志门面
1.说明 本文介绍使用日志门面Slf4j打印日志, 底层日志实现使用Log4j2框架, 方便以后切换底层日志实现, Log4j2可以替换成Logback等. 2.依赖管理 在pom.xml依赖管理中导 ...
- 通过哪吒动漫豆瓣影评,带你分析python爬虫与BeautifulSoup快速入门【华为云技术分享】
久旱逢甘霖 西安连着几天温度排行全国三甲,也许是<哪吒之魔童降世>的剧组买通了老天,从踩着风火轮的小朋友首映开始,就全国性的持续高温,还好今天凌晨的一场暴雨,算是将大家从中暑边缘拯救回来了 ...
- 日志框架之2 slf4j+logback实现日志架构 · 远观钱途
如何从缤纷复杂的日志系统世界筛选出适合自己的日志框架以及slf4j+logback的组合美妙之处?此文可能有帮助 logback介绍 Logback是由log4j创始人设计的另一个开源日志组件,官方网 ...
随机推荐
- 【文末彩蛋】数据仓库服务 GaussDB(DWS)单点性能案例集锦
摘要:介绍了13种GaussDB(DWS)单点性能的案例. 一.数据倾斜 1.1 问题描述 某局点SQL执行慢,涉及大表的SQL执行不出来结果. 1.2 分析过程 数据倾斜在很多方面都会有体现: 1) ...
- 使用Mask R-CNN模型实现人体关键节点标注
摘要:在本案例中,我们将展示如何对基础的Mask R-CNN进行扩展,完成人体关键节点标注的任务. 本文分享自华为云社区<使用Mask R-CNN模型实现人体关键节点标注>,作者: 运气男 ...
- 火山引擎 DataLeap 构建Data Catalog系统的实践(一):背景与调研思路
更多技术交流.求职机会,欢迎关注字节跳动数据平台微信公众号,回复[1]进入官方交流群 摘要 Data Catalog 产品,通过汇总技术和业务元数据,解决大数据生产者组织梳理数据.数据消费者找数和理解 ...
- 如何删除PPT中工具栏口袋动画
口袋动画官网无法打开 http://www.papocket.com/ 插件无法使用 卸载 在[程序和功能]中卸载后,打开PPT,菜单还是存在 选项--加载项,点击以p开头的一串代码(com加载项), ...
- 微服务网关 —— SpringCloud Netflix Zuul
概述 Spring Cloud Zuul 是 Spring Cloud Netflix 子项目的核心组件之一,可以作为微服务架构中的 API 网关使用,有以下用途: 鉴权:对于访问每个服务的请求进行鉴 ...
- 在 SDXL 上用 T2I-Adapter 实现高效可控的文生图
T2I-Adapter 是一种高效的即插即用模型,其能对冻结的预训练大型文生图模型提供额外引导.T2I-Adapter 将 T2I 模型中的内部知识与外部控制信号结合起来.我们可以根据不同的情况训练各 ...
- Python 基于深度学习的 opencv 车牌识别系统,可以准确识别车牌号
大家好,我是程序员徐师兄,6 年大厂程序员经验,点击关注我 简介 毕业设计基于Opencv的车牌识别系统 车牌搜索识别找出某个车牌号 对比识别车牌系统 车牌数据库认证系统 车牌图文搜索系统 车牌数据库 ...
- Linux--修改会话超时时间
控制用户在一段时间内没有活动时会话的自动注销时间 1.修改ssh配置文件(适用于SSH会话) vim /etc/ssh/sshd_config ClientAliveInterval 1800 #秒 ...
- vue2.x封装svg组件并使用
https://blog.csdn.net/ChickenBro_/article/details/134027803
- 每天学五分钟 Liunx 0010 | 软件篇: RPM 和 YUM
1. RPM RPM(RedHat Package Manager),顾名思义是 RedHat 的软件包管理器.它遵循 GPL 规则且功能强大好用,从而逐渐运用到其它 Liunx 发行版中,包括 Fe ...