百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

SLF4j + Log4j 、Log4j2、 Logback日志框架使用总结

ccwgpt 2025-05-21 12:35 3 浏览 0 评论

从写代码开始,就陆陆续续接触到了许多日志框架,常用的Log4j 、Log4j2、 Logback等。每次自己写项目时,就copy别人的代码或网上的demo。配置log4j.properties或者logback.xml 就能搞定。但是一直没有理清各个框架之间的关系。然后总感觉打印日志的时候并不是随心所欲。特此简单分析分析。

SLF4j是日志门面,是一个日志标准,并非真正的日志实现,log4j、log4j2、logback才是真正的日志实现库。也就是说log4j、log4j2、logback 这兄弟三才是 真正打印日志的。日志门面就是为了统一各个依赖的不同日志实现,便于我们自己项目中对类进行统一维护处理。

再来看看阿里java开发规范:

1.【强制】应用中不可直接使用日志系统(Log4j、Logback)中的 API,而应依赖使用日志框架

SLF4] 中的 API,使用门面模式的日志框架,有利于维护和各个类的日志处理方式统一。

import org.slf4j. Logger;

import org.sLf4j. LoggerFactory;

private static final Logger Logger LoggerFactory.getLogger(Abc.class):

如题,这里选用常用的SLF4j + Log4j 、Log4j2、 Logback 进行分析。

slf4j是门面,大的设计模式是门面系统,而logback是直接实现了slf4j-api中的接口(已经默认实现了SLF4j的日志标准),是通过接口实现的方式完成了门面的实现。而log4j和log4j2没有直接实现接口,所以需要个适配器。slf4j-log4j12和log4j-slf4j-impl就是适配器,将原本不能实现slf4j的变得也能实现这个标准了。添加了适配器后,就能使用slf4j的接口来使用log4j了。

以slf4j 的概念,共可划分为以下4种库:

日志接口层

slf4j-api

common-logging(apache提供的一个通用的日志接口)

jboss-logging(Hibernate集成的日志工具)

日志实现层

JUL(java.util.logging)

log4j

log4j2

logback

slf4j-simple

slf4j-nop

绑定适配(adaptation)层

slf4j-jcl

slf4j-jdk14

slf4j-log412(log4j实现slf标准)

log4j-slf4j-impl(log4j2实现slf标准)

桥接(bridge)层

jcl-over-slf4j

jul-to-slf4j

log4j-over-slf4j(log4j到slf4j的桥梁)

log4j-to-slf4j(log4j2到slf4j的桥梁)

commons-logging

commons-logging也被称为JCL(Java Common Logging),是apache提供的一个通用的日志接口。用户可以自由选择第三方的日志组件作为具体实现,像log4j,或者JDK自带的logging,commons-logging会通过动态查找的机制,在程序运行时自动找出真正使用的日志库,规则是倘若没有定义日志实现,则默认使用JUL日志框架作为日志实现,如果有log4j,则优先使用log4j作为日志实现。当然,commons-logging内部有一个Simple Logger的简单实现,但是功能很弱。所以使用commons-logging,通常都是配合着log4j来使用。使用它的好处就是,代码依赖是commons-logging而非log4j,避免了和具体的日志方案直接耦合,在有必要时,可以更改日志实现的第三方库。

使用commons-logging的常见代码:

import org.apache.commons.logging.Log; 
import org.apache.commons.logging.LogFactory; 
public class A { 
    private static Log logger = LogFactory.getLog(this.getClass());  
}

#使用JUL作为日志实现,仅需在maven工程中导入如下依赖:
 <dependency>
    <groupId>commons-logging</groupId>
    <artifactId>commons-logging</artifactId>
    <version>1.2</version>
</dependency>

#使用log4j作为日志实现,仅需在maven工程中导入如下依赖:
 <dependency>
    <groupId>commons-logging</groupId>
    <artifactId>commons-logging</artifactId>
    <version>1.2</version>
</dependency>
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j<artifactId>
    <version>1.2.17</version>
</dependency>

jul-to-slf4j.jar和slf4j-jdk14.jar 二者不能同时存在

slf4j-jdk14.jar是jul到SLF4J的绑定,将强制SLF4J的调用分配给jul。另一方面,jul-to-slf4j.jar,加上SLF4JBridgeHandler的安装,加上SLF4JBridgeHandler的安装,通过调用“
SLF4JBridgeHandler.install()“将jul记录发送给SLF4J。因此,如果两个jar文件同时存在(SLF4JBridgeHandler已安装),slf4的调用将被分配给jul, jul记录将发送到SLF4J,导致一个死循环。


各个库单独使用

  • log4j
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>

classpath下配置文件log4j.properties

log4j.rootLogger=INFO,console
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.target=System.out
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%p] %c: %m%n

使用:

import org.apache.log4j.Logger;
...
static final Logger LOGGER = Logger.getLogger(Main.class);
  • log4j2

classpath下log4j2.properties

rootLogger.level = info
rootLogger.appenderRef.stdout.ref = STDOUT

