日志框架简介-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.rhkb.cn/news/227455.html

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

相关文章

【Matlab】BP 神经网络时序预测算法

资源下载&#xff1a; https://download.csdn.net/download/vvoennvv/88681507 一&#xff0c;概述 BP 神经网络是一种常见的人工神经网络&#xff0c;也是一种有监督学习的神经网络。其全称为“Back Propagation”&#xff0c;即反向传播算法。BP 神经网络主要由输入层、隐藏层…

如何恢复 iPhone 上永久删除的照片?

2007年&#xff0c;苹果公司推出了一款惊天动地的智能手机&#xff0c;也就是后来的iPhone。你会惊讶地发现&#xff0c;迄今为止&#xff0c;苹果公司已经售出了 7 亿部 iPhone 设备。根据最新一项调查数据&#xff0c;智能手机利润的 95% 都进了苹果公司的腰包。 如此受欢迎…

Android实验:contentprovider 实验+SQLite 数据库的实现

目录 SQLite实验目的实验内容实验要求项目结构代码实现结果展示 SQLite SQLite 是一个开源的嵌入式关系数据库&#xff0c;实现了自给自足的、无服务器的、配置无需的、事务性的 SQL 数据库引擎。它是一个零配置的数据库&#xff0c;这意味着与其他数据库系统不同&#xff0c;…

安全生产知识竞赛活动方案

为进一步普及安全生产法律法规知识&#xff0c;增强安全意识&#xff0c;提高安全技能&#xff0c;经研究&#xff0c;决定举办以“加强安全法治、保障安全生产”为主题的新修订《安全生产法》知识竞赛活动&#xff0c;现将有关事项通知如下&#xff1a; 一、活动时间&#xf…

【教学类-43-03】20231229 N宫格数独3.0(n=1、2、3、4、6、8、9) (ChatGPT AI对话大师生成 回溯算法)

作品展示&#xff1a; 背景需求&#xff1a; 大4班20号说&#xff1a;我不会做这种&#xff08;九宫格&#xff09;&#xff0c;我做的是小格子的&#xff0c; 他把手工纸翻过来&#xff0c;在反面自己画了矩阵格子。向我展示&#xff1a;“我会做这种&#xff01;” 原来他会…

分类预测 | Matlab实现SCSO-SVM基于沙猫群优化算法优化支持向量机的多变量分类预测【23年新算法】

分类预测 | Matlab实现SCSO-SVM基于沙猫群优化算法优化支持向量机的多变量分类预测【23年新算法】 目录 分类预测 | Matlab实现SCSO-SVM基于沙猫群优化算法优化支持向量机的多变量分类预测【23年新算法】分类效果基本描述程序设计参考资料 分类效果 基本描述 1.Matlab实现SCSO-…

2023十大编程语言及未来展望

2023十大编程语言及未来展望 1. 2023年十大编程语言排行榜2. 十大编程语言未来展望PythonCCJavaC#JavaScriptPHPVisual BasicSQLAssembly language 1. 2023年十大编程语言排行榜 TIOBE排行榜是根据互联网上有经验的程序员、课程和第三方厂商的数量&#xff0c;并使用搜索引擎&a…

Peter算法小课堂—浮点数危机

大家先想想下面这个代码运行结果&#xff1a; #include <bits/stdc.h> using namespace std; int main(){double x5.2;double y4.11.1;cout<<(x<y)<<endl;cout<<x-y<<endl;return 0; } 最终发现&#xff0c; &#xff1f;&#xff1f;&…

css 用多个阴影做出光斑投影的效果 box-shadow

css 用多个阴影做出光斑投影的效果 box-shadow 你首先需要知道的一点是 box-shadow 可以接收多个值&#xff0c;也就是可以设置多个阴影&#xff0c;这样就可以做一个类似光斑投影的效果。 一、效果 二、代码 里面用到了我一些 scss 工具方法&#xff0c;不过不影响&#xf…

【音视频 ffmpeg 学习】 RTMP推流 mp4文件

1.RTMP(实时消息传输协议)是Adobe 公司开发的一个基于TCP的应用层协议。 2.RTMP协议中基本的数据单元称为消息&#xff08;Message&#xff09;。 3.当RTMP协议在互联网中传输数据的时候&#xff0c;消息会被拆分成更小的单元&#xff0c;称为消息块&#xff08;Chunk&#xff…

