Java 日志 API

从功能上来说,日志 API 本身所需求的功能非常简单,只需要能够记录一段文本即可。API 的使用者在需要进行记录时,根据当前的上下文信息构造出相应的文本信息,调用 API 完成记录。一般来说,日志 API 由下面几个部分组成:

  • 记录器(Logger):日志 API 的使用者通过记录器来发出日志记录请求,并提供日志的内容。在记录日志时,需要指定日志的严重性级别。当 程序中需要记录日志时,首先需要获取一个日志记录器对象。一般的日志记录 API 都提供相应的工厂方法来创建记录器对象。每个记录器对象都是有名称的。一般的做法是使用当前的 Java 类的名称或所在包的名称作为记录器对象的名称。
  • 格式化器(Formatter):对记录器所记录的文本进行格式化,并添加额外的元数据。实际记录的日志中除了使用记录器对象时提供的消息之外,还包括一些元数据。这些元数据由日志记录框架来提供。常用的信息包括记录器的名称、时间戳、线程名等。格式化器用来确定所有这些信息在日志记录中的展示方式。不同的日志记录实现提供各自默认的格式化方式和自定义支持。
  • 处理器(Handler):把经过格式化之后的日志记录输出到不同的地方。常见的日志输出目标包括控制台、文件和数据库等。

Java 日志封装 API

封装库中一开始以 Apache Commons Logging 框架最为流行,现在比较流行的是 SLF4J。这样封装库的 API 都比较简单,只是在日志记录库的 API 基础上做了一层简单的封装,屏蔽不同实现之间的区别。由于日志记录实现所提供的 API 大致上比较相似,封装库的作用更多的是达到语法上的一致性。

在 Apache Commons Logging 库中,核心的 API 是 org.apache.commons.logging.LogFactory 类和 org.apache.commons.logging.Log 接口。LogFactory 类提供了工厂方法用来创建 Log 接口的实现对象。比如 LogFactory.getLog 可以根据 Java 类或名称来创建 Log 接口的实现对象。Log 接口中为 6 个不同的严重性级别分别定义了一组方法。比如对 DEBUG 级别,定义了 isDebugEnabled()、debug(Object message) 和 debug(Object message, Throwable t) 三个方法。从这个层次来说,Log 接口简化了对于日志记录器的使用。

SLF4J 库的使用方式与 Apache Commons Logging 库比较类似。SLF4J 库中核心的 API 是提供工厂方法的 org.slf4j.LoggerFactory 类和记录日志的 org.slf4j.Logger 接口。通过 LoggerFactory 类的 getLogger 方法来获取日志记录器对象。与 Apache Commons Logging 库中的 Log 接口类似,Logger 接口中的方法也是按照不同的严重性级别来进行分组的。Logger 接口中有同样 isDebugEnabled 方法。不过 Logger 接口中发出日志记录请求的 debug 等方法使用 String 类型来表示消息,同时可以使用包含参数的消息。

slf4j 与 common-logging 比较

common-logging通过动态查找的机制,在程序运行时自动找出真正使用的日志库。由于它使用了ClassLoader寻找和载入底层的日志库, 导致了象OSGI这样的框架无法正常工作,因为OSGI的不同的插件使用自己的ClassLoader。 OSGI的这种机制保证了插件互相独立,然而却使Apache Common-Logging无法工作。

slf4j在编译时静态绑定真正的Log库,因此可以再OSGI中使用。另外,SLF4J 支持参数化的log字符串,避免了之前为了减少字符串拼接的性能损耗而不得不写的if(logger.isDebugEnable()),现在你可以直接写:logger.debug(“current user is: {}”, user)。拼装消息被推迟到了它能够确定是不是要显示这条消息的时候,但是获取参数的代价并没有幸免。
 
日志框架实现

Log4j

Apache的一个开放源代码项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件、甚至是套接口服务 器、NT的事件记录器、UNIX Syslog守护进程等;用户也可以控制每一条日志的输出格式;通过定义每一条日志信息的级别,用户能够更加细致地控制日志的生成过程。这些可以通过一个 配置文件来灵活地进行配置,而不需要修改程序代码。

LogBack

Logback是由log4j创始人设计的又一个开源日记组件。logback当前分成三个模块:logback-core,logback- classic和logback-access。logback-core是其它两个模块的基础模块。logback-classic是log4j的一个 改良版本。此外logback-classic完整实现SLF4J API使你可以很方便地更换成其它日记系统如log4j或JDK14 Logging。logback-access访问模块与Servlet容器集成提供通过Http来访问日记的功能。

Log4j 与 LogBack 比较

