Java日志框架

最近,新开发的一个项目遇到了一个log4j的配置问题,之前一直没怎么关注过日志框架,借助这个机会,好好了解下Java的日志框架,便于以后更好的使用。

本文重点介绍了:Java日志框架生态、Java日志框架的结构组成、Slf4j替代Commons Logging。

Java常用的日志框架如下:

  1. Commons Logging:Apache基金会所属的项目,是一套Java日志接口;
  2. Slf4j:是一套简易Java日志门面,本身并无日志的实现。(Simple Logging Facade for Java,缩写Slf4j);
  3. log4j:Apache Log4j是一个基于Java的日志记录工具;
  4. log4j 2:Apache Log4j 2是apache开发的一款Log4j的升级产品,不兼容log4j 1;
  5. Logback:一套日志组件的实现(slf4j阵营);
  6. Jul:Java Util Logging,自Java1.4以来的官方日志实现。

现今,Java日志领域被划分为两大阵营:Commons Logging阵营和SLF4J阵营。

各日志框架之间的关系:

  1. Commons Logging和Slf4j是两个日志门面框架,系统不和日志实现耦合,日志门面作为接待员,方便日志实现的替换(如:log4j2替换log4j1);
  2. Commons Logging和log4j1、2配合使用,Slf4j和Logback组合使用;
  3. 新项目建议使用Slf4j与Logback组合;

桥接原理分析

桥接器原本语境是使用在网络中数据包的转发,在日志框架里,主要是日志门面寻找日志实现类的类。


log.png

Slf4j在获取日志框架实现时扫描class path,寻找org.slf4j.impl.StaticLoggerBinder(有多个,会打印警告日志,并选择遇到的第一个),桥接器就是提供桥接来实现类和接口类之间的适配。

对于Commons Logging,其寻找Logger实现的步骤如下:

  1. 首先,寻找org.apache.commons.logging.LogFactory 属性配置
  2. 否则,利用JDK1.3 开始提供的service 发现机制,会扫描classpah 下的META-INF/services/org.apache.commons.logging.LogFactory 文件,若找到则装载里面的配置,使用里面的配置。
  3. 否则,从Classpath 里寻找commons-logging.properties ,找到则根据里面的配置加载。
  4. 否则,使用默认的配置:如果能找到Log4j 则默认使用log4j 实现,如果没有则使用JDK14Logger 实现,再没有则使用commons-logging 内部提供的SimpleLog 实现。

Slf4j和Commons Logging获取Logger的区别
Slf4j扫描classpath获取StaticLoggerBinder,通过StaticLoggerBinder的静态绑定逻辑获取Logger。
Commons Logging是采用ClassLoader动态的获取Logger,在一些情况下会产生ClassLoader的问题(如OSGI,主要原因在文末Ceki Gülcü的一片参考文献有提及)

Slf4j&Logback的优势

  1. Slf4j的静态绑定实现机制决定了其更加通用;
  2. Logback拥有更好的性能;
    Logback声称:某些关键操作,比如判定是否记录一条日志语句的操作,其性能得到了显著的提高。这个操作在Logback中需要3纳秒,而在Log4J中则需要30纳秒。LogBack创建记录器(logger)的速度也更快:13毫秒,而在Log4J中需要23毫秒。更重要的是,它获取已存在的记录器只需94纳秒,而Log4J需要2234纳秒,时间减少到了1/23。跟JUL相比的性能提高也是显著的。
  3. 自动重新加载配置文件,当配置文件修改了,Logback-classic能自动重新加载配置文件
    ...

LogBack结构

