日志框架简介-Slf4j+Logback入门实践 | 京东云技术团队

前言

随着互联网和大数据的迅猛发展,分布式日志系统和日志分析系统已广泛应用,几乎所有应用程序都使用各种日志框架记录程序运行信息。因此,作为工程师,了解主流的日志记录框架非常重要。虽然应用程序的运行结果不受日志的有无影响,但没有日志的应用程序是不完整的,甚至可以说是有缺陷的。优秀的日志系统可以记录操作轨迹监控系统运行状态解决系统故障


Java 日志框架进化史

早期 Java 日志框架没有制定统一的标准,使得很多应用程序会同时使用多种日志框架。Java 日志框架的发展历程大致可分为以下几个阶段:

1.**Log4j:**Apache Log4j是一种基于Java的日志记录工具。该项目由Ceki Gülcü于1999年创建,并几乎成为了Java日志框架的实际标准。

2.**JUL:**Apache 希望将 Log4j 引入 jdk,不过被 sun 公司拒绝了。随后,sun 模仿 Log4j,在 jdk1.4 中引入了 JUL(java.util.logging)。

3.**Commons Logging:**为了解耦日志接口与实现,Apache在2002年推出了JCL(Jakarta Commons Logging)。JCL定义了一套日志接口,具体的实现由Log4j或JUL完成。Commons Logging使用动态绑定来实现日志记录,编码时只需要使用它定义的接口即可,程序运行时会使用ClassLoader来查找和加载底层的日志库,因此可以灵活选择Log4j或JUL来实现日志功能。

4.**Slf4j&Logback:**Ceki Gülcü与Apache基金会在Commons-Logging标准上存在分歧。后来,Ceki Gülcü离开了Apache,并创建了Slf4j和Logback两个项目。Slf4j是一个日志门面,仅提供接口,可以支持Logback、JUL、log4j等日志实现。而Logback则提供了具体的实现。相比于log4j,Logback具有更快的执行速度和更完善的功能。

5.**Log4j 2:**为了保持在Java日志领域的地位,防止JCL和Log4j被Slf4j和Logback取代,Apache在2014年推出了Log4j 2。Log4j 2与log4j不兼容,经过大量深度优化,其性能得到显著提升。


日志框架介绍

在上文中已经提及,目前常用的日志框架有 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 来连接,如下图所示:

鉴于此,在引入日志框架依赖的时候要尽力避免,比如以下组合就不能同时出现:

•jcl-over-slf4j 和 slf4j-jcl

•log4j-over-slf4j 和 slf4j-log4j12

•jul-to-slf4j 和 slf4j-jdk14

日志框架的使用选择

常用的组合使用方式是 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

作者:京东零售 张洪

来源:京东云开发者社区 转载请注明来源

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/305887.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【UE5.1】程序化生成Nanite植被

目录 效果 步骤 一、下载Gaea软件和树林资产 二、使用Gaea生成贴图 三、 生成地形 四、生成草地 五、生成树林 六、生成湖泊 七、其它功能介绍 7.1 调整树林生成的面积 7.2 让植物随风飘动 7.3 玩家和植物互动 7.4 雪中树林 7.5 环境音效 效果 步骤 一、下载Ga…

18-网络安全框架及模型-信息系统安全保障模型

信息系统安全保障模型 1 基本概念 信息系统安全保障是针对信息系统在运行环境中所面临的各种风险&#xff0c;制定信息系统安全保障策略&#xff0c;设计并实现信息系统安全保障架构或模型&#xff0c;采取工程、技术、管理等安全保障要素&#xff0c;将风险减少至预定可接受的…

如何使用群晖Webdav将Obsidian笔记软件远程同步到公网访问

文章目录 1. 群晖开启Webdav服务2. 群晖安装Cpolar3. 配置Webdav远程地址4. Obsidian 安装Remotely Save5. Obsidian远程连接Webdav6. 固定Cpolar公网地址7. PC和移动端笔记同步演示 Obsidian是一款笔记软件&#xff0c;它基于Markdown&#xff0c;支持Windows、macOS、iOS和An…

