Java日志系统历史从入门到崩溃[转]

转载: https://segmentfault.com/a/1190000021121882

前言

最早开始撸码当时就遇到几次日志jar包冲突的问题,当时也是很烦躁,毕竟了解的也不多,什么那里4j,这里4j,还有什么桥接包,而且在我感觉他们的包名都还差不多!!我当时是比较懵逼的,上网搜了下,随便看到一个类似这种桥接过去桥接过来的图我就懵,都是些啥玩意儿

1.png

最近项目中突然发现我们自己的工程对于日志的记录也不是很好,很多各种日志的注解大家用的也不一样,有@Log4j,也有@Slf4j的,也有@Log4j2的,索性干脆彻底去了解一下日志系统

由于个人一直觉得现在学习技术是很好的年代,毕竟我们在前人已经踩过的坑,总结过的经验之上来学习,相当于站在了巨人的肩膀上,但同时也是最坏的时代,我们对于新技术可能还是很了解,但是这些新技术到底为什么出现,它们到底解决了什么问题,时代选择了这些技术一定是有原因的,我们不清楚技术发展的历史,就像国外不清楚我们中华民族的历史,所以会曲解我们一样

言归正传,虽然看着日志系统很乱,很难梳理清楚,可能名字都不是很好记,但我们要是从日志系统本身的发展历史去了解一次,可能就会更加明白为什么会出现现在这种情况了

发展历史

System.out和System.err

这应该是最早的日志记录方式吧,但是不灵活也不可配置,要么就是全部打印,要么就是全部不打印,没有一个统一的日志级别

Log4j

在1996年初,E.U.SEMPER(欧洲安全电子市场)项目决定编写自己的跟踪API,最后该API演变为Log4jLog4j日志软件包一经推出就备受欢迎,当然这里必须要提到一个人,就是Log4j的主要贡献者,这个大佬:

Ceki Gülcü

可能应该叫巨佬了。。。后面你就明白了,后来Log4j成为了Apache基金会项目中的一员,同时Log4j的火爆,让Log4j一度成为业内日志标杆。(据说Apache基金会还曾经建议Sun引入Log4jjava的标准库中,但是sun拒绝了)

JUL(Java Util Logging)

果然Sun有自己的考虑,2002年2月Java1.4发布,Sun竟然推出了自己的日志库Java Util Logging,其实很多日志的实现思想也都是仿照Log4j,毕竟Log4j先出来很多年了,已经很成熟了此时,这两个日志工具打架,显然Log4j是更胜一筹

它们打架感觉就是互相竞争,Sun心里可能在想,不就是做个日志工具嘛,谁不会!当然好景不长

JCL(Jakarta Commons Logging)

Apache: 玩编程,谁玩的过我!你不让我成为JDK标准,我就自己成为日志标准,哼!(完全个人意淫。。。)
于是JUL刚出来不久,2002年8月Apache又推出了日志接口Jakarta Commons Logging,也就是日志抽象层,当然也提供了一个默认实现Simple Log,这野心很大,想一统日志抽象(就像以前的JDBC一统数据库访问层),让日志产品去实现它的抽象,这样只要你的日志代码依赖的是JCL的接口,你就可以很方便的在Log4jJUL之间做切换,当时日志领域大概是这样的结构,当然也还是方便理解的,也很优雅

2.png

但是好景不长,在使用过程中,虽然现在日志系统在JCL的统一下很优雅,很美好,但大家发现了JCL还不够好,有些人甚至认为JCL造成的问题比解决的问题还多...emmm【抱怨地址】

Slf4j(Simple Logging Facade for Java)

所以大佬粗线,Ceki Gülcü(也就是Log4j的作者)由于一些原因离开了Apache,之后觉得JCL不好,于是于2005年自己撸出一个新工程,也就是一套新日志接口(有得也叫日志门面):Slf4j(Simple Logging Facade for Java),感觉粗来了么。。。这战争的硝烟,明显这个Slf4j是直指JCL啊,但是后面确实也证明了Slf4j是要比JCL在很多地方更优秀

Ceki Gülcü:玩接口,我一个人就是一支军队!

但是由于Slf4j出来的较晚,而且还只是一个日志接口,所以之前已经出现的日志产品,如JULLog4j都是没有实现这个接口的,所以尴尬的是光有一个接口,没有实现的产品也是很憋屈啊,就算开发者想用Slf4j也是用不了,这时候,大佬发话了
Ceki Gülcü:别急,我早帮你们想好了,要让Sun或者Apache这两个庞然大物来实现我的接口,太南啦,老铁,但。。。我帮你们实现,不就完了么。。。

