0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看威廉希尔官方网站 视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

日志框架简介-Slf4j+Logback入门实践

京东云 来源:jf_75140285 作者:jf_75140285 2024-07-30 10:00 次阅读

前言

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

Java 日志框架进化史

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

wKgZomandamADVaeAADrIxKpkeI928.jpg

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等。

wKgaomandamAZ0mSAACXshr4Kag764.jpg

通过使用日志门面,我们可以在应用程序中使用统一的API进行日志记录,而具体的日志实现可以根据需要选择和配置。这样,我们可以根据项目需求和团队喜好来灵活选择、切换和配置日志系统,而不会对应用程序代码造成太大影响。

避免环形依赖

Slf4j 的作者 Ceki Gülcü 当年因为觉得 Commons-Logging 的 API 设计的不好,性能也不够高,因而设计了 Slf4j。而他为了 Slf4j 能够兼容各种类型的日志系统实现,还设计了相当多的 adapter 和 bridge 来连接,如下图所示:

wKgZomandaqAEE-TAAEa1fU9SK4082.jpg

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

•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

审核编辑 黄宇

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 框架
    +关注

    关注

    0

    文章

    403

    浏览量

    17475
  • logback
    +关注

    关注

    0

    文章

    2

    浏览量

    898
收藏 人收藏

    评论

    相关推荐

    slf4j打印日志必须的三个依赖包相关资料推荐

    1、slf4j打印日志必须的三个依赖包  日志相关包 slf4j打印日志必须的三个依赖包  slf4j
    发表于 10-19 14:57

    TDK贴片电感规格书—SLF系列

    Type: Issue date: SLF6025 (6.0x6.0 mm) SLF6028 (6.0x6.0 mm) SLF6045 (6.0x6.0 mm) SLF7032 (7.
    发表于 10-26 17:23 194次下载
    TDK贴片电感规格书—<b class='flag-5'>SLF</b>系列

    java 日志框架Spring Boot分析

    应用程序中输出相应的日志。 在传统Java应用程序中,我们一般会使用类似Log4j这样的日志框架来输出日志,而不是直接在代码中通过Syste
    发表于 09-28 14:58 0次下载

    logback异常输出详细信息(调用堆栈)分析

     Logback是一个开源的日志组件,是log4j的作者开发的用来替代log4j的。logback由三个部分组成,
    发表于 11-28 16:31 8334次阅读

    基于时间卷积网络的通用日志序列异常检测框架

    基于循环神经网络的日志序列异常检测模型对短序列有较好的检测能力,但对长序列的检测准确性较差。为此,提出一种基于时间卷积网络的通用日志序列异常检测框架。将日志模板序列建模为自然语言序列,
    发表于 03-30 10:29 8次下载
    基于时间卷积网络的通用<b class='flag-5'>日志</b>序列异常检测<b class='flag-5'>框架</b>

    Java日志框架中的王者是谁

    不及Apache 的新一代日志框架 - Log4j 目前来看,Log4j2 就是王者,其他日志框架
    的头像 发表于 10-13 09:12 1362次阅读

    GitHub入门实践

    GitHub入门实践
    发表于 11-21 10:40 0次下载

    java日志框架 java日志配置等需要注意的几个方面

    前言 1. 日志框架众多,兼容问题 2. 日志配置复杂,容易出错 3. 日志异步乱用,导致日志错乱 4
    的头像 发表于 11-15 16:13 1000次阅读

    委派模式——从SLF4J说起

    SLF4J全称"Simple Logging Facade for Java (SLF4J) ", 它诞生之初的目的,是为了针对不同的log解决方案,提供一套统一的接口适配标准,从而让业务代码无须关心使用到的第三方模块都使用了哪些log方案。
    的头像 发表于 01-31 15:12 519次阅读

    如何复现Log4j2漏洞

    ApacheLog4j2是一个开源的Java日志框架,被广泛地应用在中间件、开发框架与Web应用中。
    的头像 发表于 02-13 10:55 1374次阅读

    顶级Javaer都在使用的类库!

    日志库非常常见,因为您在每个项目中都需要它们。它们对于服务器端应用程序来说是最重要的,因为日志只放置在您可以看到应用程序正在发生什么的地方。尽管 JDK 附带了自己的日志库,但仍有更好的替代方案可用,例如 Log
    的头像 发表于 02-16 10:11 614次阅读

    log4j日志框架分析

    og4j是Apache下的一款开源的日志框架,能够满足我们在项目中对于日志记录的需求。log4j提供了简单的API调用,强大的
    的头像 发表于 02-28 14:32 1114次阅读
    log<b class='flag-5'>4j</b><b class='flag-5'>日志</b><b class='flag-5'>框架</b>分析

    Spring Boot的日志框架使用

    目前市面上常见的日志框架有:slf4j(Simple Logging Facade for Java)、logback、log4j、log
    的头像 发表于 06-02 10:59 943次阅读
    Spring Boot的<b class='flag-5'>日志</b><b class='flag-5'>框架</b>使用

    深度学习框架pytorch入门实践

    深度学习框架pytorch入门实践 深度学习是机器学习中的一个分支,它使用多层神经网络对大量数据进行学习,以实现人工智能的目标。在实现深度学习的过程中,选择一个适用的开发框架是非常关
    的头像 发表于 08-17 16:03 1593次阅读

    保护Log4j日志中的敏感数据,两步搞定!

    log4j在准备添加日志消息时调用此方法。在MaskingAppender类中,我们覆盖这个方法来拦截日志消息,使用maskSensitiveData()方法对敏感数据应用masking,然后将修改后的消息传递给超类的appen
    的头像 发表于 10-18 16:03 757次阅读