Java 日志 API
从功能上来讲,日志 API 自己所需求的功能很是简单,只须要可以记录一段文本便可。API 的使用者在须要进行记录时,根据当前的上下文信息构造出相应的文本信息,调用 API 完成记录。通常来讲,日志 API 由下面几个部分组成:java
- 记录器(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 接口简化了对于日志记录器的使用。apache
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