日志SLF4J解惑

0x00 前言

作为后端开发,日志可能是我们最常用的功能之一了。平时大家也可能经常遇见日志冲突,常见的overflow报错,今天为大家详解一下,这其中的原理以及问题所在。本文涉及 jar 包有:log4j,log4j-over-slf4j,slf4j-api,slf4j-log4j12 等等。

0x01 背景

不知道大家在平时开发中,是否经常遇见以下几个问题:

  • log4j,logback等等日志包冲突,然后再慢慢排除,不胜其烦。
  • 使用了 slf4j ,但是又遇到 StackOverflwError 错误。
    image
  • 好不容易解决了StackOverflwError,可能又遇到了类似如图所示的错误:
    image
  • ......

0x02 概述

什么是 SLF4J 呢?简而言之,他就是一个日志的门面,市场上的日志系统非常多, SLF4J 想做的一件事情,就是将这多种的日志系统包装起来,提供统一的 API 供调用,从而解决日志的列国争霸的情况。

0x03 SLF4J 调用流程

在解决以上问题之前,让我们先对日志系统做一个大概的理解。到底什么是 log4j,什么是 slf4j-api,为什么有一个 slf4j-log4j12,又怎么有个log4j-over-slf4j,看上去头晕眼花,绕来绕去。先祭上一张官网图:
image

相信大家都见过这张图,但是未必全都理解图上说的是什么意思。所以呢,我们先不讲图,先看看最上面的一排文字,SLF4J bound to xxxx,xxxx总共涉及:

  1. null
  2. logback-classic
  3. log4j
  4. java.util.logging
  5. simple
  6. no-operation

第1个顾名思义,不绑定,就是没有日志实现。第5,6可以看出来,是 SLF4J 自己的实现,这里就忽略不讲。所以着重讲一下2、3、4。他们有个共同的特点,就是他们都是日志的真正实现库,他们和SLF4J没有关系,你可以使用 logback 打印日志,也可以使用 log4j 打日志。

第一层, application 就是应用层。

看看图中第二层,统统都是 SLF4J API。那么这一层是干什么用的呢?这一层就是一个门面层,而和门面层息息相关的 jar 包是什么呢?对,就是图中的 slf4j-api.jar 。这个jar包中,提供了日志调用的所有接口,应用都是直接调用这个 jar 包中的接口进行日志调用。

第三层有点不同。第一列,无实现,第2,5,6都是原生的一个实现,而3,4都有一个适配层。这里说说 logback。logback 他为什么不需要适配层呢,因为他就是按照了 SLF4J 接口去实现的一个日志库,相当于亲儿子,自然不需要适配层。所以,logback-classic.jar 和 logback-core.jar 就是 logback 的底层实现。而3,4就不同了,他们的接口或多或少会有差异,调用方式也各不相同,所以,需要一个适配层。所以 slf4j-log412.jar 和 slf4j-jdk14.jar 包的作用就是一个适配,这里是一个桥接,应用通过 slf4j-api 的接口调用过来时,桥接类实际会调用其底层的实现,达到一个桥接的过程。所以,slf4j-log412.jar,slf4j-jdk14.jar,slf4j-simple.jar,slf4j-nop.jar 是同一类,就是把-右边的实现进行一个桥接。

第四层,可以看到第2,3对应的实现,log4j.jar 和 jvm 就是最后的实现。

至此,做一个小总结:

  1. slf4j-api.jar 是上层的门面,里面提供接口供调用。
  2. logback-classic.jar, logback-core.jar, log4j.jar, 是同一类别,属于底层实现库。
  3. slf4j-log412.jar,slf4j-jdk14.jar,slf4j-simple.jar,slf4j-nop.jar,可以看成 slf4j-xxxx.jar,属于同一个类别,就是对 - 后面的库做一个桥接,更简单的理解,从左到右读:把 - 左边的调用用右边的库实现。

此时再看看上面那张图,是否已经全部理解了呢?

0x04 SLF4J 转换流程

如果看完上面,不觉得 SLF4J 有什么好处,就来看看下面这张图:
image

那这张图又是什么意思呢?这就要说到 SLF4J 的一个强大之处了。设想一下以下一种情况:新建了一个工程,引入的第一个库使用的是 java.util.logging 日志库,引入的第二个库使用的是 log4j 日志库,而你自己的工程,老板规定,必须要用 logback 。你怎么办呢?这个时候, SLF4J 就出场了。他能帮你把所有日志归拢到你所指定的一种日志实现。就是说,他可以把 jul 日志实现转成 logback,还能把 log4j 实现转成 logback。那他是怎么做的呢?回过头来看图吧。

着重讲解左上角这一部分,其他的类似。

先看 application,这个是应用,可以看到,他也遇到了我说到的问题。他的依赖里面有使用 log4j 的,有用 commons logging 的,有用 java.util.logging 的。所以此时需要做一个替换,分别是通过 jcl-over-slf4j.jar 替换掉 commons-logging.jar,log4j-over-slf4j.jar 替换掉 log4j.jar, jul-to-slf4j.jar 包中安装 SLF4JBrindgeHandler 解决。替换掉之后,就把所有日志调用转接到 slf4j-api 上了,然后 api 接口再调用底层实现,图上是 logback。文中说的替换是什么意思呢?就是把原日志实现库排除掉,引入 xxx-over-slf4j.jar 。

那么,xxx-over-slf4j.jar 是什么原理呢?先给大家看这张图:


image

左边是 log4j.jar 的包结构,右边是 log4j-over-slf4j.jar 的包结构。发现猫腻了吗?他们的目录结构一模一样!所以用 log4j-over-slf4j 可以替换掉 log4j!且编译不会出错。log4j-over-slf4j.jar 实现了基本上所有 log4j 会被调用的 api 接口。所以替换之后,不会报错,编译也能通过,而底层实现却全转到 slf4j 这里去了。这里就是一个狸猫换太子的把戏。

再看其他两个图,底层分别是 log4j, jvm 实现。都是讲其他库 over 一下到 slf4j 。

特别注意一下, logback 不需要转,为什么?因为他是亲儿子。天生就带这些。

所以再小总结一下:

  • jcl-over-slf4j.jar, log4j-over-slf4j.jar, jul-to-slf4j.jar,这种形式类似 xxx-over-slf4j.jar 的,就是将 - 前的太子用 slf4j 的狸猫代替。而 xxx-to-slf4j.jar 比较特殊,这是因为 xxx 这个包无法被替换掉,比如 java.util.logging,系统的库,无法替换,所以只能采用别的手段。此类别的实现读者有兴趣可以去看看,本文不再分析。

0x05 常见问题解决

StackOverflow 错误

为什么会出现这个问题呢?控制台输出上一般会比较清楚,就是你既使用了桥接库,又使用了over库(狸猫)。比如:
image

试想一下:你先用 over 库把 log4j 转成了 slfj4 调用。紧接着,你又把 slf4j 适配到 log4j 上。这就构成了一个死循环,肯定是会出现堆栈溢出的问题。所以,一个工程里面,只能保留一个日志实现库,还有配套的桥接库,加上其他日志的 over 库,才是正确之道。

异常参数错误

上面提到的这个错误:


image

大致可以看出来吧,他缺少一个真正的实现。看你选择使用什么,就把什么库补充上去。加上 logback,去掉 slf4j-log4j 或者加上 log4j 都可以解决这个问题。

其他问题都比较类似,如果看懂了上文的介绍,应该可以着手解决此类问题了。

0x06 不算总结的总结

了解了日志的原理,以后妈妈再也不担心日志冲突了!

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

推荐阅读更多精彩内容