JAVA几种日志组件的兼容

来源:互联网 发布:无法打开数据库msdb 编辑:程序博客网 时间:2024/06/05 09:53

    • 几种日志组件介绍
    • jul转log4j的桥接关系
      • 1maven 依赖文件
      • 2SLF4JBridgeHandler要在代码中引用
      • 3log4jxml样例
    • 调试遇到的问题
      • 1slf4j存在多个绑定时出错
        • 11意外验证调整引用顺序竟然也对了
        • 2官方文档解释
      • 2log4jWARN 元素类型为 log4jconfiguration 的内容必须匹配

JAVA有多款日志组件介绍如jul,common-logging,log4j,slf4j,logback等,一个项目中引用的框架或库可能用到不同的日志组件。
这次就遇到兼容性的问题,专门把这个问题记录下来

1.几种日志组件介绍

参考别人的文档:java日志组件介绍(common-logging,log4j,slf4j,logback )

2.jul转log4j的桥接关系

参考:桥接关系
我这次的项目是jul转log4j,官方有非常清晰的桥接关系图,形象的表述了不同日志组件的转换关系

非常清晰的桥接关系图
如:jul –> slf4j–>log4j
- SLF4J bound to log4j
- with redirection of commons-logging and java.util.logging to SLF4J

2.1.maven 依赖文件:

jul-to-slf4j —-> slf4j-api
jcl-over-slf4j –> slf4j-api
—————-> slf4j-api -> slf4j-log4j12 -> log4j
包含slf4j-api、[JCL 桥接器、java.util.logging(JUL)桥接器]、log4j 绑定器、log4j 这5个 jar

        <dependency>            <groupId>log4j</groupId>            <artifactId>log4j</artifactId>            <version>1.2.17</version>            <scope>compile</scope>        </dependency>        <dependency>            <groupId>org.slf4j</groupId>            <artifactId>slf4j-api</artifactId>            <version>1.7.12</version>            <scope>compile</scope>        </dependency>        <dependency>            <groupId>org.slf4j</groupId>            <artifactId>jul-to-slf4j</artifactId>            <version>1.7.12</version>            <scope>compile</scope>        </dependency>        <dependency>            <groupId>org.slf4j</groupId>            <artifactId>jcl-over-slf4j</artifactId>            <version>1.7.12</version>            <scope>compile</scope>        </dependency>        <dependency>            <groupId>org.slf4j</groupId>            <artifactId>slf4j-log4j12</artifactId>            <version>1.7.12</version>        </dependency>

2.2.SLF4JBridgeHandler要在代码中引用

