技术控

    今日:48| 主题:49369
收藏本版 (1)
最新软件应用技术尽在掌握

[其他] 【Java深入学习系列】三. 那些年我们用过的日志框架

[复制链接]
亡雨是深海的疤 发表于 2016-10-16 16:18:32
109 6

立即注册CoLaBug.com会员,免费获得投稿人的专业资料,享用更多功能,玩转个人品牌!

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
目前常见的Java日志框架和facades(中文似乎不太好翻译)有一下几种:
  
       
  • ① log4j   
  • ② logback   
  • ③ SLF4J   
  • ④ commons-logging   
  • ⑤ j.u.l (即java.util.logging)  
  其中,①-③为同一个作者(Ceki)所写。④被很多开源项目所用,⑤是Java原生库(以下用j.u.l简写来代替),但是在Java 1.4中才被引入。
   这么多得日志库,我们该如何选择呢,我认为,这并非一道非此即彼的选择题,但是在了解它们的 历史渊源优劣 以及 相互关系 的基础上才能更好地适配自己的项目。
  下面我将上述这些框架串起来讲一下,如有疏漏请见谅。
  1. Logging frameworks的上古时期(Java 1.3及以前)

   在上古时期,Java打日志依赖 System.out.println() , System.err.println() 或者 e.printStackTrace() 。Debug日志被写入 STDOUT 流,错误日志被写入 STDERR 流。
   这种方式目前小脚本中也依然使用广泛。但是在生产环境或大的项目中,Debug日志通常被重定向到/dev/null中: >/dev/null , 错误日志被重定向到本地文件中: 2>stderr.log 。看起来很完美,是吗?实则不然,这样打日志有一个非常大的缺陷: 无法可定制化
   具体来讲,没有一个类似开关的东东来切换是否打印Debug日志,当我们定位问题时需要输出Debug日志到文件去查看,而不是到 /dev/null 里,是吗?日志无法定制化,我们只能硬编码到代码里,不需要时再注释掉相关代码,重新编译。
   还有一些缺陷,比如: 无法更细粒度地输出日志 ,换句话说,缺少当前成熟的日志框架常见的LOG LEVEL控制。
  而Java本身也没有提供相应的Library,在这样恶劣的境况下,Log4j勇敢地站了出来,拯救劳苦大众。
  Log4j可以说是一个里程碑式的框架,它提出的一些基本理念,深深地影响了后来者,直至今天,这些理念也依然在被广泛使用:
  
       
  • Logger
      我们来看下维基百科对 Logger 的定义:
      
  A Logger is an object that allows the application to log without regard to where the output is sent/stored. The application logs a message by passing an object or an object and an exception with an optional severity level to the logger object under a given a name/identifier.
  Logger是一个允许应用记录日志的对象,开发者不必需考虑输出位置。应用可将具体需要打印的信息通过一个Object传递。每个Logger互相独立,通过名字或标识符来区分。
  
       
  • Appender  
  每个appender可独立配置记录日志的设备,可以是文件、数据库、消息系统等。
  
       
  • Level  
  每个打印日志都可以单独制定日志级别。外部通过配置文件来控制输出级别,不同的输出级别打印不同的日志信息。
   2. J.U.L 姗姗来迟

   后来,Sun公司开始意识到JDK需要一个记录日志的特性。受Log4j的启发,Sun在Java1.4版本中引入了一个新的API, 叫 java.util.logging , 但是, j.u.l 功能远不如Log4j完善,如果开发者要使用它,就意味着需要自己写 Appenders (Sun称它为 Handlers ),而且,只有两个 Handlers 可被使用: Console 和 File ,这就意味着,开发者只能将日志写入Console和文件。
   如前面所述, j.u.l 在Java 1.4才被引入,在这之前,并没有官方的日志库供开发者使用。于是便有了很多日志相关的”轮子”。我想这应该是当前会有如此多日志框架的一个很重要的原因。
   回顾历史,一方面,在Java 1.4之前,第三方日志库已经被广泛使用了,占得了先机。另一方面, j.u.l 在被引入时性能和可用性都很差,直到1.5甚至以后才有了显著提升。
  3-1. Logging facades出现及进化

   由于项目的日志打印必然依赖以上两个框架中至少一个,无论是 j.u.l 还是 log4j ,开发者必须去两个都配置。这时候,Apache的 commons-logging 出现了。本质上来讲, commons-logging 并非一个日志打印框架,而是一个 API bridge , 它起到一个连接和沟通的作用,开发者可以使用它来兼容logging frameworks( j.u.l 和 log4j )。有了它,第三方库就可以使用 commons-logging 来做一个中间层,去灵活选择 j.u.l 或者 log4j ,而不必强加依赖。
   然而 commons-logging 对 j.u.l 和 log4j 的配置问题兼容得并不好,更糟糕的是,使用 commons-logging 可能会遇到类加载问题,导致 NoClassDefFoundError 的错误出现。
   最终, log4j 的创始人 Ceki 发起了另一个项目,这便是大名鼎鼎的 SLF4j 日志框架,该框架可以看成是 log4j 的升级版。需要说明的是,log4j 2.0已经被加入Apache基金会,过去几年已经被大幅改善,社区活跃度也非常高,借助开源社区的力量,log4j 2.0目前被加入越来越多得现代化特性,一定程度上,甚至超越了 log4j 的升级版 logback (稍后介绍),关于log4j 2.0的新特性,请参见这篇文章: THE NEW LOG4J 2.0
   据 slf4j 的作者 Ceki 说,首先,slf4j是不仅仅是一个 logging framework , 而且一个 logging facdes , 借助 slf4j 的 log4j adapter , 开发者从 slf4j 切换到 log4j 不需要额外改动一行代码,只需要从CLASS_PATH中排除掉 slf4j-log4j12.jar 。如果想从 log4j 迁移到 logback , 在CLASS_PATH添加 slf4j-log4j12.jar , 并将 log4j.properties 转换为 logback.xml 即可,这里有一个在线工具可以自动完成转换: logback.xml translator 。
   slf4j提供了很大的灵活度,开发者可以借助它去灵活选择底层的日志框架。比如,当下更多的开发者比较倾向于使用log4j的升级版logback,因为它具有较log4j更多更好的特性:
  
       
  • 配置文件支持 xmlGroovy 语法(版本号>= 0.9.22)   
  • 自动重载有变更的配置文件   
  • 自动压缩历史日志   
  • 打印异常信息时自动包含package名称级版本号   
  • Filters   
  • 其它一些很棒的特性  
   需要说明的是,logback是slf4j接口的一套具体实现,又是同一个作者,因而保证了其和log4j相近的使用方式,也具有 slf4j 的全部特性。
   此外,对于一些大型框架及服务的开发者,需要考虑客户端用户的体验。比如jstorm, 你不能只考虑自己的喜好,或许有人偏好使用 slf4j 开发jstorm topology, 而另一些人喜欢用logback。这种情况下,你应该使用 slf4j ,把最终logging framework的选择权留给用户。
   最后,除了 slf4j 比 j.u.l 或者 log4j 更好用,还有一个选择 slf4j 的现实原因:Java圈的非常多开发者更钟情于 slf4j 作为他们的logging API, 随大流有时候能少很多不必要的麻烦。
  3-2. 日志参数化打印的支持(parameterized logging)

   slf4j除了包含该log4j的全部特性外,还提供了 parameterized logging 特性。这个特性非常有用,它允许开发者在打印日志时借助 {} 来实现参数化打印:
  [code]logger.debug("The attribute value is {}", fooIns.getAttribute());