二叉树的中序遍历,力扣

目录 题目地址&#xff1a; 题目&#xff1a; 解题方法&#xff1a; 解题分析&#xff1a; 解题思路&#xff1a; 代码实现&#xff1a; 注&#xff1a; 代码实现&#xff08;递归&#xff09;&#xff1a; 代码实现&#xff08;迭代&#xff09;&#xff1a; 题目地址&#xf…

【目标检测】yolov8结构及代码分析

yolov8代码:https://github.com/ultralytics/ultralytics yolov8的整体结构如下图&#xff08;来自mmyolo&#xff09;&#xff1a; yolov8的配置文件&#xff1a; # Ultralytics YOLO &#x1f680;, AGPL-3.0 license # YOLOv8 object detection model with P3-P5 outputs.…

跨境电商迎来综合竞争力比拼时代 五大趋势解读跨境2024

过去几年&#xff0c;跨境电商成为外贸出口增长的一大亮点&#xff0c;随着年底国务院办公厅《关于加快内外贸一体化发展的若干措施》的发布&#xff0c;跨境电商在促进经济发展、助力内外贸一体化发展方面的价值更加凸显。 这是跨境电商变化最快的时代&#xff0c;也是跨境电…

GrayLog日志平台的基本使用-ssh之Email报警

1、首先编辑并添加邮件配置到server.conf&#xff08;注意&#xff1a;是添加&#xff09; vim /etc/graylog/server/server.conf # Email transport transport_email_enabled true transport_email_hostname smtp.qq.com transport_email_port 465 transport_email_use_a…

Net6 Core webApi发布到IIS

Net6 Core Api发布到IIS不同于webapi&#xff0c;依赖框架不同&#xff0c;配置也移至项目内Program.cs 一、发布到指定文件夹和IIS&#xff0c;不过注意IIS应用程序池选择的是 “无托管代码“ 在IIS管理器中点击浏览&#xff0c;访问接口路径报500.19&#xff0c;原因是所依赖…

杰发科技AC7840——EEPROM初探

0.序 7840和7801的模拟EEPROM使用不太一样 1.现象 按照官方Demo&#xff0c;在这样的配置下&#xff0c;我们看到存储是这样的&#xff08;连续三个数字1 2 3&#xff09;。 使用串口工具的多帧发送功能 看不出多少规律 修改代码后 发现如下规律&#xff1a; 前四个字节是…

GBASE南大通用携手宇信科技打造“一表通”全链路解决方案

什么是“一表通”&#xff1f; “一表通”是国家金融监督管理总局为发挥统计监督效能、完善银行保险监管统计制度、推进监管数据标准化建设、打破数据壁垒&#xff0c;而制定的新型监管数据统计规范。相较于以往的报送接口&#xff0c;“一表通”提高了对报送时效性、校验准确…

stm32学习笔记:TIM-定时中断和外部时钟

定时器四部分讲解内容&#xff0c;本文是第一部分 ​​​​​TIM简介 基本定时器 时基单元&#xff1a;预分频器、计数器、自动重装载寄存器 预分频器之前&#xff0c;连接的就是基准计数时钟的输入&#xff0c;由于基本定时器只能选择内部时钟&#xff0c;所以可以认为这根…

【MySQL】数据库之存储过程(“SQL语句的脚本“)

目录 一、什么是存储过程&#xff1f; 二、存储过程的作用 三、如何创建、调用、查看、删除、修改存储过程 四、存储过程的参数&#xff08;输入参数&#xff0c;输出参数&#xff0c;输入输出参数&#xff09; 第一种&#xff1a;输入参数 第二种&#xff1a;输出参数 …

【数据结构】什么是二叉树?

&#x1f984;个人主页:修修修也 &#x1f38f;所属专栏:数据结构 ⚙️操作环境:Visual Studio 2022 目录 &#x1f4cc;二叉树的定义 &#x1f4cc;二叉树的特点 &#x1f4cc;特殊二叉树 &#x1f4cc;二叉树的性质 &#x1f4cc;二叉树的存储结构 &#x1f4cc;二叉树…