Java日志框架由3部分组成,分别是Logger,Formatter,Appender。
Logger:用来接收用户输入的内容;
Formatter:用来格式化日志内容;
Appender:将日志内容输出到Console,socket,文件,数据库,邮件等。
在Logback中,则分别对应于Logger、Layout、Appender。

  1. Logger
    Logger有三点需要重点关注:名字属性、Level属性,如何获取。
    (1)每个Logger都有一个名字,并且有父子、子孙层次关系;
    存在一个特殊的Logger实例,它的名字为“org.slf4j.Logger.ROOT_LOGGER_NAME”,即“ROOT”

    (2)Logger实例应该设置Level属性,如果某个Logger实例的Level属性未设置,那么沿着Logger实例的层次关系向上回溯直到最顶层的"ROOT"Logger实例为止。
    (3)在Logback运行的时候,LoggerContext类实例会维护一个类型为Map<String, Logger>的map对象loggerCache,它的key为Logger实例的名字,它的value为对应的Logger实例。
    当我们执行"LoggerFactory.getLogger('xxx')"语句,来检索名字为"xxx"的Logger实例时,LoggerContext类实例会先去查看loggerCache对象,看是否已经存在名字为"xxx"的Logger实例,如果存在,直接返回;否则,先创建好Logger实例(注意这里创建Logger实例的时候,会把loggerCache中不存在的祖先和父亲Logger实例都创建好)并放入loggerCache中,最后返回刚创建好的Logger实例。
    即在Logback运行的时候,相同名字的Logger实例只保存一份。

  2. Layout
    绑定在Appender上,用来格式化Appender的输出

  3. Appender
    Appender代表日志输出目的地,可以是Console, File, Sockets, DataBase等等。
    一个Logger实例上可以绑定0到多个Appender实例,当在该Logger实例上产生的日志记录请求是有效的情况下,日志记录请求会被发送到所有绑定在该Logger实例上的Appender实例。
    一个Logger实例上绑定的Appender实例不仅来自自身的绑定,也来自祖先和父亲Logger实例的Appender绑定,即可以继承祖先和父亲Logger实例绑定的Appender实例。

Slf4j替代Commons Logging

Java生态有许多日志工具,不同的组件可能会使用不同的日志框架,为了不对日志框架产生依赖,Apache引入了Commons Logging门面框架,不过当程序规模越来越庞大时,JCL的动态绑定并不是总能成功。Slf4j的静态绑定功能解决了这一问题,然而,依赖的组件中可能会有使用了Commons Logging的组件,Slf4j提供了jcl-over-slf4j.jar ,可以借助jcl-over-slf4j.jar 讲Commons Logging输出的日志引入到Slf4j中。
Component(服务)
| |
log to Apache Commons Logging(JCL)
V
jcl-over-slf4j.jar — (redirect) —> SLF4j —> slf4j-log4j12-version.jar —> log4j.jar —> 输出日志
(另外也可以删除所有Commons Logging的依赖,不过这太繁琐了,也容易出问题)。

参考文献:
https://www.cnblogs.com/chenhongliang/p/5312517.html(各日志框架介绍)
https://www.cnblogs.com/crazyrunning/p/6145890.html(日志门面的作用)
http://www.runoob.com/design-pattern/facade-pattern.html(门面模式)
https://blog.csdn.net/jpf254/article/details/80757041(Slf4j桥接原理)
http://singleant.iteye.com/blog/934593(commons-logging Logger实现加载步骤)
https://blog.csdn.net/dslztx/article/details/47450741(Logback详解)
https://articles.qos.ch/classloader.html(Ceki Gülcü控诉了Commons Logging的弊端😂)
https://blog.csdn.net/zbajie001/article/details/79596109(Logback的优点)
https://blog.csdn.net/javaloveiphone/article/details/52486257(Slf4j替代Commons Logging)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容

  • 按照基本的定义,日志即是对程序运行过程中关键事件的记录;大体日志分为运行日志和开发日志,运行日志在业务层面记录一些...
    clannad月阅读 464评论 0 0
  • [TOC] Java 日志框架解析:设计模式、性能 在平常的系统开发中,日志起到了重要的作用,日志写得好对于线上问...
    albon阅读 3,940评论 1 8
  • 作为Java开发人员,对于日志记录框架一定非常熟悉。而且几乎在所有应用里面,一定会用到各种各样的日志框架用来记录程...
    意识流丶阅读 13,647评论 0 13
  • 在项目开发过程中,我们可以通过 debug 查找问题。而在线上环境我们查找问题只能通过打印日志的方式查找问题。因此...
    Java架构阅读 3,407评论 2 41
  • 对于Java的日志框架,你也许会经常看到这些名词: Log4j、Log4j2 Logback Slf4j JCL ...
    NoahU阅读 3,881评论 0 15