[/code]   logback复用了 slf4j 的API,这意味着使用logback实际上是在使用slf4j的API,不难看出,logback同样支持 parameterized logging 特性。
  4. 各日志框架时间线

  以上日志框架,有些是为了解决现有框架的不足,有些是功能的扩展升级,有些是从头到尾重新写的,根据各自出现先后次序,可以将它们放在同一时间线上:
   
【Java深入学习系列】三. 那些年我们用过的日志框架-1 (选择题,null,中文,Java,定向)

   注意箭头仅代表时间走向,分支不具有 fork 的含义。
友荐云推荐




上一篇:怎么保证服务可靠性、数据一致性、以及一旦宕机数据恢复
下一篇:Continue Network Fetching Even When App Goes to Background
酷辣虫提示酷辣虫禁止发表任何与中华人民共和国法律有抵触的内容!所有内容由用户发布,并不代表酷辣虫的观点,酷辣虫无法对用户发布内容真实性提供任何的保证,请自行验证并承担风险与后果。如您有版权、违规等问题,请通过"联系我们"或"违规举报"告知我们处理。

刘丽 发表于 2016-10-16 19:41:16
珍爱生命,果断回帖。
回复 支持 反对

使用道具 举报

yelonggongzi 发表于 2016-10-16 22:18:24
最近病院在打折!?
回复 支持 反对

使用道具 举报

fkquf 发表于 2016-10-21 06:21:00
亡雨是深海的疤不整容也像雷锋!
回复 支持 反对

使用道具 举报

冯粒 发表于 2016-10-22 02:49:12
路过的帮顶
回复 支持 反对

使用道具 举报

wwwww22 发表于 2016-10-22 05:04:34
在街上看美女,高一点就是欣赏;低一点就是流氓。
回复 支持 反对

使用道具 举报

圝◣帝潮◢圝 发表于 2016-11-20 13:58:42
绘一场生死契阔的游戏,为我们的故事写一个结局。
回复 支持 反对

使用道具 举报

*滑动验证:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

我要投稿

推荐阅读

扫码访问 @iTTTTT瑞翔 的微博
回页顶回复上一篇下一篇回列表手机版
手机版/CoLaBug.com ( 粤ICP备05003221号 | 文网文[2010]257号 )|网站地图 酷辣虫

© 2001-2016 Comsenz Inc. Design: Dean. DiscuzFans.

返回顶部 返回列表