最通俗易懂的 JAVA slf4j,log4j,log4j2,logback 关系与区别以及完整集成案例

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 最通俗易懂的 JAVA slf4j,log4j,log4j2,logback 关系与区别以及完整集成案例

slf4j 于log4j,log4j2,logback 是什么关系,有何区别

什么是 slf4j

slf4j不是一个真正意义的可用应用程序,他是一个接口层

就像java 的接口性质一样,单纯集成了slf4j 的话,执行比如log.info log.debug等方法,只能在控制台打印日志,并不会在持久化到文件,或者其他自定义介质上,slf4j至少需要一个实现层框架,比如log4j,logback等

什么是 log4j,log4j2,logback

log4j,log4j2(log4j的2.0+版本),logback都是log日志的实现框架,作者都是Ceki Gülcü或者说是他的团队,最早开发的是log4j,并基于slf4j和log4j,优化开发了logback,再后来又用全新的技术disruptor框架

重构log4j底层并将logback取其精华重新搭建了一个全新的框架log4j2

也就是log4j的2.0+版本,可以这么理解,logback是log4j的升级版,但并没有用log4j那套接口 log4j2

推翻了log4j和logbak所有底层实现,但是复用了log4j的几大模块和接口

slf4j,log4j,log4j2,logback的关系

前面说了slf4j只是接口层,必须依赖实现层的框架实现接口层才能真正实现日志记录 log4j(与slf4j接口一致无需适配),log4j2,logback(本身内嵌了slf4j

转换器)都是实现层的框架,但是其实都是有自己独立的接口层的,但是这就有一个问题

一个应用程序用了独立用了log4j款就改,如果哪天想要切换成logback框架的话,所有的log初始化以及log

debug,info等语句都要替换

那么工作量太大了,几乎就是整个项目级别的日志语法替换,所以就需要以后所有开发的应用程序都基于接口层统一提供log初始化以及log.debug,log.info语法记录

基于这一点log4j的作者Ceki Gülcü,独立开发了一个slf4j层,专门用来适配底层的实现

就算你这个日志实现框架比如log4j2,logback

目前提供的接口不兼容slf4j也没关系,再开发一个xxx-slf4j-impl实现就slf4j的接口就可以了,相当于做了一个adapter

比如应用程序的底层实现框架用的是log4j2,但是接口层我想要用slf4j接口层,那么就引入一个log4j-slf4j-impl.jar等就可以了

slf4j,log4j,log4j2,logback 时间线

log4j ->slf4j ->logback ->log4j2

slf4j,log4j,log4j2,logback 关系图




23e56a4dd7504ee3803c513e23d91aae.png

日志框架完整集成例子

首先设置资源目录

logback 日志框架完整集成例子

 <!--slf4j 依赖-->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.25</version>
        </dependency>
        <!-- logback依赖 -->
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>

logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <!--通用格式配置-->
    <property name="pattern" value="[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} %c %M %L %thread %m%n"/>
    <!-- 配置文件的输出路径 -->
    <property name="logDir" value="E:/code/log"/>
    <!-- 配置文件的appender 普通文件-->
    <appender name="fileAppender" class="ch.qos.logback.core.FileAppender">
        <!-- 引入文件位置 -->
        <file>${logDir}/test_logback.log</file>
        <!-- 配置日志输出格式 -->
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!-- 格式引用通用属性配置 -->
            <pattern>${pattern}</pattern>
        </encoder>
    </appender>
    <!-- 配置控制台appender -->
    <appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
        <!--默认:System.out 表示以黑色字体输出日志-->
        <!--设置:System.err 表示以红色字体输出日志-->
        <target>
            System.err
        </target>
        <!--配置日志输出格式-->
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!-- 格式引用通用属性配置 -->
            <pattern>${pattern}</pattern>
        </encoder>
    </appender>
    <!--
        日志记录器
        配置root logger
        level:配置日志级别
        可以同时配置多个appender,做日志的多方向输出
    -->
    <root level="ALL">
        <!-- 引入控制台appender -->
        <appender-ref ref="consoleAppender"/>
        <!-- 引入普通文件appender -->
        <appender-ref ref="fileAppender"/>
    </root>
</configuration>

logback demo code

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
 * @Author alan.wang
 */
public class LogTester {
    private static Logger logger = LoggerFactory.getLogger(LogTester.class);
    public static void main(String[] args){
        logger.debug("这是Log4j2 debug");
        logger.info("这是Log4j2 info");
        logger.warn("这是Log4j2 warn");
        logger.error("这是Log4j2 error");
    }
}

logback日志执行结果

我们看一下logback.xml设置的文件位置以及输出内容

log4j2 日志框架完整集成例子


 <!--log4j2 依赖-->
        <!-- Slf4j的核心包,只有日志的接口,整合log4j2并没有实现 -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.25</version>
        </dependency>
        <!-- 桥接器,将JCL的日志输出重定向到Slf4j中 -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>jcl-over-slf4j</artifactId>
            <version>1.7.25</version>
            <scope>runtime</scope>
        </dependency>
        <!-- 导入日志框架核心包与接口包 -->
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>2.9.1</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-api</artifactId>
            <version>2.9.1</version>
            <scope>runtime</scope>
        </dependency>
        <!--用于slf4j与log4j2保持桥接 -->
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-slf4j-impl</artifactId>
            <version>2.9.1</version>
            <scope>runtime</scope>
        </dependency>
        <!--用于解决web环境下关闭服务器时可能出现的log4j线程无法及时关闭的warn,web工程需要包含log4j-web,非web工程不需要 -->
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-web</artifactId>
            <version>2.9.1</version>
            <scope>runtime</scope>
        </dependency>
        <!--使用log4j2的AsyncLogger时需要包含disruptor -->
        <dependency>
            <groupId>com.lmax</groupId>
            <artifactId>disruptor</artifactId>
            <scope>runtime</scope>
            <version>3.4.2</version>
        </dependency>

log4j2.xml

<Configuration status="warn" monitorInterval="30">
    <Properties>
        <!-- 需要配置日志目录 -->
        <Property name="baseDir">E:/code/log</Property>
        <Property name="appName">test_log4j2</Property>
        <Property name="pattern">%d %-5p [%t] [%c{1.}] %.-300m%n</Property>
    </Properties>
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="${pattern}"/>
        </Console>
        <RollingFile name="File" fileName="${baseDir}/${appName}/${appName}.log" filePattern="${baseDir}/${appName}/%d{yyyyMMdd}-%i.${appName}.log">
            <PatternLayout pattern="${pattern}"/>
            <Policies>
                <TimeBasedTriggeringPolicy/>
                <SizeBasedTriggeringPolicy size="2048 MB"/>
            </Policies>
            <DefaultRolloverStrategy max="30">
                <Delete basePath="${baseDir}/${appName}" maxDepth="1">
                    <IfFileName glob="*/*.log"/>
                    <IfLastModified age="20d"/>
                </Delete>
            </DefaultRolloverStrategy>
        </RollingFile>
    </Appenders>
    <Loggers>
        <Root level="debug" includeLocation="false" additivity="false">
            <AppenderRef ref="Console"/>
            <AppenderRef ref="File"/>
        </Root>
    </Loggers>
</Configuration>

logback demo code

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
 * @Author alan.wang
 */
public class LogTester {
    private static Logger logger = LoggerFactory.getLogger(LogTester.class);
    public static void main(String[] args){
        logger.debug("这是Log4j2 debug");
        logger.info("这是Log4j2 info");
        logger.warn("这是Log4j2 warn");
        logger.error("这是Log4j2 error");
    }
}

log4j2日志执行结果

我们看一下log4j2.xml设置的文件位置以及输出内容

logback,log4j2 同时框架同时存在时,slf4j会用哪个实现

有些时候我们引入第三方或者自己多个模块引入时会不小心同时集成了多个日志框架比如同时继承了logback和log4j2 ,这时候他会报错还是会用哪个呢,我们测试结果如下:

首先他会输出提示提醒你发现了哪些可以绑定的实现框架

然后会告诉你最终用了哪个

目录
打赏
0
1
0
0
17
分享
相关文章
【日志框架整合】Slf4j、Log4j、Log4j2、Logback配置模板
本文介绍了Java日志框架的基本概念和使用方法,重点讨论了SLF4J、Log4j、Logback和Log4j2之间的关系及其性能对比。SLF4J作为一个日志抽象层,允许开发者使用统一的日志接口,而Log4j、Logback和Log4j2则是具体的日志实现框架。Log4j2在性能上优于Logback,推荐在新项目中使用。文章还详细说明了如何在Spring Boot项目中配置Log4j2和Logback,以及如何使用Lombok简化日志记录。最后,提供了一些日志配置的最佳实践,包括滚动日志、统一日志格式和提高日志性能的方法。
997 31
【日志框架整合】Slf4j、Log4j、Log4j2、Logback配置模板
SpringBoot入门(6)- 添加Logback日志
SpringBoot入门(6)- 添加Logback日志
138 5
Java中Log级别和解析
日志级别定义了日志信息的重要程度,从低到高依次为:TRACE(详细调试)、DEBUG(开发调试)、INFO(一般信息)、WARN(潜在问题)、ERROR(错误信息)和FATAL(严重错误)。开发人员可根据需要设置不同的日志级别,以控制日志输出量,避免影响性能或干扰问题排查。日志框架如Log4j 2由Logger、Appender和Layout组成,通过配置文件指定日志级别、输出目标和格式。
Java 高级面试技巧:yield() 与 sleep() 方法的使用场景和区别
本文详细解析了 Java 中 `Thread` 类的 `yield()` 和 `sleep()` 方法,解释了它们的作用、区别及为什么是静态方法。`yield()` 让当前线程释放 CPU 时间片,给其他同等优先级线程运行机会,但不保证暂停;`sleep()` 则让线程进入休眠状态,指定时间后继续执行。两者都是静态方法,因为它们影响线程调度机制而非单一线程行为。这些知识点在面试中常被提及,掌握它们有助于更好地应对多线程编程问题。
62 9
Java面试必问!run() 和 start() 方法到底有啥区别?
在多线程编程中,run和 start方法常常让开发者感到困惑。为什么调用 start 才能启动线程,而直接调用 run只是普通方法调用?这篇文章将通过一个简单的例子,详细解析这两者的区别,帮助你在面试中脱颖而出,理解多线程背后的机制和原理。
67 12
JAVA线程池有哪些队列? 以及它们的适用场景案例
不同的线程池队列有着各自的特点和适用场景,在实际使用线程池时,需要根据具体的业务需求、系统资源状况以及对任务执行顺序、响应时间等方面的要求,合理选择相应的队列来构建线程池,以实现高效的任务处理。
123 12
Java社招面试题:& 和 && 的区别,HR的套路险些让我翻车!
今日分享的主题是如何区分&和&&的区别,提高自身面试的能力。主要分为以下四部分。 1、自我面试经历 2、&amp和&amp&amp的不同之处 3、&对&&的不同用回答逻辑解释 4、彩蛋
Java社招面试题:& 和 && 的区别,HR的套路险些让我翻车!
小米,29岁程序员,分享了一次面试经历,详细解析了Java中&和&&的区别及应用场景,展示了扎实的基础知识和良好的应变能力,最终成功获得Offer。
108 14
|
2月前
|
java中面向过程和面向对象区别?
java中面向过程和面向对象区别?
37 1
java 中操作字符串都有哪些类,它们之间有什么区别
Java中操作字符串的类主要有String、StringBuilder和StringBuffer。String是不可变的,每次操作都会生成新对象;StringBuilder和StringBuffer都是可变的,但StringBuilder是非线程安全的,而StringBuffer是线程安全的,因此性能略低。
105 8

热门文章

最新文章

AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等