在
多用户并发的环境下,通常是由不同的线程分别处理不同的客户端请求。此时要在日志信息中区分出不同的客户端,你可以为每一个线程生成一个Logger,从
而从一堆日志信息中区分出哪些信息是属于哪个线程的,但这种方式并不高效。Log4J巧妙地使用了Neil
Harrison提出的“NDC(嵌套诊断环境)”机制来解决这个问题。Log4J为同一类别的线程生成一个Logger,多个线程共享使用,而它仅在日
志信息中添加能够区分不同线程的信息。NDC是什么?举例来说,如果一个Servlet接到并发请求时,为每一个客户端创建一个新的线程,然后分配一个用
于保存该请求上下文的NDC堆栈。该上下文可能是发出请求的主机名、IP地址或其它任何可以用于标识该请求的信息。这样,由于不同的客户端处理线程具有不
同的NDC堆栈,即使这个Servlet同时生成多个线程处理不同的请求,这些日志信息仍然可以区分出来,就好像Log4J为每一个线程都单独生成了一个
Logger实例一样。在Log4J中是通过org.apache.log4j.NDC实现这种机制的。使用NDC的方法也很简单,步骤如下:
1. 在进入一个环境时调用NDC.push(String),然后创建一个NDC;
2. 所做的日志操作输出中包括了NDC的信息;
3. 离开该环境时调用NDC.pop方法;
4. 当从一个线程中退出时调用NDC.remove方法,以便释放资源。
下面是一个模拟记录来自不同客户端请求事件的例子,代码如下:
import org.apache.log4j.Logger;
import org.apache.log4j.NDC;
public class TestNDC {
static Logger log = Logger.getLogger(TestNDC.class.getName());
public static void main(String[] args) {
log.info("Make sure %x is in your layout pattern!");
// 从客户端获得IP地址的例子
String[] ips = {"192.168.0.10","192.168.0.27"};
for (int i = 0; i<ips.length ; i++) // 模拟一个运行方法
{
// 将IP放进 NDC中
NDC.push(ips[i]);
log.info("A NEW client connected, who's ip should appear in this log message.");
NDC.pop();
}
NDC.remove();
log.info("Finished.");
}
}
注意配置文件中的布局格式中一定要加上%x。系统输出如下:
INFO - Make sure %x is in your layout pattern!
INFO 192.168.0.10 - A NEW client connected, who's ip should appear in this log message.
INFO 192.168.0.27 - A NEW client connected, who's ip should appear in this log message.
INFO - Finished.