logback和log4j的区别能共存吗

> 施用logback替换原有项目中的log4j
施用logback替换原有项目中的log4j
发布时间: & &
浏览:25 & &
回复:0 & &
悬赏:0.0希赛币
使用logback替换原有项目中的log4j
  据说logback性能比较高,故想替换以前项目中的log4j,需要如下jar包:
  jcl-over-slf4j-1.6.1.jar log4j-over-slf4j-1.6.1.jar logback-classic-0.9.28.jar logback-core-0.9.28.jar slf4j-api-1.6.1.jar 工程中加入上述jar包,即可替换调commonsloging+log4j 并且,类中创建Logger地方,根本不用修改。
本问题标题:
本问题地址:
温馨提示:本问题已经关闭,不能解答。
暂无合适的专家
&&&&&&&&&&&&&&&
希赛网 版权所有 & &&从Log4j迁移到LogBack的理由 - 技术翻译 - 开源中国社区
从Log4j迁移到LogBack的理由
【已翻译100%】
英文原文:
推荐于 4年前 (共 10 段, 翻译完成于 04-02)
参与翻译&(4人)&: ,
无论从设计上还是实现上,Logback相对log4j而言有了相对多的改进。不过尽管难以一一细数,这里还是列举部分理由为什么选择logback而不是log4j。牢记logback与log4j在概念上面是很相似的,它们都是有同一群开发者建立。所以如果你已经对log4j很熟悉,你也可以很快上手logback。如果你喜欢使用log4j,你也许会迷上使用logback。
更快的执行速度
基于我们先前在log4j上的工作,logback 重写了内部的实现,在某些特定的场景上面,甚至可以比之前的速度快上10倍。在保证logback的组件更加快速的同时,同时所需的内存更加少。
&翻译得不错哦!
充分的测试
Logback 历经了几年,数不清小时数的测试。尽管log4j也是测试过的,但是Logback的测试更加充分,跟log4j不在同一个级别。我们认为,这正是人们选择Logback而不是log4j的最重要的原因。人们都希望即使在恶劣的条件下,你的日记框架依然稳定而可靠。
logback-classic 非常自然的实现了SLF4J
logback-classic中的登陆类自然的实现了SLF4J。当你使用
logback-classic作为底层实现时,涉及到LF4J日记系统的问题你完全不需要考虑。更进一步来说,由于
logback-classic强烈建议使用SLF4J作为客户端日记系统实现,如果需要切换到log4j或者其他,你只需要替换一个jar包即可,不需要去改变那些通过
SLF4J API 实现的代码。这可以大大减少更换日记系统的工作量。
&翻译得不错哦!
Logback附带详细的和不断更新的文档。
使用XML配置文件或者Groovy
配置logback的传统方法是通过XML文件。在文档中,大部分例子都是是用XML语法。但是,对于logback版本0.9.22,也得到支持。相比于XML,Groovy风格的配置文件更加直观,连贯和简短的语法。
现在, 已经有一个。
&翻译得不错哦!
自动重新载入配置文件
Logback-classic可以。这个扫描过程很快,无资源争用,并且可以动态扩展支持在上百个线程之间每秒上百万个调用。它和应用服务器结合良好,并且在JEE环境通用,因为它不会调用创建一个单独的线程来做扫描。
优雅地从I/O错误中恢复
FileAppender和它的子类,包括RollingFileAppender,可以优雅的从I/O错误中恢复。所以,如果一个文件服务器临时宕机,你再也不需要重启你的应用,而日志功能就能正常工作。当文件服务器恢复工作,logback相关的appender就会透明地和快速的从上一个错误中恢复。
&翻译得不错哦!
自动清除旧的日志归档文件
通过设置&或者&的&maxHistory&属性,你就可以控制日志归档文件的最大数量。如果你的回滚策略是每月回滚的,并且你希望保存一年的日志,那么只需简单的设置maxHistory属性为12。对于12个月之前的归档日志文件将被自动清除。
自动压缩归档日志文件
可以在回滚操作中,自动压缩归档日志文件。压缩通常是异步执行的,所以即使是很大的日志文件,你的应用都不会因此而被阻塞。
&翻译得不错哦!
在中,在多个JVM中运行的多个FileAppender实例,可以安全的写入统一个日志文件。谨慎模式可以在一定的限制条件下应用于RollingFileAppender。
是logback的一个记录和访问事件查看器。它相当于log4j的 chainsaw,但是Lilith设计的目的是处理大量的日志记录。
配置文件中的条件处理
开发者通常需要在不同的目标环境中变换logback的配置文件,例如开发环境,测试环境和生产环境。这些配置文件大体是一样的,除了某部分会有不同。为了避免重复,logback支持,只需使用&if&,&then&和&else&,那么同一个配置文件就可以在不同的环境中使用了。
&翻译得不错哦!
Logback拥有远比log4j更丰富的。例如,让我们假设,有一个相当重要的商业应用部署在生产环境。考虑到大量的交易数据需要处理,记录级别被设置为WARN,那么只有警告和错误信息才会被记录。现在,想象一下,你在开发环境遇到了一个臭虫,但是在测试平台中却很难发现,因为一些环境之间(生产环境/测试环境)的未知差异。
&翻译得不错哦!
使用log4j,你只能选择在生产系统中降低记录的级别到DEBUG,来尝试发现问题。但是很不幸,这会生成大量的日志记录,让分析变得困难。更重要的是,多余的日志记录会影响到生产环境的性能。
使用logback,你可以选择保留只所有用户的WARN级别的日志,而除了某个用户,例如Alice,而她就是问题的相关用户。当Alice登录系统,她就会以DEBUG级别被记录,而其他用户仍然是以WARN级别来记录日志。这个功能,可以通过在配置文件的XML中添加4行。请在中查找MDCFilter
&翻译得不错哦!
SiftingAppender
是一个全能的追加器。它可以基于任何给定的实时属性分开(或者筛选)日志。例如,SiftingAppender可以基于用户会话分开日志事件,这样,可以为每一个用户建立一个独立的日志文件。
堆栈轨迹信息包含包的数据
当logback打印一个异常,堆栈轨迹信息将包含包的相关数据。下面是一个通过&&生成的堆栈信息:
14:28:48.835 [btpool0-7] INFO
c.q.l.demo.prime.PrimeAction - 99 is not a valid value
java.lang.Exception: 99 is invalid
at ch.qos.logback.demo.prime.PrimeAction.execute(PrimeAction.java:28) [classes/:na]
at org.apache.struts.action.RequestProcessor.processActionPerform(RequestProcessor.java:431) [struts-1.2.9.jar:1.2.9]
at org.apache.struts.action.RequestProcessor.process(RequestProcessor.java:236) [struts-1.2.9.jar:1.2.9]
at org.apache.struts.action.ActionServlet.doPost(ActionServlet.java:432) [struts-1.2.9.jar:1.2.9]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:820) [servlet-api-2.5-6.1.12.jar:6.1.12]
at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:502) [jetty-6.1.12.jar:6.1.12]
at ch.qos.logback.demo.UserServletFilter.doFilter(UserServletFilter.java:44) [classes/:na]
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1115) [jetty-6.1.12.jar:6.1.12]
at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:361) [jetty-6.1.12.jar:6.1.12]
at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:417) [jetty-6.1.12.jar:6.1.12]
at org.mortbay.jetty.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:230) [jetty-6.1.12.jar:6.1.12]
从上面的信息,你可以发现这个应用使用Struts 1.2.9 而且是使用 jetty 6.1.12部署的。所以,堆栈轨迹信息将快速的告诉读者,关于异常发生的类还有包和包的版本。当你的客户发送一个堆栈轨迹信息给你,作为一个开发人员,你就不需要让他们告诉你他们正在使用的包的版本。这项信息已经包括在堆栈轨迹信息中。详细请参考& .
这项功能可以非常有帮助的说明,有些用户误以为这是。
&翻译得不错哦!
Logback-access模块,提供了通过HTTP访问日志的能力,是logback不可或缺的组成部分
最后但绝非最不重要的是,作为logback发布包的一部分,logback-access模块可与Jetty或者Tomcat进行集成,提供了非常丰富而强大的通过HTTP访问日志的功能。因为logback-access模块是logback初期设计方案中的一部分,因此,所有你所喜欢的logback-classic模块所提供的全部特性logback-access同样也具备。
我们给出了许多选择logback而不选择log4j的理由。简而言之,既然logback构建于我们先前所构建的log4j之上,logback可以说就是一个更好的log4j。
&翻译得不错哦!
我们的翻译工作遵照 ,如果我们的工作有侵犯到您的权益,请及时联系我们
吃饱了撑,没完没了。
吃饱了撑,没完没了。.......
为什么人们总喜欢嘲笑这些贡献者,在网上贡献自己的力量,这本身就是应该被鼓励和赞美的,出现细节上的小错误,谁都在所难免,为什么人们就不能宽容一些呢?
为什么人们总喜欢嘲笑这些贡献者,在网上贡献自己的力量,这本身就是应该被鼓励和赞美的,出现细节上的小错误,谁都在所难免,为什么人们就不能宽容一些呢?这不是贡献,这是捣乱。
为什么人们总喜欢嘲笑这些贡献者,在网上贡献自己的力量,这本身就是应该被鼓励和赞美的,出现细节上的小错误,谁都在所难免,为什么人们就不能宽容一些呢?这不是贡献,这是捣乱。。。。完美主义者啊
看样子平时不犯错的。佩服posts - 3,&
comments - 4,&
trackbacks - 0
common-loggingcommon-logging是apache提供的一个通用的日志接口。用户可以自由选择第三方的日志组件作为具体实现,像log4j,或者jdk自带的logging, common-logging会通过动态查找的机制,在程序运行时自动找出真正使用的日志库。当然,common-logging内部有一个Simple logger的简单实现,但是功能很弱。所以使用common-logging,通常都是配合着log4j来使用。使用它的好处就是,代码依赖是common-logging而非log4j, 避免了和具体的日志方案直接耦合,在有必要时,可以更改日志实现的第三方库。使用common-logging的常见代码:[java]&import&mons.logging.L&&import&mons.logging.LogF&&&&public&class&A&{&&&&&&private&static&Log&logger&=&LogFactory.getLog(this.getClass());&&}&&动态查找原理:Log 是一个接口声明。LogFactory 的内部会去装载具体的日志系统,并获得实现该Log 接口的实现类。LogFactory 内部装载日志系统的流程如下:首先,寻找mons.logging.LogFactory 属性配置。否则,利用JDK1.3 开始提供的service 发现机制,会扫描classpah 下的META-INF/services/mons.logging.LogFactory文件,若找到则装载里面的配置,使用里面的配置。否则,从Classpath 里寻找commons-logging.properties ,找到则根据里面的配置加载。否则,使用默认的配置:如果能找到Log4j 则默认使用log4j 实现,如果没有则使用JDK14Logger 实现,再没有则使用commons-logging 内部提供的SimpleLog 实现。从上述加载流程来看,只要引入了log4j 并在classpath 配置了log4j.xml ,则commons-logging 就会使log4j 使用正常,而代码里不需要依赖任何log4j 的代码。slf4jslf4j全称为Simple Logging Facade for JAVA,java简单日志门面。类似于Apache Common-Logging,是对不同日志框架提供的一个门面封装,可以在部署的时候不修改任何配置即可接入一种日志实现方案。但是,他在编译时静态绑定真正的Log库。使用SLF4J时,如果你需要使用某一种日志实现,那么你必须选择正确的SLF4J的jar包的集合(各种桥接包)。使用slf4j的常见代码:[java]&import&org.slf4j.L&&import&org.slf4j.LoggerF&&&&public&class&A&{&&&&&&private&static&Log&logger&=&LogFactory.getLog(this.getClass());&&}&&slf4j静态绑定原理:SLF4J 会在编译时会绑定import org.slf4j.impl.StaticLoggerB 该类里面实现对具体日志方案的绑定接入。任何一种基于slf4j 的实现都要有一个这个类。如:org.slf4j.slf4j-log4j12-1.5.6: 提供对 log4j 的一种适配实现。注意:如果有任意两个实现slf4j 的包同时出现,那么就可能出现问题。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)。拼装消息被推迟到了它能够确定是不是要显示这条消息的时候,但是获取参数的代价并没有幸免。Log4jApache的一个开放源代码项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件、甚至是套接口服务 器、NT的事件记录器、UNIX Syslog守护进程等;用户也可以控制每一条日志的输出格式;通过定义每一条日志信息的级别,用户能够更加细致地控制日志的生成过程。这些可以通过一个 配置文件来灵活地进行配置,而不需要修改程序代码。LogBackLogback是由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接口,接入具体实现的方法应用代码中使用别的日志接口,转成slf4j的方法日志组件相关历史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 LoggingVjcl-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 里。
阅读(9720)
java日志组件介绍(common-logging,log4j,slf4j,logback )
关于Java 日志最好的介绍。转载过去。&&&&&&
java日志组件介绍(common-logging,log4j,slf4j,logback )
lihai ,拿走&&&&&&
java日志组件介绍(common-logging,log4j,slf4j,logback )
赞一个,详细代码示例可参考这个:&&&&&&
java日志组件介绍(common-logging,log4j,slf4j,logback )
很清晰,谢谢。&&&&&&
3031123456789101112141516171819202122232425262728293012345678910
阅读排行榜
评论排行榜jcl与jul、log4j1、log4j2、logback的集成原理 -
- ITeye技术网站
博客分类:
本文章已收录于:
jcl与jul、log4j1、log4j2、logback的集成原理
转自:http://my.oschina.net/pingpangkuangmo/blog/407895#OSC_h1_17
1 系列目录
前面介绍了jdk自带的logging、log4j1、log4j2、logback等实际的日志框架
对于开发者而言,每种日志都有不同的写法。如果我们以实际的日志框架来进行编写,代码就限制死了,之后就很难再更换日志系统,很难做到无缝切换。
java web开发就经常提到一项原则:面向接口编程,而不是面向实现编程
所以我们应该是按照一套统一的API来进行日志编程,实际的日志框架来实现这套API,这样的话,即使更换日志框架,也可以做到无缝切换。
这就是commons-logging与slf4j的初衷。
下面就来介绍下commons-logging与slf4j这两个门面如何与上述四个实际的日志框架进行集成的呢
介绍之前先说明下日志简称:
jdk自带的logging-&简称 jul (java-util-logging)
apache commons-logging-&简称 jcl
2 apache commons-logging
先从一个简单的使用案例来说明
2.1 简单的使用案例
private static Log logger=LogFactory.getLog(JulJclTest.class);
public static void main(String[] args){
if(logger.isTraceEnabled()){
logger.trace("commons-logging-jcl trace message");
if(logger.isDebugEnabled()){
logger.debug("commons-logging-jcl debug message");
if(logger.isInfoEnabled()){
("commons-logging-jcl info message");
上述Log、LogFactory都是commons-logging自己的接口和类
2.2 使用原理
LogFactory.getLog(JulJclTest.class)的源码如下:
public static Log getLog(Class clazz) throws LogConfigurationException {
return getFactory().getInstance(clazz);
上述获取Log的过程大致分成2个阶段
获取LogFactory的过程 (从字面上理解就是生产Log的工厂)
根据LogFactory获取Log的过程
commons-logging默认提供的LogFactory实现:LogFactoryImpl commons-logging默认提供的Log实现:Jdk14Logger、Log4JLogger、SimpleLog。
来看下commons-logging包中的大概内容:
下面来详细说明:
1 获取LogFactory的过程
从下面几种途径来获取LogFactory
1.1 系统属性中获取,即如下形式
System.getProperty("mons.logging.LogFactory")
1.2 使用java的SPI机制,来搜寻对应的实现
对于java的SPI机制,详细内容可以自行搜索,这里不再说明。搜寻路径如下:
META-INF/services/org.apache.commons.logging.LogFactory
简单来说就是搜寻哪些jar包中含有搜寻含有上述文件,该文件中指明了对应的LogFactory实现
1.3 从commons-logging的配置文件中寻找
commons-logging也是可以拥有自己的配置文件的,名字为commons-logging.properties,只不过目前大多数情况下,我们都没有去使用它。如果使用了该配置文件,尝试从配置文件中读取属性"mons.logging.LogFactory"对应的值
1.4 最后还没找到的话,使用默认的mons.logging.impl.LogFactoryImpl
LogFactoryImpl是commons-logging提供的默认实现
2 根据LogFactory获取Log的过程
这时候就需要寻找底层是选用哪种类型的日志
就以commons-logging提供的默认实现为例,来详细看下这个过程:
2.1 从commons-logging的配置文件中寻找Log实现类的类名
从commons-logging.properties配置文件中寻找属性为"mons.logging.Log"对应的Log类名
2.2 从系统属性中寻找Log实现类的类名
即如下方式获取:
System.getProperty("mons.logging.Log")
2.3 如果上述方式没找到,则从classesToDiscover属性中寻找
classesToDiscover属性值如下:
private static final String[] classesToDiscover = {
"mons.logging.impl.Log4JLogger",
"mons.logging.impl.Jdk14Logger",
"mons.logging.impl.Jdk13LumberjackLogger",
"mons.logging.impl.SimpleLog"
它会尝试根据上述类名,依次进行创建,如果能创建成功,则使用该Log,然后返回给用户。
下面针对具体的日志框架,看看commons-logging是如何集成的
3 commons-logging与jul集成
3.1 需要的jar包
commons-logging
对应的maven依赖是:
&commons-logging&
&commons-logging&
3.2 使用案例
private static Log logger=LogFactory.getLog(JulJclTest.class);
public static void main(String[] args){
if(logger.isTraceEnabled()){
logger.trace("commons-logging-jcl trace message");
if(logger.isDebugEnabled()){
logger.debug("commons-logging-jcl debug message");
if(logger.isInfoEnabled()){
("commons-logging-jcl info message");
结果输出如下:
四月 27, 2015 11:13:33 下午 com.demo.log4j.JulJclTest main
信息: commons-logging-jcl info message
3.3 使用案例分析
案例过程分析,就是看看上述commons-logging的在执行原理的过程中是如何来走的
1 获取获取LogFactory的过程
1.1 我们没有配置系统属性"mons.logging.LogFactory”
1.2 我们没有配置commons-logging的commons-logging.properties配置文件
1.3 也没有含有"META-INF/services/mons.logging.LogFactory"路径的jar包
所以commons-logging会使用默认的LogFactoryImpl作为LogFactory
2 根据LogFactory获取Log的过程
2.1 我们没有配置commons-logging的commons-logging.properties配置文件
2.2 我们没有配置系统属性"mons.logging.Log”
所以就需要依次根据classesToDiscover中的类名称进行创建。
2.3 先是创建mons.logging.impl.Log4JLogger
创建失败,因为该类是依赖org.apache.log4j包中的类的
2.4 接着创建mons.logging.impl.Jdk14Logger
创建成功,所以我们返回的就是Jdk14Logger,看下它是如何与jul集成的
它内部有一个java.util.logging.Logger logger属性,所以Jdk14Logger的info(“commons-logging-jcl info message”)操作都会转化成由java.util.logging.Logger来实现:
上述logger的来历:
logger = java.util.logging.Logger.getLogger(name);
就是使用jul原生的方式创建的一个java.util.logging.Logger,参见
是如何打印info信息的呢?
使用jul原生的方式:
logger.log(Level.WARNING,"commons-logging-jcl info message");
由于jul默认的级别是INFO级别(见上一篇文章的说明中的配置文件),所以只打出了如下信息:
四月 27, 2015 11:41:24 下午 com.demo.log4j.JulJclTest main
信息: commons-logging-jcl info message
原生的jdk的logging的日志级别是FINEST、FINE、INFO、WARNING、SEVERE分别对应我们常见的trace、debug、info、warn、error。
4 commons-logging与log4j1集成
4.1 需要的jar包
commons-logging
对应的maven依赖是:
&commons-logging&
&commons-logging&
4.2 使用案例
在类路径下加入log4j的配置文件log4j.properties
log4j.rootLogger = trace, console
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} %m%n
使用方式如下:
private static Log logger=LogFactory.getLog(Log4jJclTest.class);
public static void main(String[] args){
if(logger.isTraceEnabled()){
logger.trace("commons-logging-log4j trace message");
if(logger.isDebugEnabled()){
logger.debug("commons-logging-log4j debug message");
if(logger.isInfoEnabled()){
("commons-logging-log4j info message");
代码没变,还是使用commons-logging的接口和类来编程,没有log4j的任何影子。这样,commons-logging就与log4j集成了起来,我们可以通过log4j的配置文件来控制日志的显示级别
上述是trace级别(小于debug),所以trace、debug、info的都会显示出来
4.3 使用案例分析
案例过程分析,就是看看上述commons-logging的在执行原理的过程中是如何来走的:
1 获取获取LogFactory的过程
同上述jcl的过程一样,使用默认的LogFactoryImpl作为LogFactory
2 根据LogFactory获取Log的过程
同上述jcl的过程一样,最终会依次根据classesToDiscover中的类名称进行创建:
先是创建mons.logging.impl.Log4JLogger
创建成功,因为此时含有log4j的jar包,所以返回的是Log4JLogger,我们看下它与commons-logging是如何集成的:
它内部有一个org.apache.log4j.Logger logger属性,这个是log4j的原生Logger。所以Log4JLogger都是委托这个logger来完成的
2.1 org.apache.log4j.Logger logger来历
org.apache.log4j.Logger.getLogger(name)
使用原生的log4j1的写法来生成,参见之前log4j原生的写法,我们知道上述过程会引发log4j1的配置文件的加载,之后就进入log4j1的世界了
2.2 输出日志
测试案例中我们使用commons-logging输出的日志的形式如下(这里的logger是mons.logging.impl.Log4JLogger类型):
logger.debug("commons-logging-log4j debug message");
其实就会转换成log4j原生的org.apache.log4j.Logger对象(就是上述获取的org.apache.log4j.Logger类型的logger对象)的如下输出:
logger.debug("log4j debug message");
上述过程最好与log4j1的原生方式对比着看,见
5 commons-logging与log4j2集成
5.1 需要的jar包
commons-logging
log4j-api (log4j2的API包)
log4j-core (log4j2的API实现包)
log4j-jcl (log4j2与commons-logging的集成包)
对应的maven依赖是:
&commons-logging&
&commons-logging&
&org.apache.logging.log4j&
&log4j-api&
&org.apache.logging.log4j&
&log4j-core&
&org.apache.logging.log4j&
&log4j-jcl&
5.2 使用案例
编写log4j2的配置文件log4j2.xml,简单如下:
&?xml version="1.0" encoding="UTF-8"?&
status="WARN"&
name="Console" target="SYSTEM_OUT"&
pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/&
level="debug"&
ref="Console"/&
使用案例如下:
private static Log logger=LogFactory.getLog(Log4j2JclTest.class);
public static void main(String[] args){
if(logger.isTraceEnabled()){
logger.trace("commons-logging-log4j trace message");
if(logger.isDebugEnabled()){
logger.debug("commons-logging-log4j debug message");
if(logger.isInfoEnabled()){
("commons-logging-log4j info message");
仍然是使用commons-logging的Log接口和LogFactory来进行编写,看不到log4j2的影子。但是这时候含有上述几个jar包,log4j2就与commons-logging集成了起来。
5.3 使用案例分析
案例过程分析,就是看看上述commons-logging的在执行原理的过程中是如何来走的:
1 先来看下上述 log4j-jcl(log4j2与commons-logging的集成包)的来历:
我们知道,commons-logging原始的jar包中使用了默认的LogFactoryImpl作为LogFactory,该默认的LogFactoryImpl中的classesToDiscover(到上面查看它的内容)并没有log4j2对应的Log实现类。所以我们就不能使用这个原始包中默认的LogFactoryImpl了,需要重新指定一个,并且需要给出一个apache的Log实现(该Log实现是用于log4j2的),所以就产生了log4j-jcl这个jar包,来看下这个jar包的大致内容:
这里面的LogFactoryImpl就是要准备替换commons-logging中默认的LogFactoryImpl(其中META-INF/services/下的那个文件起到重要的替换作用,下面详细说)
这里面的Log4jLog便是针对log4j2的,而commons-logging中的原始的Log4JLogger则是针对log4j1的。它们都是commons-logging的Log接口的实现
2 获取获取LogFactory的过程
这个过程就和jul、log4j1的集成过程不太一样了。通过java的SPI机制,找到了mons.logging.LogFactory对应的实现,即在log4j-jcl包中找到的,其中META-INF/services/mons.logging.LogFactory中的内容是:
org.apache.logging.log4j.jcl.LogFactoryImpl
即指明了使用log4j-jcl中的LogFactoryImpl作为LogFactory
3 根据LogFactory获取Log的过程
就来看下log4j-jcl中的LogFactoryImpl是怎么实现的
public class LogFactoryImpl extends LogFactory {
private final LoggerAdapter&Log& adapter = new LogAdapter();
这个LoggerAdapter是lo4j2中的一个适配器接口类,根据log4j2生产的原生的org.apache.logging.log4j.Logger实例,将它包装成你指定的泛型类。
这里使用的LoggerAdapter实现是LogAdapter,它的内容如下:
public class LogAdapter extends AbstractLoggerAdapter&Log& {
protected Log newLogger(final String name, final LoggerContext context) {
return new Log4jLog(context.getLogger(name));
protected LoggerContext getContext() {
return getContext(ReflectionUtil.getCallerClass(LogFactory.class));
我们可以看到,它其实就是将原生的log4j2的Logger封装成Log4jLog。这里就可以看明白了,下面来详细的走下流程,看看是什么时候来初始化log4j2的:
3.1 首先获取log4j2中的重要配置对象LoggerContext,LogAdapter的实现如上面的源码(使用父类的getContext方法),父类方法的内容如下:
LogManager.getContext(cl, false);
我们可以看到这其实就是使用log4j2的LogManager进行初始化的,至此就进入log4j2的初始化的世界了。
3.2 log4j2的LoggerContext初始化完成后,该生产一个log4j2原生的Logger对象
使用log4j2原生的方式:
context.getLogger(name)
3.3 将上述方式产生的Log4j原生的Logger实例进行包装,包装成Log4jLog
new Log4jLog(context.getLogger(name));
至此,我们通过Log4jLog实例打印的日志都是委托给了它内部包含的log4j2的原生Logger对象了。
上述过程最好与log4j2的原生方式对比着看,见
6 commons-logging与logback集成
6.1 需要的jar包
jcl-over-slf4j (替代了commons-logging,下面详细说明)
logback-core
logback-classic
对应的maven依赖是:
&org.slf4j&
&jcl-over-slf4j&
&org.slf4j&
&slf4j-api&
&ch.qos.logback&
&logback-core&
&ch.qos.logback&
&logback-classic&
6.2 使用案例
首先在类路径下编写logback的配置文件logback.xml,简单如下:
&?xml version="1.0" encoding="UTF-8"?&
&configuration&
&appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"&
&pattern&%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n&/pattern&
&/encoder&
&/appender&
&root level="DEBUG"&
&appender-ref ref="STDOUT" /&
&/configuration&
使用方式:
private static Log logger=LogFactory.getLog(LogbackTest.class);
public static void main(String[] args){
if(logger.isTraceEnabled()){
logger.trace("commons-logging-jcl trace message");
if(logger.isDebugEnabled()){
logger.debug("commons-logging-jcl debug message");
if(logger.isInfoEnabled()){
("commons-logging-jcl info message");
完全是用commons-logging的API来完成日志编写
6.3 使用案例分析
logback本身的使用其实就和slf4j绑定了起来,现在要想指定commons-logging的底层log实现是logback,则需要2步走
第一步: 先将commons-logging底层的log实现转向slf4j (jcl-over-slf4j干的事)
第二步: 再根据slf4j的选择底层日志原理,我们使之选择上logback
这样就可以完成commons-logging与logback的集成。即写着commons-logging的API,底层却是logback来进行输出
然后来具体分析下整个过程的源码实现:
1 先看下jcl-over-slf4j都有哪些内容(它可以替代了commons-logging),如下图
1.1 commons-logging中的Log接口和LogFactory类等
这是我们使用commons-logging编写需要的接口和类
1.2 去掉了commons-logging原生包中的一些Log实现和默认的LogFactoryImpl
只有SLF4JLog实现和SLF4JLogFactory
这就是jcl-over-slf4j的大致内容
这里可以与commons-logging原生包中的内容进行下对比。原生包中的内容如下:
2 获取获取LogFactory的过程
jcl-over-slf4j包中的LogFactory和commons-logging中原生的LogFactory不一样,jcl-over-slf4j中的LogFactory直接限制死,是SLF4JLogFactory,源码如下:
public abstract class LogFactory {
static LogFactory logFactory = new SLF4JLogFactory();
3 根据LogFactory获取Log的过程
这就需要看下jcl-over-slf4j包中的SLF4JLogFactory的源码内容:
Logger slf4jLogger = LoggerFactory.getLogger(name);
if (slf4jLogger instanceof LocationAwareLogger) {
newInstance = new SLF4JLocationAwareLog((LocationAwareLogger) slf4jLogger);
newInstance = new SLF4JLog(slf4jLogger);
可以看到其实是用slf4j的LoggerFactory先创建一个slf4j的Logger实例(这其实就是单独使用logback的使用方式,见)。
然后再将这个Logger实例封装成common-logging定义的Log接口实现,即SLF4JLog或者SLF4JLocationAwareLog实例。
所以我们使用的commons-logging的Log接口实例都是委托给slf4j创建的Logger实例(slf4j的这个实例又是选择logbakc后产生的,即slf4j产生的Logger实例最终还是委托给logback中的Logger的)
7 未完待续
这篇讲解commons-logging与jul、log4j1、log4j2、logback的集成原理,内容很长了,就把slf4j与上述四者的集成放到下一篇文章
浏览: 42524 次
来自: 上海

我要回帖

更多关于 logback log4j 共存 的文章

 

随机推荐