自然语言处理(第16课 机器翻译4、5/5)

一、学习目标 1.学习各种粒度的系统融合方法 2.学习两类译文评估标准 3.学习语音翻译和文本翻译的不同 4.学习语音翻译实现方法 二、系统融合 以一个最简单的例子来说明系统融合&#xff0c;就是相当于用多个翻译引擎得到不同的翻译结果&#xff0c;然后选择其中最好的作为…

大创项目推荐 深度学习YOLO抽烟行为检测 - python opencv

文章目录 1 前言1 课题背景2 实现效果3 Yolov5算法3.1 简介3.2 相关技术 4 数据集处理及实验5 部分核心代码6 最后 1 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 基于深度学习YOLO抽烟行为检测 该项目较为新颖&#xff0c;适合作为竞赛课…

华为鸿蒙应用--登录页:网络请求、自定义Loading、MD5密码加密、emitter订阅状态变化、持久化登录状态、隐藏软键盘-ArkTs

HarmonyOS系列 华为鸿蒙应用--底部导航栏Tabs&#xff08;自适应手机和平板&#xff09;-ArkTs_华为鸿蒙应用 csdn 底部导航栏-CSDN博客 华为鸿蒙应用--欢迎页SplashPage倒计时跳过&#xff08;自适应手机和平板&#xff09;-ArkTs_app.media.ic_splash_page_background-CSDN…

喜讯,思迈特签约南方电网搭建云景数字化运营管控平台

近日&#xff0c;思迈特软件签约南方电网共同搭建云景数字化运营管控平台。 Smartbi将助力云景平台构建“全域协同&#xff0c;全员参与、全员创新”的数字化运营新生态。该平台以“工具数据”赋能基层&#xff0c;充分释放基层“业务人员数字化人员”专业能力&#xff0c;实现…

电子设计从零开始(2)-----走进电子技术之电阻器

同学们大家好&#xff0c;今天我们继续学习杨欣的《电子设计从零开始》&#xff0c;这本书从基本原理出发&#xff0c;知识点遍及无线电通讯、仪器设计、三极管电路、集成电路、传感器、数字电路基础、单片机及应用实例&#xff0c;可以说是全面系统地介绍了电子设计所需的知识…

NFC刷卡soc芯片SI3262集成刷卡+触摸+ACD超低功耗一体

简介 13.56mhz刷卡soc芯片SI3262集成刷卡触摸ACD超低功耗&#xff0c;ACD模式刷卡距离可达到5cm以上&#xff0c;非常适用于小体积门锁&#xff0c;密码锁&#xff0c;柜锁&#xff0c;接下来介绍一下这款芯片的具体功能。 优势 1.超低功耗&#xff0c;最低功耗达 1.7uA&…

你是否还在用for循环给实体类中的某个属性逐个赋值?尽量避免for循环赋值,应当使用sql关联表的方法去赋值来提升接口请求速度!

在我们的开发中&#xff0c;查询列表&#xff0c;想拿到另外一张表的name&#xff0c;但是列表中存着的是另一个表中的id&#xff0c;这时候使用了for循环去遍历然后通过MybatisPlus提供的方法去getOne获取这一条数据的name&#xff0c;这种方法数据量少还能支撑得住&#xff0…

硅像素传感器文献调研(四)

写在前面&#xff1a; 好喜欢这种短论文哈哈哈哈哈 感觉这篇文献已经提到了保护环的概念啊&#xff0c;只不过叫的是&#xff1a;场限制环。 1986——高压功率器件场终端横向掺杂的变化 0.摘要 对于高压平面结提出了一个简单的新概念。通过在氧化物掩模中的小开口和随后的驱…

mvtec3d

以bagel为例&#xff0c;其中有calibration、 bagel # 百吉圈(硬面包)calibrationcamera_parameters.jsontestcombinedgt # 缺陷部位的分割剪影pngrgb # 原图pngxyz # tiffcontamination # 污染物同上crack同上good同上 hole同上 traingoodrgbxyzvalidationgood同traincla…