appender.console.type = Console
appender.console.name = STDOUT
appender.console.layout.type = PatternLayout
appender.console.layout.pattern = %d{yyyy-MM-dd HH:mm:ss} [%p] %c: %m%n

使用:

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
...
static final Logger LOGGER = LogManager.getLogger(Main.class);
  • logback
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.2.3</version>
</dependency>

classpath下logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss} [%p] %c: %m%n</pattern>
        </encoder>
    </appender>
    <root level="debug">
        <appender-ref ref="console" />
    </root>
</configuration>

使用:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
...
static final Logger LOGGER = LoggerFactory.getLogger(Main.class);

注意:logback本身就是实现slf4j的,如上代码中的logger本就是slf4j的。然而log4j 和 log4j2 的logger都不是slf4j的。当然是可以升级的

为啥要升级?是想要统一到一个门面标准升级:基础库如何升级到SLF4j标准log4j实现方式,引入slf4j-log4j12,即加一个适配器。

 <dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.7.29</version>
</dependency>

log4j2的实现方式,引入log4j-slf4j-impl ,也是加一个适配器

<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.12.1</version>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-slf4j-impl</artifactId>
    <version>2.9.0</version>
</dependency>

这样组装后就可以用slf4j的写法了,统一了门面标准。

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
...
static final Logger LOGGER = LoggerFactory.getLogger(Main.class);

实际项目中,往往会依赖于其它的包,这些依赖包可能就是不同的日志实现方式

生产场景一:某项目依赖到的其余三个包 的日志实现分别是 log4j、log4j2、logback 。

这个时候我们不做统一处理的话,当然是不会冲突 报错的,只是打印的日志时候就会各自找各自的日志实现。

其中一种方式是可以 在我们的项目的redources下,新增 log4j.properties / log4j2.properties 和 logback.xml 共3个配置文件来自定义 (覆盖) 日志输出方式 ,这样,输出的日志也是会按照我们配置的进行正确输出。

生产场景二:某项目依赖到的其余三个包 的日志实现分别是 log4j log4j2 logback 。但是log4j 和 log4j2 已经统一了门面标准为SLF4J

这个实现我们项目在打印日志的时候,就会根据类加载随机选择一个日志实现,可能就是按照log4j的配置文件实现方式进行日志的打印。

问题:这种情况如何指定特定的日志实现库呢?假如期望项目使用logback,并期望统一为slf化的logback形式,只配置一个logback.xml就能对所有依赖进行配置这个时候可以分别剔除A依赖包的和B依赖包。

     <exclusions>
                <exclusion>
                    <groupId>org.slf4j</groupId>
                    <artifactId>slf4j-log4j12</artifactId>
                </exclusion>
            </exclusions>
      <exclusions>
                <exclusion>
                    <groupId>org.apache.logging.log4j</groupId>
                    <artifactId>log4j-slf4j-impl</artifactId>
                </exclusion>
            </exclusions>

这个时候,只需要在我们项目的resources目录下配置一个logback.xml文件即可。当然,很有可能我们在项目中是不清楚哪一个依赖包使用到了log4j 和 log4j2 的,这个时候我们是可以在 pom 文件的最后 写一个不存在的版本:

ps:maven加载方式按照最外层优先使用,如果引入一个不存在的,那么maven就不会加载这个依赖了。

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>99.99.99</version>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-slf4j-impl</artifactId>
    <version>99.99.99</version>
</dependency>

也是能够达到去除slf化 ,从而使用统一的logback打印日志的效果的

生产场景三:某项目依赖到的其余三个包 的日志实现分别是 log4j log4j2 logback 。但是log4j 和 log4j2 并没有实现slf门面标准。但是又想要统一为slf化的logback形式。怎么办呢?

也就是说要先对log4j 和 log4j2 进行slf 化才行。

思路:

1.先在整个项目下吧原有的log4j 和log4j2 剔除掉

2.再使用其它已经桥接好的log4j 和 log4j2 的包来代替slf 化的log4j 和 log4j2 的包

以下配置几乎是万能的,当遇到问题的时候,直接全部拷贝进去,稳定解决。

<!-- 处理单独log4j的依赖: -->
<!-- 用log4j-over-slf4j替换log4j,使依赖中的log4j也能"实现"slf4j-->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>log4j-over-slf4j</artifactId>
    <version>1.7.29</version>
</dependency>
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>99.99.99</version>
</dependency>

<!-- 处理单独log4j2的依赖: -->
<!-- 用log4j-to-slf4j替换log4j2,使依赖中的log4j2也能"实现"slf4j -->
 <dependency>
    <groupId>org.apache.logging.log4j</groupId>
     <artifactId>log4j-to-slf4j</artifactId>
    <version>2.12.1</version>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>99.99.99</version>
</dependency>

<!-- 处理slf化的log4j的依赖: -->
<!-- 因为slf选binding的时候有多个候选,为防止slf4j-log4j12选中,直接去掉他 -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>99.99.99</version>
</dependency>

<!-- 处理slf化的log4j2的依赖: -->
<!-- 因为slf选binding的时候有多个候选,为防止log4j-slf4j-impl选中,直接去掉他 -->
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-slf4j-impl</artifactId>
    <version>99.99.99</version>
