原文地址http://www.onjava.com/pub/a/onjava/
一些高级功能
JDBCAppender
接下去我们将要把log纪录到console和屏幕以外的地方。因为数据库log相当的流行,就让我们来看看我们如何修改我们的简单的例子log到数据库中去。这个例子是基于MySql上的,但是只要你有相应正确的JDBC驱动它实际上可以在任何数据库上运行。(注意:当前版本的log4j关于JDBCAppender有一个提醒,文档中指出在将来JDBCAppender将要被全部修订版替换。虽然它的内部实现可能完全不同了,但对于使用者来说使用是不一定会有改变的)
打开我们例子应用中的config-JDBC.properties文件。第一句没有什么特别。作为一个简单的例子我们设置root logger的等级是DEBUG等级,并为它添加一个appender,R.下面的几行就是把R定义成JDBC类型,并且修改它的一些相关属性
log4j.appender.R=org.apache.log4j.jdbc.JDBCAppender
log4j.appender.R.URL=jdbc:mysql://localhost/LOG4JDemo
log4j.appender.R.user=default
log4j.appender.R.password=default
log4j.appender.R.sql=INSERT INTO JDBCTEST (Message) VALUES ('%d - %c - %p - %m')
第一行告诉log4j R是JDBCAppender类型的。第二行定义所使用的数据库的位置。第三,四行设置数据库的用户名密码。最后一行是一条SQL的执行语句,我们下面将详细描述它。
对于之前使用过JDBC的开发者来说以上的使用方法已经相当熟悉了。在任何的使用到JDBC的应用中都要定义上述的属性。当然你要根据具体你自己的环境来修改这些参数。例如你使用的是Oracle,URL就应该变为jdbc:oracle:thin:@yourhostDIS.另外一点需要注意的是,相应的JDBC驱动应该在你的应用可以正确加载到的位置。
现在让我们来讨论一下最后一条语句。这条你用来把LOG插入数据库的的SQL语句可以根据你的需求进行各式各样的修改。语句中指出LOG中使用的表JDBCTEST: date(%d), ategory/logger(%c), priority(%p); 以及实际被记录的属性message(%m).log4j载入这个语句然后根据相应的layout再匹配上一实际的值转换成正确的格式。Log4j就可以轻松的执行这条SQL了。
如果有需要你可以LOG不同属性的多个值,下面是一条正确的例子
INSERT INTO JDBCTEST (Date, Logger, Priority, Message) VALUES ('%d', '%c', '%p', '%m')
这就意味着在我们的数据库中JDBCTEST表格中拥有相应的属性列Date, Logger, Priority, 和 Message。你可以通过在config-JDBC.properties中设置相应的JDBCl路径的属性来测试你的应用。
然后接下去我们要在代码中进行哪些修改来完成往数据库中进行LOG吗,答案是:不需要。这正是LOG4J强大之处。往数据库中进行LOG我们不需要添加任何的代码,我们只需要使用不同的配置文件,先前打印到控制台的LOG信息就可以直接转入到数据库中了。
NDC/MDC
Nested Diagnostic Context (NDC) 和 Mapped Diagnostic Context (MDC)在多客户端同时访问服务器的情况下可以帮助我们区别出来自不同的客户端的LOG内容。WEB应用在这方面是个很好的例子。
我们应该如何区别不同客户端的LOG呢?让我们在LOG上加入不同客户端的信息。在典型的WEB应用中,可以包括一些其他信息,例如IP地址等等servlet容器可以确实拿到的信息。所以在NDC中,在进入一个环境时调用NDC.push(String),然后创建一个NDC,离开该环境时调用NDC.pop方法其间的所有LOG输出都包括了NDC的信息。如果在相关的layout中你使用了x%这类标记,Log4j在写向appender的时候会关联到相关的信息。让我们看看它是如何工作的。我们配置文件(config-NDC.properties)和程序代码(GetCommentsServlet.java)
config-NDC 文件有一个和之前的配置文件不同的地方。前面几行和config-simple文件是相同的,说明了我们要做什么除GetCommentsServlet的以外的Logger都是简单的输出在console上的。而GetCommentsServlet使用了一个特殊的appender (R1)同样是输出到屏幕上不过他的输出形式中含有%x标记。
log4j.logger.demo.log4j.servlet.GetCommentsServlet=debug, R1
...
log4j.appender.R1.layout.ConversionPattern=%p - [%x] - %m%n
注意我们是如何设置GetCommentsServlet的logger的。所有的logger都可以通过log4j.logger.<logger名称>来取得索引(除了root logger 是通过log4j.rootLogger获取的)。
GetCommentsServlet的代码向我们展示了通过对NDC stack的push和pop操作使用NDC的方法。
注意40和57行。在40行我们push了客户端相关信息入栈。接下去的所有LOG语句都将包含这个通过%x标志转换的信息。在57行我们pop这个信息出栈。之后的log将不带有客户端相关信息。
我们再来讨论一下Mapped Diagnostic Context (MDC)。MDC和NDC相似,MDC用一个map(java.util.map)来代替了NDC的push和pop操作。这使得实现必须是一个唯一的KEY对应每个相应的客户信息。GetCommentsServlet.java的43行就是一个具体的实现。
MDC.put("RemoteHost", remHost);
MDC类提供一个static的方法来操作MAP中的client-specific信息.所以每个发到appender的log 语句的RemoteHost信息将被%x{key}形式的信息所替代。那么这个KEY是什么呢?这个KEY就是我们向MAP插入remHost的值的的对应的那个KEY。例如我们想要在输出中加入RemoteAddress信息可以加入以下代码。
MDC.put("RemoteAddress",
req.getRemoteAddr());
在配置文件中加入以下
%X{RemoteAddress}
一个MDC的例子在config-MDC.properties文件。虽然它和config-NDC.properties很相似。但是他们有两个很大的不同。一,我们用MDC替代了NDC,二,第二个logger的appender是RollingFileAppender而不是ConsoleAppender。
相关技巧
第一条技巧,如果你打算使用log4j应该知道log4j的邮件列表中间有许许多多的技巧。你可以在Mail Archive得到保存的邮件,也可以向列表发出自己的问题。
下面是一些具体的小技巧
- ConfigureAndWatch:你必须注意每次修改完配置文件,你都必要要重新启动你的应用。这有一点点麻烦。如果你有需要LOG4J提供了一个可以监视配置配置文件改变的机制。用PropertyConfigurator.configureAndWatch(props)替换PropertyConfigurator.configure(props),默认60秒检查一下configuration file的改变。
Additivity: 如果你检查config-MDC 和 config-NDC文件你可以发现他们都有下面这条语句log4j.additivity.demo.log4j.servlet.GetCommentsServlet=false
什么是additivity为什么我们要把这个值设置成false呢。Loggers默认他们的appenders都是继承自他们的父类。所以demo.log4j.servlet.GetCommentsServlet也是一样继承自R,rootLogger的appender.这意味着所有GetCommentsServlet logger发起的log都将经过两个appender.一个是它自己的appender一个是它继承的那个。所以消息会被输出两次。这不一定是你想要的效果。这样的一条语句保证每个信息只输出一次
资源
在log4j的官方网站上有学习log4j 的资源,也有log4j的代码,一份使用手册。还有内容丰富的mailing list.
总结
Log4j是一个流行的在Apache旗下开发中使用的log工具.JDK1.4以后提供了它自己的logAPI .然而Log4j比他们经过更加长时间的考验.log4j提供了LOG相关的各个方面的控制,提供一份实际中非常有有的等级制度.提供了不用修改代码就可以控制log的方法.
我希望这篇文章可以给你一些使用log4j的指导,并且帮助你熟悉使用其中的一些高级功能,无论如何,学习log4j的最佳方法是实际使用.运用一个实际的例子作为开始.修改配置文件,添加删除appender,使用layout等等.这些都将帮助你对log4j的理解和实际使用. GOOD LUCK!