于是大佬Ceki Gülcü撸出了之前提到的桥接包,也就是这种类似适配器模式

1.png

好了,大佬提供了桥接包,于是日志系统现在有了这样的结构


image.png

但是其实之前很多Java应用应该依赖的JCL,所以光有日志产品桥接包,好像还不够
Ceki Gülcü:没问题,不就是不够桥接包么,我写,我来证明Slf4j是最完美的
于是有了JCL的桥接包

image.png

相当于此时的桥接包就是分了两种场景

  1. 之前Java应用用的日志接口(如JCL
  2. 之前Java应用用的日志产品(如Log4j

那好,那我们如果再考虑一下这种场景呢?
假设哈,你的Java应用使用了Spring的第三方的框架,但是假设Spring默认用JCL,并且最终用的JUL打印的日志,但是你的系统使用了Slf4j作为日志接口,日志产品使用了Log4j,那。。。不出意外的话。。。你将有两种日志输出,两种日志的打印方式不统一,到时候解决bug的时候就很恼火,而且配置日志的配置文件还需要两份。

image.png

所以为了方便统一应用中的所有日志,大佬发话了
Ceki Gülcü:没事,大家都选择用Slf4j统一吧,我来帮大家统一,没有事是桥接包解决不了的,有的话,那就再来个

image.png

当然此时这种场景也是符合之前说的两种情况的,因此现在日志系统大体应该是这样的


image.png

总结一句话就是:大佬撸完。。。

但好景又不长,大佬毕竟是大佬,Log4j不就是自己写的么,所以最清楚Log4j缺点的人也正是他

Logback

由于使用Slf4j,需要一次桥接包,也就是之前的日志产品都不是正统的Slf4j的实现,因此,2006年,出自Ceki Gülcü之手的日志产品Logback应运而生,而且大佬还专门写了一篇文章
[图片上传失败...(image-589d8b-1598862941079)]

是不是这太针对了。。。哈哈哈哈,就是这么无情,当然都是他写的,他肯定是最清楚这两者实现的区别

肯定的,Logback是完美实现了Slf4j,于是现在日志系统变成了

image.png

ok了,现在咱们有了2个日志接口,3个日志产品,大家也都看起来相安无事。。。但。。。Slf4j+Logback的模式,显然很冲击JCL+Log4j,并且本身Logback确实比Log4j性能更优,设计更为合理,所以。。。老东家Apache可就坐不住了

Log4j2

在2012年,Apache直接推出新项目,不是Log4j1.x升级,而是新项目Log4j2,因为Log4j2是完全不兼容Log4j1.x

并且很微妙的,Log4j2几乎涵盖Logback所有的特性(这不是对着干是啥~而且还有抄袭的嫌疑。。。哈哈哈),更甚者的Log4j2也搞了分离的设计,分化成log4j-apilog4j-core,这个log4j-api也是日志接口,log4j-core才是日志产品。。。

emmm,我看到这,我都有点崩溃了

现在我们可有了3个日志接口,以及4个日志产品。。。当然Apache也知道该做啥,为了让大家可以接入自己的Log4j2,那不就是桥嘛,不就是桥嘛,Apache也麻溜的推出了它的桥接包,所以。。。
唉,所以我都不敢画图了。。。

前方高能!!!

前方高能!!!

前方高能!!!

image.png

总结到这,我们可以吸取什么经验么?

  1. 不写接口的坏处
  2. 没有什么问题是加一个层适配器(接口)解决不了的,如果有,那就再加一层

最佳实践

了解了日志的发展历史,那现在我们再回过头来看看如果,你的系统在选择日志方案的时候,如何抉择呢?毕竟我们3个日志接口,以及4个日志产品

  • 显然第一点是使用日志接口的API而不是直接使用日志产品的API

这一条也是必须的,也是符合依赖倒置原则的,我们应该依赖日志的抽象,而不是日志的实现

  • 日志产品的依赖只添加一个

当然也这个也是必须的,依赖多个日志产品,只会让自己的应用处理日志显得更复杂,不可统一控制

  • 把日志产品的依赖设置为Optionalruntime scope

其中Optional是为了依赖不会被传递,比如别的人引用你这个jar,就会被迫使用不想用的日志依赖

    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-core</artifactId>
        <version>${log4j.version}</version>
        <optional>true</optional>
    </dependency>

scope设置为runtime,是可以保证日志的产品的依赖只有在运行时需要,编译时不需要,这样,开发人员就不会在编写代码的过程中使用到日志产品的API

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