</dependency>

<!-- 最后引个新版本的logback -->
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.2.3</version>
</dependency>

小结

  • slf4j-log4j12:与log4j联合使用,用于使当前项目的log4j实现slf标准
  • log4j-slf4j-impl:与log4j2联合使用,用于使当前项目的log4j2实现slf标准
  • log4j-over-slf4j:与剔除log4j联合使用,替换log4j,使log4j实现slf。用于让单独用log4j的依赖能遵循slf,进而统一日志配置。
  • log4j-to-slf4j:与剔除log4j2联合使用,替换log4j2,使log4j2实现slf。用于让单独用log4j2的依赖能遵循slf,进而统一日志配置。

相关推荐

SLF4j + Log4j 、Log4j2、 Logback日志框架使用总结

从写代码开始,就陆陆续续接触到了许多日志框架,常用的Log4j、Log4j2、Logback等。每次自己写项目时,就copy别人的代码或网上的demo。配置log4j.properties或者lo...

轻量级日志追踪方案——TLog

TLog概述TLog提供了一种最简单的方式来解决日志追踪问题,它不收集日志,也不需要另外的存储空间,它只是自动的对你的日志进行打标签,自动生成TraceId贯穿你微服务的一整条链路。并且提供上下游节点...

Java中优雅实现日志记录:Spring AOP秘籍

Java中优雅实现日志记录:SpringAOP秘籍在软件开发中,日志记录是一项非常重要的任务。它不仅帮助我们追踪程序执行的过程,还能在出现问题时快速定位错误原因。在Java世界里,Spring框架为...

Redis与Java整合的最佳实践

Redis与Java整合的最佳实践在这个数字化时代,数据处理速度决定了企业的竞争力。Redis作为一款高性能的内存数据库,以其卓越的速度和丰富的数据结构,成为Java开发者的重要伙伴。本文将带你深入了...

SpringBoot2.x系列教程54--SpringBoot整合日志记录项目重要信息

前言我们在进行项目开发时,无论是前端还是后端,都必须进行日志的记录。通过日志,来记录项目开发、运行时产生的各种异常信息和重要数据。这样我们才能对项目的异常进行定位,对项目的后期运营提供数据支撑。但我们...

Spring Boot中的Logback日志配置详解

在SpringBoot开发中,日志作为检查问题、追踪系统、分析系统性能的手段之一,为开发者提供了各种快速解决问题的方案。而在SpringBoot中默认采用的日志框架是LogBack,作为一个功能强...

MyBatis系列-2-日志配置

日积月累,方成大器。各大网站:Mybatis官方技术文档https://mybatis.org/mybatis-3/zh/index.htmlMybatis源码包下载:https://github...

Springboot强大的日志功能你真的了解吗?这些功能你肯定不知道

环境:Springboot2.4.10日志配置详解SpringBoot使用CommonsLogging记录所有内部日志,但保留底层日志实现的打开状态。为JUL日志记录、Log4J2和Logback...

SpringBoot中14个日志使用技巧

前言:日志是软件开发中不可或缺的一部分,它能帮助我们了解应用运行状态、调试问题和监控性能。1.使用SLF4J门面模式统一日志APISLF4J(SimpleLoggingFacadeforJ...

探索Java项目中日志系统最佳实践:从入门到精通

探索Java项目中日志系统最佳实践:从入门到精通在现代软件开发中,日志系统如同一位默默无闻却至关重要的管家,它记录了程序运行中的各种事件,为我们排查问题、监控性能和优化系统提供了宝贵的依据。在Java...

# 怎么让 java -jar example.jar 产生的日志输出到指定文件

#怎么让java-jarexample.jar产生的日志输出到指定文件要实现java-jarexample.jar命令产生的日志输出到指定文件,可以使用以下几种方法:##一、方法1...

探秘Logback:优雅管理Java日志的魔法工具

探秘Logback:优雅管理Java日志的魔法工具在Java的世界里,日志记录是每个开发者都绕不开的重要话题。想象一下,如果没有日志,我们的程序就像一辆没有仪表盘的汽车,既看不到速度,也摸不清方向。而...

SLF4J与Logback:Java日志世界的双子星

SLF4J与Logback:Java日志世界的双子星在Java的世界里,日志记录就像空气一样无处不在。无论是调试程序还是排查生产环境的问题,日志都是我们不可或缺的好帮手。而提到日志框架,SLF4J和L...

SLF4J与Logback:让Java日志记录变得简单优雅

SLF4J与Logback:让Java日志记录变得简单优雅在Java开发的世界里,日志记录是一项不可或缺的技术。它不仅帮助我们追踪程序运行的状态,还能在排查问题时提供重要的线索。今天,我们就来聊聊两个...

阿里强制使用SLF4J日志框架的缘由

背景想必小伙伴们都用过日志,虽然日志看起来可有可无,但是等到出问题的时候,就比较棘手。所以说日志框架使用好不好,规范不规范,直接影响了解决生产环境故障的效率,日志框架选的不好、用的不好,有可能影响环境...

取消回复欢迎 发表评论: