java日志系统经常遇到SLF4j,JCL,logback,log4j2等等。一些人可能要晕了怎么选择,这里简单说下。

发展

这些都要从Java日志框架的元老log4j说起。java1.3之前打日志都是采用System.out.println(), System.err.println()等做法。
此时log4j诞生,定义了Logger、Appender、Level等概念,至今还在使用。可以说是一下子脱离了刀耕火种时代。
毕竟还不是java的标准,因此随着IT发展,开始有多种设计和实现

从上图可以看出,这个过程出了两个统一的接口,并有不同实现

SLF4j和JCL

JCL,Jakarta Commons Logging。

SLF4j和JCL对使用者封装了统一接口,进行解耦。两者定位一样,在不更改代码的基础上,随意切换日志系统。也各自拥有忠实的原生实现logback和log4j2。

SLF4j

SLF4j采用静态绑定机制
1.SLF4j为各个日志输出系统提供了适配库
2.SLF4j会加载org.slf4j.impl.StaticLoggerBinder作为输出日志的实现类(老版本)。新版本通过java SPI实现。自然而然地就能与具体的日志输出实现绑定起来。

JCL

JCL采用动态绑定机制
1.启动时,尝试寻找当前factory中名叫org.apache.commons.logging.Log配置属性的值
2.找不到,则寻找系统中属性中名叫org.apache.commons.logging.Log的值
3.依旧找不到,如果应用程序的classpath中有log4j,则使用相关的包装(wrapper)类(Log4JLogger)
4.还没找到的话,使用相关的包装类(Jdk14Logger)

log4j2与logback

log4j2比较新,比logback晚出来几年。也吸收了logback的有点,也有大量改进。在多线程环境下和使用异步日志时性能比较好
log4j2和logback各有优缺点

桥接与适配

因为理念和实现的差异性,不可避免的存在一些不兼容。另外不同的java库也依赖不同的日志输出服务,也有兼容性问题。因此两个门面在与实现进行组合时就需要一些桥接器和适配器。
完美情况下,应该是

这个是最理想的实现方案,比如:

dependencies {compile "org.slf4j:slf4j-api:1.7.30"compile "ch.qos.logback:logback-classic:1.2.3"compile "ch.qos.logback:logback-core:1.2.3"
}

然而现实是多样的。因为理念、设计思想、实现思路等各不相同。一定会出现兼容性问题。

适配器

系统jar包之间肯定存在统一接口与日志输出系统不兼容的

此时就需要在接口和日志输出系统之间,做一层适配。

示例代码

适配到log4j依赖:

repositories {mavenCentral()maven { url "http://maven.aliyun.com/nexus/content/groups/public/" }
}dependencies {compile "org.slf4j:slf4j-api:1.7.30"compile "org.slf4j:slf4j-log4j12:1.7.30" // 自带了 log4jcompile "log4j:log4j:1.2.17"
}
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;public class MyMain {private static Logger logger = LoggerFactory.getLogger(MyMain.class);public static void main(String[] args)  {logger.info("ka---------ka");}
}

log4j.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration PUBLIC "-//log4j/log4j Configuration//EN" "log4j.dtd">
<log4j:configuration><!-- 日志输出到控制台 --><appender name="console" class="org.apache.log4j.ConsoleAppender"><!-- 日志输出格式 --><layout class="org.apache.log4j.PatternLayout"><param name="ConversionPattern" value="[%p][%d{yyyy-MM-dd HH:mm:ss SSS}][%c]-[%m]%n"/></layout></appender><!--1. 指定logger的设置,additivity是否遵循缺省的继承机制2. 当additivity="false"时,root中的配置就失灵了,不遵循缺省的继承机制3. 代码中使用Logger.getLogger("logTest")获得此输出器,且不会使用根输出器--><logger name="com.hust" additivity="false"><level value ="INFO"/><appender-ref ref="console"/></logger><!-- 根logger的设置,若代码中未找到指定的logger,则会根据继承机制,使用根logger--><root><appender-ref ref="console"/></root>
</log4j:configuration>

或者适配到log4j2:

dependencies {compile "org.slf4j:slf4j-api:1.7.30"compile "org.apache.logging.log4j:log4j-slf4j-impl:2.13.1"// 适配到 log4jcompile "org.apache.logging.log4j:log4j-core:2.13.1"compile "org.apache.logging.log4j:log4j-api:2.13.1"
}

此时log4j2.xml 配置反而更简单:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN"><Appenders><Console name="Console" target="SYSTEM_OUT"><PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/></Console></Appenders><Loggers><Root level="INFO"><AppenderRef ref="Console"/></Root></Loggers>
</Configuration>

简单来说就是把slf4j收到的日志请求转向到合适的日志系统中,目前主要有

slf4j-jdk14:slf4j适配到jdk-logging
slf4j-log4j12:slf4j适配到 log4j1
log4j-slf4j-impl:slf4j 适配到 log4j2
logback-classic:slf4j 适配到 logback
slf4j-jcl:slf4j 适配到 commons-logging

桥接器

由于历史遗留的jar包、日志输出实现选择等问题,肯定存在java服务直接使用日志输出系统。
比如当前系统要使用slf4j,但是依赖的某个jar使用了log4j。此时slf4j就收集不到这个jar的日志,怎么办?此时就需要桥接,简单说就是把日志重定向输出

示例,注意这里Log是 common-logging里的类

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;public class MyMain {// commons.logging 的类private static Log logger = LogFactory.getLog(MyMain.class);public static void main(String[] args)  {logger.info("ka---------ka");}
}

改造:

dependencies {compile "commons-logging:commons-logging:1.2"compile "org.slf4j:jcl-over-slf4j:1.7.30"// commons-logging到slf4j的桥梁compile "org.slf4j:slf4j-api:1.7.30" // slf4j 可以直接输出到logbackcompile "ch.qos.logback:logback-classic:1.2.3"compile "ch.qos.logback:logback-core:1.2.3"
}

桥接器自动把已经存在的日志输出系统实现类似屏蔽,对此java服务是无感知的.

同样的现有log4j的也可以无感知的桥接到slf4j,然后转到日志输出系统

import org.apache.log4j.Logger;public class MyMain {// apache 的 log4j 包的类private static Logger logger = Logger.getLogger(MyMain.class);public static void main(String[] args)  {logger.info("ka---------ka");}
}

对应依赖

dependencies {compile "log4j:log4j:1.2.17"compile "org.slf4j:log4j-over-slf4j:1.7.30" // log4j1到slf4j的桥梁compile "org.slf4j:slf4j-api:1.7.30"compile "ch.qos.logback:logback-classic:1.2.3"compile "ch.qos.logback:logback-core:1.2.3"
}

对于jul来说也是一样,稍微不同的是要提前注册一个类。另外日志 两边都输出

import org.slf4j.bridge.SLF4JBridgeHandler;
import java.util.logging.Logger;public class MyMain {static {// 在使用之前,必须提前注册这个处理器,SLF4JBridgeHandler.install();// 该类集成了jdk-logging里面的java.util.logging.Handler,这个是jdk-logging处理日志中的一个处理器}// jdk 自带的 Logger 类private static Logger logger = Logger.getLogger(MyMain.class.getName());public static void main(String[] args)  {logger.info("ka---------ka");}
}

依赖如下:

dependencies {compile "org.slf4j:jul-to-slf4j:1.7.30" // jdk-logging到slf4j的桥梁compile "org.slf4j:slf4j-api:1.7.30"compile "ch.qos.logback:logback-classic:1.2.3"compile "ch.qos.logback:logback-core:1.2.3"
}

Java日志系统概述SLF4J、log4j、JCL、Logback相关推荐

  1. Java日志框架Slf4j+Log4j入门

    一.日志系统介绍 slf4j,即简单日志门面(Simple Logging Facade for Java),不是具体的日志解决方案,它只服务于各种各样的日志系统.简答的讲就是slf4j是一系列的日志 ...

  2. java日志:三、JCL使用

    java日志:三.JCL使用 1 介绍 全称为Jakarta Commons Logging,是Apache提供的一个通用日志API.它是为"所有的Java日志实现",提供一个统一 ...

  3. java日志框架JUL、JCL、Slf4j、Log4j、Log4j2、Logback 一网打尽

    为什么程序需要记录日志 我们不可能实时的24小时对系统进行人工监控,那么如果程序出现异常错误时要如何排查呢?并且系统在运行时做了哪些事情我们又从何得知呢?这个时候日志这个概念就出现了,日志的出现对系统 ...

  4. Java日志框架SLF4J和log4j以及logback的联系和区别

    1.SLF4J(Simple logging Facade for Java) 意思为简单日志门面,它是把不同的日志系统的实现进行了具体的抽象化,只提供了统一的日志使用接口,使用时只需要按照其提供的接 ...

  5. java日志体系(SLF4J,JCL)

    平时我们引用日志包打印日志时发现和我们预料中的不一致,最常见的就是明明配置了但确不打印日志,所以我简单总结了下java的日志体系. 一.我们日前常用的日志有log4j,log4j2,logback,j ...

  6. java sl4j 日志_Java日志框架Slf4j+Log4j入门

    一.日志系统介绍 slf4j,即简单日志门面(Simple Logging Facade for Java),不是具体的日志解决方案,它只服务于各种各样的日志系统.简答的讲就是slf4j是一系列的日志 ...

  7. java ndc_通过slf4j/log4j的MDC/NDC 实现日志追踪

    在分布式系统或者较为复杂的系统中,我们希望可以看到一个客户请求的处理过程所涉及到的所有子系统\模块的处理日志. 由于slf4j/log4j基本是日志记录的标准组件,所以slf4j/log4j成为了我的 ...

  8. Java日志(slf4j+logback)及打印彩色日志

    一.maven依赖 在pom文件增加slf4j+logback依赖 <!-- 版本配置 --> <properties><slf4j.version>1.7.21& ...

  9. Java日志框架 -- SLF4J日志门面(入门案例、SLF4J优点、SLF4J日志绑定、SL4J桥接旧的日志框架)

    1. SLF4J日志门面 JCL日志门面逐渐被淘汰了,因为他无法动态的扩展具体的日志实现框架. 简单日志门面(Simple Logging Facade For Java) SLF4J主要是为了给Ja ...

最新文章

  1. JavaScript 日期联动选择器
  2. mysql 获取姓名首字母_MySQL取姓名的首字母
  3. Qt学习之路(28): 坐标变换
  4. 【英语学习】【Level 07】U07 Stories of my Life L6 An experience worth remembering
  5. Java设计模式学习总结(9)——结构型模式之过滤器模式(标准模式)
  6. ActionSheet的用法
  7. windows2008安装DNS服务器
  8. 【转】解决Navicat 报错:1130-host ... is not allowed to connect to this MySql server,MySQL不允许从远程访问的方法 .
  9. 【csdn积分】获得方式大全
  10. 企业微信api消息接口调用
  11. C# DLL HRESULT:0x8007000B
  12. 如何锻炼深入思考能力
  13. 使用 natbib 进行参考文献管理
  14. IOT-OS之RT-Thread(六)--- 线程间同步与线程间通信
  15. MySQL之INTERVAL()函数用法
  16. 【Ubuntu】远程软件安装与卸载
  17. 港美股系统开发软件开发之证券交易软件供应商对比
  18. 【题解】通往奥格瑞玛的道路
  19. linux 音频播放器源码,Android音乐播放器源码
  20. Linux free -m 详解命令

热门文章

  1. 五金连续冲模之冲裁,折弯成形常见不良及其改善措施
  2. ready for 4g 以后蓝屏
  3. 【数据手册】CH340G芯片使用介绍
  4. 关于天翼3G网卡DATA interface驱动无法加载的问题
  5. 国外steam搬砖是骗人的吗?csgo游戏装备项目到底咋样?
  6. 2022考研数学李永乐复习全书pdf版-基础篇(数一二三通用)
  7. Python3 爬取 NBA 2013-2014 赛季比赛数据
  8. 小八手残党摇杆主板-拳皇97-安装接线教程
  9. 【分享】批量下载百度/谷歌搜索的图片结果工具
  10. 通用产品演示系统,适合快速演示功能和开发