最近使用log4j库,由于需要输出xml格式的日志文件,有关输出MDC和NDC内容,折腾了整整一天,最后还是切换使用log4j2.x才能够成功。网上搜索了很久都没能找到原因,国内外搜了上百篇,借鉴一些帖子,然后推断出了原因。现整理如下,作为备忘录。
1、下载log4j-1.2.17.jar,可以到网站http://mvnrepository.com/搜索,这个网站的jar包很全。
2、使用eclpise创建一个工程,把log4j-1.2.17.jar加上。
3、编写Log类,代码如下:
import org.apache.log4j.Logger;
import org.apache.log4j.MDC;
import org.apache.log4j.NDC;
import org.apache.log4j.PropertyConfigurator;
import org.apache.log4j.xml.DOMConfigurator;
public class Log {
public static void main(String[] args) {
Logger log = Logger.getRootLogger();
DOMConfigurator.configureAndWatch("log4j.xml");
log.debug("Sample debug message");
log.info("Sample info message");
log.error("Sample error message");
log.fatal("Sample fatal message");
}
}
配置文件,输出格式xml文件,因此需要需要使用org.apache.log4j.xml.XMLLayout。如下:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration debug="false" xmlns:log4j='http://jakarta.apache.org/log4j/'>
<appender name="FILE" class="org.apache.log4j.RollingFileAppender">
<param name="threshold" value="debug" />
<param name="file" value="log4jlog.xml" />
<param name="maxBackupIndex" value="5" />
<param name="append" value="true" />
<layout class="org.apache.log4j.xml.XMLLayout">
</layout>
</appender>
<root>
<level value="DEBUG" />
<appender-ref ref="FILE" />
</root>
</log4j:configuration>
运行输出:
<log4j:event logger="root" timestamp="1468679895876" level="DEBUG" thread="main">
<log4j:message><![CDATA[Sample debug message]]></log4j:message>
</log4j:event>
<log4j:event logger="root" timestamp="1468679895877" level="INFO" thread="main">
<log4j:message><![CDATA[Sample info message]]></log4j:message>
</log4j:event>
<log4j:event logger="root" timestamp="1468679895878" level="ERROR" thread="main">
<log4j:message><![CDATA[Sample error message]]></log4j:message>
</log4j:event>
<log4j:event logger="root" timestamp="1468679895878" level="FATAL" thread="main">
<log4j:message><![CDATA[Sample fatal message]]></log4j:message>
</log4j:event>
4、在多线程环境中,有需要需要打印线程信息,就需要使用MDC或NDC(网上有概念介绍),网上实例都是PatternLayout介绍的,没有针对XMLLayout。代码如下:
import org.apache.log4j.Logger;
import org.apache.log4j.MDC;
import org.apache.log4j.NDC;
import org.apache.log4j.PropertyConfigurator;
import org.apache.log4j.xml.DOMConfigurator;
public class Log {
public static void main(String[] args) {
Logger log = Logger.getRootLogger();
MDC.put("key", "value");
MDC.put("key2", "value2");
NDC.push("haha");
DOMConfigurator.configureAndWatch("og4j.xml");
log.debug("Sample debug message");
log.info("Sample info message");
log.error("Sample error message");
log.fatal("Sample fatal message");
NDC.clear();
MDC.clear();
}
}
<log4j:event logger="root" timestamp="1468680531531" level="DEBUG" thread="main">
<log4j:message><![CDATA[Sample debug message]]></log4j:message>
<log4j:NDC><![CDATA[haha]]></log4j:NDC>
</log4j:event>
<log4j:event logger="root" timestamp="1468680531532" level="INFO" thread="main">
<log4j:message><![CDATA[Sample info message]]></log4j:message>
<log4j:NDC><![CDATA[haha]]></log4j:NDC>
</log4j:event>
<log4j:event logger="root" timestamp="1468680531532" level="ERROR" thread="main">
<log4j:message><![CDATA[Sample error message]]></log4j:message>
<log4j:NDC><![CDATA[haha]]></log4j:NDC>
</log4j:event>
<log4j:event logger="root" timestamp="1468680531532" level="FATAL" thread="main">
<log4j:message><![CDATA[Sample fatal message]]></log4j:message>
<log4j:NDC><![CDATA[haha]]></log4j:NDC>
</log4j:event>
从输出来看,MDC的内容没有输出,原因是选项开关没打开,这个还是通过看源代码猜到的原因,配置参数为Properties,把这个值设为true(LocationInfo选项是当前函数信息,这个挺有用的)。log4j.jar版本很多,犯了一个基本错误,开始用了老版本jar始终不能解决问题,居然以为log4j-1.2.9比log4j-1.2.17新。等我弄好了log4j2再回头long4j1的时候,才发现版本弄错了,浪费了一整天的时间。
修改的xml配置文件如下:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration debug="false" xmlns:log4j='http://jakarta.apache.org/log4j/'>
<appender name="FILE" class="org.apache.log4j.RollingFileAppender">
<param name="threshold" value="debug" />
<param name="file" value="log4jlog.xml" />
<param name="maxBackupIndex" value="5" />
<param name="append" value="true" />
<layout class="org.apache.log4j.xml.XMLLayout">
<param name="LocationInfo" value="true" />
<param name="Properties" value="true" />
</layout>
</appender>
<root>
<level value="DEBUG" />
<appender-ref ref="FILE" />
</root>
</log4j:configuration>
重新运行,输出对了,MDC这个关键字并没有输出,使用log4cxx是有的,原因是新版本好像改掉了。但现在还有个问题,如果需要输出MDC,就只有扩展appender了。
<log4j:event logger="root" timestamp="1468680646638" level="DEBUG" thread="main">
<log4j:message><![CDATA[Sample debug message]]></log4j:message>
<log4j:NDC><![CDATA[haha]]></log4j:NDC>
<log4j:locationInfo class="testlog4j.Log" method="main" file="Log.java" line="22"/>
<log4j:properties>
<log4j:data name="key" value="value"/>
<log4j:data name="key2" value="value2"/>
</log4j:properties>
</log4j:event>
<log4j:event logger="root" timestamp="1468680646641" level="INFO" thread="main">
<log4j:message><![CDATA[Sample info message]]></log4j:message>
<log4j:NDC><![CDATA[haha]]></log4j:NDC>
<log4j:locationInfo class="testlog4j.Log" method="main" file="Log.java" line="23"/>
<log4j:properties>
<log4j:data name="key" value="value"/>
<log4j:data name="key2" value="value2"/>
</log4j:properties>
</log4j:event>
<log4j:event logger="root" timestamp="1468680646641" level="ERROR" thread="main">
<log4j:message><![CDATA[Sample error message]]></log4j:message>
<log4j:NDC><![CDATA[haha]]></log4j:NDC>
<log4j:locationInfo class="testlog4j.Log" method="main" file="Log.java" line="24"/>
<log4j:properties>
<log4j:data name="key" value="value"/>
<log4j:data name="key2" value="value2"/>
</log4j:properties>
</log4j:event>
<log4j:event logger="root" timestamp="1468680646641" level="FATAL" thread="main">
<log4j:message><![CDATA[Sample fatal message]]></log4j:message>
<log4j:NDC><![CDATA[haha]]></log4j:NDC>
<log4j:locationInfo class="testlog4j.Log" method="main" file="Log.java" line="25"/>
<log4j:properties>
<log4j:data name="key" value="value"/>
<log4j:data name="key2" value="value2"/>
</log4j:properties>
</log4j:event>
结论:java不熟悉,麻烦的不是java,而是第三方库的使用,总感觉通过xml配置麻烦,不如直接用api来得直观。可能是用c++用惯了,总是想从基本原理看起,快速搭建环境。log4j的配置,也可以通过properties文件实现。上述的配置文件也可以写成:
# Define the root logger with file appender
log4j.rootLogger = DEBUG, XML
# Define the file appender
log4j.appender.XML=org.apache.log4j.FileAppender
log4j.appender.XML.File=log4jlog.xml
# Define the xml layout for file appender
log4j.appender.XML.layout=org.apache.log4j.xml.XMLLayout
log4j.appender.XML.layout.LocationInfo=true
log4j.appender.XML.layout.Properties=true
log4j.appender.XML.Threshold=DEBUG
使用下面的代码进行读取配置文件,配置文件的路径可以依据你的工程指定,可以使用绝对路径:
PropertyConfigurator.configure("log4j.properties");