LogBack作为一个通用可靠、快速灵活的日志框架,将作为Log4j的替代和SLF4J组成新的日志系统的完整实现。LOGBack声称具有极佳的性能,“ 某些关键操作,比如判定是否记录一条日志语句的操作,其性能得到了显著的提高。这个操作在LogBack中需要3纳秒,而在Log4J中则需要30纳秒。 LogBack创建记录器(logger)的速度也更快:13微秒,而在Log4J中需要23微秒。更重要的是,它获取已存在的记录器只需94纳秒,而 Log4J需要2234纳秒,时间减少到了1/23。跟JUL相比的性能提高也是显著的”。 另外,LOGBack的所有文档是全面免费提供的,不象Log4J那样只提供部分免费文档而需要用户去购买付费文档。

 
总结
接口:将所有日志实现适配到了一起,用统一的接口调用。 
实现:目前主流的日志实现 
旧日志到slf4j的适配器:如果使用了slf4j,但是只想用一种实现,想把log4j的日志体系也从logback输出,这个是很有用的。 
slf4j到实现的适配器:如果想制定slf4j的具体实现,需要这些包。

slf4J与旧日志框架的关系 
slf4j等于commons-logging,是各种日志实现的通用入口,会根据classpath中存在下面哪一个Jar来决定具体的日志实现库。 
logback-classic(默认的logback实现) 
slf4j-jcl.jar(apache commons logging) 
slf4j-logj12.jar(log4j 1.2.4) 
slf4j-jdk14(java.util.logging) 
将所有使用旧式日志API的第三方类库或旧代码的日志调用转到slfj 
jcl-over-slf4j.jar/jcl104-over-slf4j:apache commons logging 1.1.1/1.0.4,直接替换即可。 
log4j-over-slf4j.jar:log4j,直接替换即可。 
jul-to-slf4j:jdk logging,需要在程序开始时调用SLF4JBridgeHandler.install()来注册listener参考JulOverSlf4jProcessor,可在applicationContext.xml中定义该bean来实现初始化。注意原有的log4j.properites将失效,logback网站上提供转换器,支持从log4j.properties 转换到logback.xml 。 

 

日志组件相关历史

Java 界里有许多实现日志功能的工具,最早得到广泛使用的是 log4j,许多应用程序的日志部分都交给了 log4j,不过作为组件开发者,他们希望自己的组件不要紧紧依赖某一个工具,毕竟在同一个时候还有很多其他很多日志工具,假如一个应用程序用到了两个组件,恰好两个组件使用不同的日志工具,那么应用程序就会有两份日志输出了。

为了解决这个问题,Apache Commons Logging (之前叫 Jakarta Commons Logging,JCL)粉墨登场,JCL 只提供 log 接口,具体的实现则在运行时动态寻找。这样一来组件开发者只需要针对 JCL 接口开发,而调用组件的应用程序则可以在运行时搭配自己喜好的日志实践工具。

所以即使到现在你仍会看到很多程序应用 JCL + log4j 这种搭配,不过当程序规模越来越庞大时,JCL的动态绑定并不是总能成功,具体原因大家可以 Google 一下,这里就不再赘述了。解决方法之一就是在程序部署时静态绑定指定的日志工具,这就是 SLF4J 产生的原因。

跟 JCL 一样,SLF4J 也是只提供 log 接口,具体的实现是在打包应用程序时所放入的绑定器(名字为 slf4j-XXX-version.jar)来决定,XXX 可以是 log4j12, jdk14, jcl, nop 等,他们实现了跟具体日志工具(比如 log4j)的绑定及代理工作。举个例子:如果一个程序希望用 log4j 日志工具,那么程序只需针对 slf4j-api 接口编程,然后在打包时再放入 slf4j-log4j12-version.jar 和 log4j.jar 就可以了。

现在还有一个问题,假如你正在开发应用程序所调用的组件当中已经使用了 JCL 的,还有一些组建可能直接调用了 java.util.logging,这时你需要一个桥接器(名字为 XXX-over-slf4j.jar)把他们的日志输出重定向到 SLF4J,所谓的桥接器就是一个假的日志实现工具,比如当你把 jcl-over-slf4j.jar 放到 CLASS_PATH 时,即使某个组件原本是通过 JCL 输出日志的,现在却会被 jcl-over-slf4j “骗到”SLF4J 里,然后 SLF4J 又会根据绑定器把日志交给具体的日志实现工具。过程如下

Component
|
| log to Apache Commons Logging
V
jcl-over-slf4j.jar --- (redirect) ---> SLF4j ---> slf4j-log4j12-version.jar ---> log4j.jar ---> 输出日志

看到上面的流程图可能会发现一个有趣的问题,假如在 CLASS_PATH 里同时放置 log4j-over-slf4j.jar 和 slf4j-log4j12-version.jar 会发生什么情况呢?没错,日志会被踢来踢去,最终进入死循环。

所以使用 SLF4J 的比较典型搭配就是把 slf4j-api、JCL 桥接器、java.util.logging(JUL)桥接器、log4j 绑定器、log4j 这5个 jar 放置在 CLASS_PATH 里。

不过并不是所有APP容器都是使用 log4j 的,比如 Google AppEngine 它使用的是 java.util.logging(JUL),这时应用 SLF4J 的搭配就变成 slf4j-api、JCL桥接器、logj4桥接器、JUL绑定器这4个 jar 放置在 WEB-INF/lib 里。

 
http://blog.jobbole.com/51155/
http://phl.iteye.com/blog/2021461
http://blog.csdn.net/yycdaizi/article/details/8276265