参考官方文档:SLF4JBridgeHandler要在代码中引用 ,应用代码如下

    public static void main(String[] args) {        // Optionally remove existing handlers attached to j.u.l root logger        SLF4JBridgeHandler.removeHandlersForRootLogger();         // (since SLF4J 1.6.5) add SLF4JBridgeHandler to j.u.l's root logger,         // should be done once during        // the initialization phase of your application        SLF4JBridgeHandler.install();        ..    }

2.3.log4j.xml样例

这是我的一个简单样例,如果想看详细讲解,参考log4j.xml介绍

<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd"><log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">    <appender name="ConsoleAppender" class="org.apache.log4j.ConsoleAppender">        <layout class="org.apache.log4j.PatternLayout">            <param name="ConversionPattern" value="%d{MM-dd HH:mm:ss.SSS} %5p [%t] (%F:%L)-%m%n" />        </layout>    </appender>    <appender name="FILE" class="org.apache.log4j.RollingFileAppender">        <param name="file" value="./logs/lingxi_ml.log" />        <param name="Append" value="false" />        <param name="MaxFileSize" value="10MB" />        <param name="MaxBackupIndex" value="10" />        <param name="encoding" value="UTF-8" />        <layout class="org.apache.log4j.PatternLayout">            <param name="ConversionPattern" value="%d{MM/dd HH:mm:ss.SSS}  %5p [%t] (%F:%L) -%m%n" />        </layout>    </appender>    <root>        <level value="debug" />        <appender-ref ref="ConsoleAppender" />        <!--<appender-ref ref="FILE" /> -->    </root>    <logger name="io.socket">        <level value="warn" />    </logger></log4j:configuration>

3.调试遇到的问题

3.1.slf4j存在多个绑定时出错

安装上述配置后,发现日志输出内容如下:
slf4j多个绑定时出错
根据框内提示,原因是发现了多个绑定关系,最终绑定了org.slf4j.impl.SimpleLoggerFactory这个东东。
检查maven文件,发现除了slf4j-log4j12外,还有个slf4j-simple,如下所示

        <dependency>            <groupId>org.slf4j</groupId>            <artifactId>slf4j-simple</artifactId>            <version>1.7.7</version>        </dependency>

去掉slf4j-simple的引用后,jul日志就可以通过log4j输出了

log4j:WARN Continuable parsing error 42 and column 23log4j:WARN 元素类型为 "log4j:configuration" 的内容必须匹配 "(renderer*,throwableRenderer?,appender*,plugin*,(category|logger)*,root?,(categoryFactory|loggerFactory)?)"06-12 10:19:09.252  WARN [main] (MyStaticValue.java:79)-not find library.properties in classpath use it by default !

3.1.1.意外验证,调整引用顺序竟然也对了

slf4j多个绑定时有告警,但仍然正确

3.2.官方文档解释

多个绑定的解释,原始英文参见官方文档,下面是个人消化后的理解

SLF4J只能绑定到一个日志组件,如果探测到多个日志组件,会进行告警

SLF4J API is designed to bind with one and only one underlying logging framework at a time. If more than one binding is present on the class path, SLF4J will emit a warning, listing the location of those bindings

但这仅仅是个告警,SLF4J会选择一个日志组件进行绑定,至于绑定哪个,看JVM了(根据我测试看,是按着加载顺序,绑定第一个)

The warning emitted by SLF4J is just that, a warning. Even when multiple bindings are present, SLF4J will pick one logging framework/implementation and bind with it. The way SLF4J picks a binding is determined by the JVM and for all practical purposes should be considered random. As of version 1.6.6, SLF4J will name the framework/implementation class it is actually bound to.

当出现多个组件告警时,简单去掉一个就可以了

When multiple bindings are available on the class path, select one and only one binding you wish to use, and remove the other bindings. For example, if you have both slf4j-simple-1.7.12.jar and slf4j-nop-1.7.12.jar on the class path and you wish to use the nop (no-operation) binding, then remove slf4j-simple-1.7.12.jar from the class path.

项目中引用一个框架或库时,框架或库可能会引入项目不需要的应用日志组件,例如cassandra-all version 0.8.1 声明了 log4j 和 slf4j-log4j12 作为 compile-time dependencies。但是又不想使用log4j作为SLF4J backend,可以通过修改maven排除掉这两个引用。

The list of locations that SLF4J provides in this warning usually provides sufficient information to identify the dependency transitively pulling in an unwanted SLF4J binding into your project. In your project’s pom.xml file, exclude this SLF4J binding when declaring the unscrupulous dependency. For example, cassandra-all version 0.8.1 declares both log4j and slf4j-log4j12 as compile-time dependencies. Thus, when you include cassandra-all as a dependency in your project, the cassandra-all declaration will cause both slf4j-log4j12.jar and log4j.jar to be pulled in as dependencies. In case you do not wish to use log4j as the the SLF4J backend, you can instruct Maven to exclude these two artifacts as shown next:

<dependencies>  <dependency>    <groupId> org.apache.cassandra</groupId>    <artifactId>cassandra-all</artifactId>    <version>0.8.1</version>    <exclusions>      <exclusion>         <groupId>org.slf4j</groupId>        <artifactId>slf4j-log4j12</artifactId>      </exclusion>      <exclusion>         <groupId>log4j</groupId>        <artifactId>log4j</artifactId>      </exclusion>    </exclusions>   </dependency></dependencies>

特别注意:引用的框架或库,不应该依赖于SLF4J binding,而是依赖slf4j-api。当一个库声明一个compile-time依赖SLF4J binding,会使SLF4J的目的失效。如果遇到这样的框架或库时,建议联系作者,告知其修改掉

Embedded components such as libraries or frameworks should not declare a dependency on any SLF4J binding but only depend on slf4j-api. When a library declares a compile-time dependency on a SLF4J binding, it imposes that binding on the end-user, thus negating SLF4J’s purpose. When you come across an embedded component declaring a compile-time dependency on any SLF4J binding, please take the time to contact the authors of said component/library and kindly ask them to mend their ways.

3.2.log4j:WARN 元素类型为 “log4j:configuration” 的内容必须匹配

碰到如下告警

log4j:WARN Continuable parsing error 42 and column 23log4j:WARN 元素类型为 "log4j:configuration" 的内容必须匹配 "(renderer*,throwableRenderer?,appender*,plugin*,(category|logger)*,root?,(categoryFactory|loggerFactory)?)"

原因:
在log4j的dtd中(默认为mavenlog4j.jar/org/apache/log4j/xml/log4j.dtd)),明确定义了每个元素的顺序

<!ELEMENT log4j:configuration (renderer*, throwableRenderer?,                               appender*,plugin*, (category|logger)*,root?,                               (categoryFactory|loggerFactory)?)>

所以在写的时候最好按照这个顺序
我把logger元素写在了logger元素上面,所以就报这个警告…

0 0