2015第30周四Java日志组件的更多相关文章

  1. Java日志组件logback使用:加载非类路径下的配置文件并设置定时更新

    Java日志组件logback使用:加载非类路径下的配置文件并设置定时更新 摘自: https://blog.csdn.net/johnson_moon/article/details/7887449 ...

  2. java日志组件介绍(common-logging,log4j,slf4j,logback )

    转自:http://www.blogjava.net/daiyongzhi/archive/2014/04/13/412364.html common-logging是apache提供的一个通用的日志 ...

  3. 转:java日志组件介绍(common-logging,log4j,slf4j,logback )

    原网址:http://www.blogjava.net/daiyongzhi/archive/2014/04/13/412364.html common-logging common-logging是 ...

  4. 【转】java日志组件介绍(common-logging,log4j,slf4j,logback )

    common-logging common-logging是apache提供的一个通用的日志接口.用户可以自由选择第三方的日志组件作为具体实现,像log4j,或者jdk自带的logging, comm ...

  5. 五分钟秒懂Java日志组件

    Java中有许多种日志记录方式,有些API有占位符,有些API没占位符,初学的人可能会搞不清楚这些日志组件的由来.我一开始的时候也是很懵逼的,后来一点点弄懂了于是就又了这篇文章. 在Java中进行日志 ...

  6. Java日志组件2---Log4j(org.apache.log4j.Logger)

    如果我们在项目中,需要记录的东西并不多,而且也不需要有太多区分,使用jdk的自带Log完全可以解决问题.但是,在开发的过程中,大多数项目都比较大,为方便找到程序的bug,都是需要系统的记录日志的.这里 ...

  7. Java日志组件1---Jdk自带Logger(java.util.logging.Logger)

    最近在看日志的一些东西,发现利用JDK自带的log也可以简单的实现日志的输出,将日志写入文件的过程记录如下: 1.新建LogUtil.Java( 里面写了几个静态方法,为log设置等级.添加log控制 ...

  8. JAVA日志库2

    一.常用日志Jar关系 2015第30周四Java日志组件 接口:将所有日志实现适配到了一起,用统一的接口调用. 实现:目前主流的日志实现 旧日志到slf4j的适配器:如果使用了slf4j,但是只想用 ...

  9. [翻译]Java日志终极指南

    本文由 ImportNew - Wing 翻译自 loggly.欢迎加入翻译小组.转载请见文末要求. Java日志基础 Java使用了一种自定义的.可扩展的方法来输出日志.虽然Java通过java.u ...

随机推荐

  1. mkfs---创建Linux文件系统

    [root@xiaolizi ~]# mkfsmkfs mkfs.btrfs mkfs.cramfs mkfs.ext2 mkfs.ext3 mkfs.ext4 mkfs.minix mkfs.xfs ...

  2. 微信小程序从零开始开发步骤(五)轮播图

    上一章完成页面自定义分享,这一章来说说轮播图,最常见的一个轮播图,中间带小圆点,自动轮播. Swiper是滑动特效插件,面向手机.平板电脑等移动终端.能实现触屏焦点图.触屏Tab切换.触屏多图切换等常 ...

  3. C. Arthur and Table(Codeforces Round #311 (Div. 2) 贪心)

    C. Arthur and Table time limit per test 1 second memory limit per test 256 megabytes input standard ...

  4. js--07 编解码,eval

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/stri ...

  5. 36.intellij idea 如何一键清除所有断点

    转自:https://www.cnblogs.com/austinspark-jessylu/p/7799212.html 1.在idea左下方找到"View Breakpoints&quo ...

  6. Mysql数据库的瓶颈处理一点建议

    Mysql数据库的瓶颈处理一点建议         我们在使用Mysql数据库是常见的两个瓶颈是CPU和I/O的瓶颈,CPU在饱和的时候一般发生在数据装入内存或从磁盘上读取数据时候.磁盘I/O瓶颈的出 ...

  7. CList 点击表头排序 (2)两种排序方法中其中一种

    上一篇讲解SortItem()方法如何使用,虽然都是抄别人的但是就是想让大家有个大概的了解 CList 点击表头排序 (1)SortItems函数 点击表头排序基本思路都是 1.首先响应HDN_ITE ...

  8. Java中的线程模型及实现方式

    概念: 线程是一个程序内部的顺序控制流 线程和进程的比较: 每个进程都有独立的代码和数据空间(进程上下文),进程切换的开销大. 线程:轻量的进程,同一类线程共享代码和数据空间,每个线程有独立的运行栈和 ...

  9. amazeui学习笔记二(进阶开发1)--项目结构structure

    amazeui学习笔记二(进阶开发1)--项目结构structure 一.总结 1.项目结构:是说的amazeui在github上面的项目结构,二次开发amazeui用 二.项目结构structure ...

  10. iOS Threading编程指南 官方文档翻译第一篇(序言)

    序言   Thread是能够使多个code paths 在同一个APP内并发运行的几种技术之一.虽然新的技术为并发运行提供了先进.高效的工具(例如operation 对象和GCD),但是OS X和iO ...