`

Log4j NDC MDC 区别及用法

 
阅读更多

Log4j NDC MDC 区别及用法

NDC(Nested Diagnostic Context)和MDC(Mapped Diagnostic Context)是log4j种非常有用的两个类,它们用于存储应用程序的上下文信息(context infomation),从而便于在log中使用这些上下文信息。
NDC采用了一个类似栈的机制来push和pop上下文信息,每一个线程都独立地储存上下文信息。比如说一个servlet就可以针对每一个request创建对应的NDC,储存客户端地址等等信息。
当使用的时候,我们要尽可能确保在进入一个context的时候,把相关的信息使用NDC.push(message);在离开这个context的时候使用NDC.pop()将信息删除。另外由于设计上的一些问题,还需要保证在当前thread结束的时候使用NDC.remove()清除内存,否则会产生内存泄漏的问题。
存储了上下文信息之后,我们就可以在log的时候将信息输出。在相应的PatternLayout中使用”%x”来输出存储的上下文信息,下面是一个PatternLayout的例子:
%r [%t] %-5p %c{2} %x - %m%n
使用NDC最重要的好处就是,当我们想输出一些上下文的信息的时候,不需要让logger去寻找这些信息,而只需要在适当的位置进行存储,然后再配置文件中修改PatternLayout。在最新的log4j 1.3版本中增加了一个org.apache.log4j.filters.NDCMatchFilter,用来
根据NDC中存储的信息接受或拒绝一条log信息。
MDC和NDC非常相似,所不同的是MDC内部使用了类似map的机制来存储信息,上下文信息也是每个线程独立地储存,所不同的是信息都是以它们的key值存储在”map”中。相对应的方法,MDC.put(key, value); MDC.remove(key); MDC.get(key); 在配置PatternLayout的时候使用:%x{key}来输出对应的value。同样地,MDC也有一个org.apache.log4j.filters.MDCMatchFilter。这里需要注意的一点,MDC是线程独立的,但是一个子线程会自动获得一个父线程MDC的copy。
至于选择NDC还是MDC要看需要存储的上下文信息是堆栈式的还是key/value形式的。
动态修改日志配置
在开发过程中,我们经常会遇到修改log4j配置的情况,在这种情况下,频繁重启应用显然是不可接受的。幸好log4j提供了自动重新加载配置文件的能力,在配置文件修改后,便会自己重新加载配置。在1.2及以前的版本中DOMConfigurator和PropertyConfigurator都提供了configureAndWatch方法,对指定的配置文件进行监控,并且可以设置检查的间隔时间。

NDC 介绍

NDC(Nested Diagnostic Context)是 Neil Harrison 在名为《Patterns for Logging Diagnostic Messages》的书中提出的嵌套诊断环境的机制。这种机制的提出,主要为了减少多线程的系统为每个客户单独记录日志的系统开销。在过去,区分两个客户的日志输出的常用方法是单独为每个客户机实例化新类别,但该方法会增加类别数量,并增加日志记录的管理开销。Neil Harrison 提出的方法就是把用户的上下文信息放到嵌套式诊断环境 (NDC) 中。

NDC 为每一个线程管理一个堆栈。开发人员可以在代码中合适的位置嵌入简单的 push 和 pop 方法,用来维护堆栈。通常 push 进堆栈的是可以唯一标示客户的上下文信息,如 SessionID 或者客户名称,IP 地址等。因为每个客户请求都会有单独的 NDC 堆栈,因此日志系统在输出的时候会根据每个线程找到对应的堆栈,并在输出日志的时候附加上堆栈内的信息。开发人员就可以很容易的在日志中区分出各个不同客户所产生的日志条目。

Log4J 从 1.2 起开始支持 NDC,org.apache.log4j.NDC 声明如下:


代码 5. NDC 声明代码

1. public class NDC {

2.     // 返回诊断堆栈的内容

3.     public static String get();

4.     // 从堆栈的顶端删除一个元素

5.     public static String pop();

6.     //在堆栈顶端加入一个元素

7.     public static void push(String message);

8.     //察看这个堆栈最顶层的元素,但不删除它

9.     public static String peek()

10.        // 删除这个线程的堆栈内容

11.        public static void remove();

12.    }

13.    

要注意的是,org.apache.log4j.NDC 类中所有的方法都是静态的。假设 NDC 日志输出功能被打开,每一次的日志请求,Log4J 组件都会把当前线程的整个 NDC 堆栈内容输出在日志条目中。这样的过程不需要开发人员写过多的代码,程序员只需要在代码中合适的地方通过 push 和 pop 方法将正确的信息放到 NDC 的堆栈中,然后通过修改 Log4J 的配置文件,指定用户标志信息输出的位置和格式,而原来 Java 代码中输出日志的代码不需要任何修改,就能够输出带有用户标志信息的日志。

在前面的 Log4J 使用示例 部分,我们曾经讲过 Log4J 配置文件中相应的配置信息,其中 PatternLayout 的 ConversionPattern 用于程序员指定日志输出的格式。要使用 NDC 的方式输出用户标志信息,只需要在 PatternLayout 的格式定义 ConversionPattern 中使用 %x,就能在相应的位置上输出 NDC 存储的上下文信息。具体的使用方法我们将在后面的 在 Web 应用中添加用户跟踪 部分进行介绍。

MDC介绍

MDC 和 NDC 相似,也可以减少多线程的系统为每个客户单独记录日志的系统开销。它同样是为每个线程建立一个独立的存储空间,开发人员可以根据需要把信息存入其中。不同的是 MDC 使用 Map 的机制来存储信息,信息以 key/value 对的形式存储在 Map 中。

Log4J 从 1.3 alpha 版本开始提供对 MDC 的支持,org.apache.log4j.MDC 声明如下:


代码 6. MDC 声明代码

1. public class MDC {

2.     // 清空map所有的条目。

3.     public static void clear();

4.     // 根据key值返回相应的对象

5.     public static object get(String key);

6.     //返回所有的key值.

7.     public static Enumeration getKeys();

8.     //把key值和关联的对象,插入map中

9.     public static void put(String key, Object val),

10.        //删除key对应的对象

11.        public static  remove(String key)

12.    }

13.    

MDC 和 NDC 的使用方法也类似,区别只是在 Log4J配置文件中,在通过 PatternLayout 的 ConversionPattern 来配置日志的格式的时候,需要使用 %x{key} 来输出相应的用户标志信息对象。

下面,我们通过具体的例子来说明如何在使用 Log4J 的 Web 应用中增加用户标志信息,达到进行用户跟踪的目的。在开发中,对于使用 NDC 还是 MDC 的机制,要看具体的应用在处理上下文信息的时候,是采用堆栈式的还是 Map 式的方便。下面我们以 NDC 为例进行说明。

在 Web 应用中添加用户跟踪

通常,开发人员会在系统的很多地方设置输出点,输出日志。如果要全面的修改这些输出点使日志条目附加上所需的信息,是一件繁重的工作。我们可以利用 Servlet 的 filter 来简化这项工作。Servlets Filter 是 Servlet 2.3 规范中出现的,它能截取用户从客户端提交的请求,并在请求没有到达真正需要访问的资源前运行一个指定的类。如果我们在这个类中实现 NDC 或 MDC 的功能,就可以大量简化日志修改的工作。下面的清单显示了实现这种修改所需的三个步骤。在这里,我们使用的是 NDC,您也可以使用 MDC 实现相同的功能。

在下面的例子中,介绍如何在前面已有的 Log4J 使用示例 的 Web 应用代码的基础上,通过为 Web 应用的 Servlet 增加一个 filter 的方法,将用户标志信息在 filter 中压入/弹出 NDC 堆栈,而不需要修改任何原来的 Java 程序中的输出日志的代码,使用起来非常简便。

第 1 步:增加一个处理 NDC 堆栈信息的 filter 类

本例通过在 filter 中取得访问该 Web 应用的客户机的IP地址,用以唯一地标识客户。您也可以和实际的应用程序代码相配合,使用更加人性化的方式来唯一标识客户,如取得 Session 中存储的客户名称等。


代码 7. 在 filter 中增加将用户标志信息放入 NDC 堆栈

1. package is.dsw.base.filter;

2. import javax.servlet.Filter;

3. import javax.servlet.http.HttpServletRequest;

4. import javax.servlet.http.HttpSession;

5. import org.apache.log4j.NDC;

6. public class Log4jNdcFilter implements Filter {

7. 

8. public void doFilter(ServletRequest request, ServletResponse response,

9.     FilterChain chain) throws IOException, ServletException {

10.        // 获得客户的网络地址

11.        String address = request.getRemoteAddr();

12.        // 把网络地址放入NDC中. 那么在在layout pattern 中通过使用 %x,就可在每条日之中增加网络地址的信息.

13.        NDC.push(address);

14.        //继续处理其他的filter链.

15.        chain.doFilter(req, res);

16.         // 从NDC的堆栈中删除网络地址.

17.        NDC.pop();

18.        }

19.    }

20.    

第 2 步:修改 Web 应用的 web.xml 文件

我们需要修改 Web 应用的 web.xml 文件,对 filter 进行设置。在 <web-app< 元素下面增加下列的代码行:


代码 8. 修改 web.xml 文件,增加 filter 配置

1. ……

2. <filter>

3.   <filter-name>NdcFilter</filter-name>

4.   <filter-class> is.dsw.base.filter.Log4jNdcFilter</filter-class>

5. </filter>

6. <filter-mapping>

7.   <filter-name>NdcFilter</filter-name>

8.   <url-pattern>/*</url-pattern>

9. </filter-mapping>

10.    ……

11.    

上述 XML 中的 url-pattern 元素与这个 Web 应用中的所有 URL 匹配。如果只想应用于部分 URL,可以相应地调整模式。

第 3 步:修改 Log4J 的配置文件

需要对 Log4J.properties 文件的配置做一些改变,以便看到 NDC 上下文。在 NDC 简介部分,我们曾经说过,%x 表示会在每个日志行上打印当前 NDC 上下文。我们对 Log4J使用示例 中的 Log4J.properties配置文件 进行如下修改,在 PatternLayout 的格式定义 ConversionPattern 中增加 %x, 将 NDC 堆栈中的信息在 %x 指定的位置上进行输出。如下:


代码 9. Log4J 配置文件中修改 PatternLayout 的输出格式

1. log4j.appender.A1.layout.ConversionPattern=%d %p %c %x - %m%n

完成以上修改之后,每一条记录都会把我们在 Filter 中 push 进 NDC 堆栈的内容打印出来。仍然以 Log4J 使用示例 中的三个并发用户访问为例,我们可以得到如下的日志信息,和前面不使用 NDC 的方式下 打印的日志信息相比较,可以看到在原来日志的基础上增加了客户机 IP 地址,这样可以很容易地区分不同的用户的信息,为我们进行日志分析和用户跟踪打下了很好的基础。

 

 

分享到:
评论

相关推荐

    log4j-API-最新稳定版本log4j-1.2.17

    标题提及的是"log4j-API-最新稳定版本log4j-1.2.17",这表明我们关注的是日志框架Log4j的一个特定版本,即1.2.17。Log4j是Apache软件基金会开发的一个用于Java应用程序的日志记录工具,它提供了灵活的日志记录功能,...

    log4j简单使用

    - `log4j-1.2.14.jar`: 这是Log4j 1.2.14版本的jar包,包含了Log4j的全部类和方法,是使用Log4j进行日志记录的核心组件。 - `commons-logging-1.0.4.jar`: 这是Apache Commons Logging库,它是Java日志API的一个抽象...

    Log4J完整说明和配置

    本文将围绕一份示例配置文件来详细介绍Log4J的配置方法。 #### 二、核心概念 在深入分析配置文件之前,我们先了解几个Log4J中的核心概念: - **Logger**:负责接收并处理日志信息的对象。 - **Appender**:指定日志...

    log4j jarjar包

    本文将深入探讨Log4j的核心概念,以及如何在项目中使用log4j-1.2.16.jar这个关键的jar包。 一、Log4j简介 Log4j是由Apache软件基金会开发的一个开源日志组件,主要服务于Java平台。它的设计目标是提供一个灵活且...

    java-日志-log4j.7z

    此外,Log4j还支持MDC(Mapped Diagnostic Context)和NDC(Nested Diagnostic Context),这些特性可以附加上下文信息到日志记录中,对于调试多线程和分布式系统非常有用。 如果你对Log4j的具体使用还有疑问,可以...

    log4j多个简单实例

    MDC(Mapped Diagnostic Context)和NDC(Nested Diagnostic Context)是Log4j提供的上下文诊断工具。它们可以用来存储与线程相关的诊断信息,便于在复杂环境中追踪问题。 通过以上实例,你已经了解了Log4j的基本...

    log4j-slf4j-impl.zip

    本文将深入探讨Log4j-SLF4J-Impl这一关键组件,解析其工作原理和使用方法,帮助开发者更好地理解和利用这一工具。 一、Log4j-SLF4J-Impl简介 "Log4j-slf4j-impl.zip"这个压缩包中包含的是Log4j对SLF4J接口的实现,...

    log4j配置详解与使用方法说明

    本文将深入探讨Log4j的配置与使用方法。 ### 一、Log4j概述 Log4j 是一个灵活的日志框架,支持多种输出格式,如控制台、文件、数据库等。它提供了丰富的日志级别(DEBUG、INFO、WARN、ERROR、FATAL),以及自定义...

    log4j-2.11.1.jar

    本文将深入探讨Log4j 2.11.1的核心特性和使用方法。 1. **核心组件与架构** - **Loggers**: 日志记录器是Log4j 的核心组件,负责接收日志事件并将其传递给适当的Appender。 - **Appenders**: Appender 是负责将...

    log4j-1.2.17含源码

    本文将对"Log4j 1.2.17含源码"进行深入探讨,包括其核心组件、配置、使用方法以及源码分析。 首先,Log4j的核心组件主要包括Appender、Layout、Logger和Level。Appender负责输出日志信息到指定的目标,如控制台、...

    log4j-1.2.17

    《深入理解log4j-1.2.17:构建高效日志系统的关键》 在IT行业中,日志记录是至关重要的,它为系统监控、故障排查和性能优化提供了宝贵的线索。Apache Log4j作为Java领域中最广泛使用的日志框架之一,其1.2.17版本...

    Log4j2 web demo (log4j2 version 2.1)

    Log4j2允许你基于MDC(Mapped Diagnostic Context)或NDC(Nested Diagnostic Context)进行日志过滤。例如,你可以添加一个MDC键值对来区分不同的用户请求: ```java MDC.put("userId", "123456"); // 记录日志 ...

    log4j使用实例.zip

    这个"log4j使用实例.zip"压缩包包含了关于如何在Java项目中配置和使用Log4j的示例代码,非常适合Java后端初学者学习。 首先,Log4j的核心组件包括Logger、Appender和Layout。Logger是日志信息的生产者,负责生成...

    log4j-1.2.9.jar

    本文将围绕“log4j-1.2.9.jar”这一特定版本,详细探讨其核心概念、功能以及使用方法,帮助读者深化对Log4j的理解。 一、Log4j简介 Log4j是Apache软件基金会的一个开源项目,它提供了一种灵活且强大的日志记录解决...

    log4j入门、详解

    **日志框架Log4j详解** 日志框架在软件开发中扮演着至关重要的角色,它提供了记录应用程序运行过程中的各种事件的功能,便于调试、监控和问题排查。Log4j是Apache组织开发的一个开源的日志记录工具,广泛应用于Java...

    log4j使用例子和文档

    提供的文档应该详细介绍了Log4j的配置、使用方法以及高级特性,如自定义Appender、过滤器、异步日志等。建议仔细阅读并实践,以更好地理解和掌握Log4j的使用。 ### 5. 进阶应用 - **过滤器(Filters)**: 可以根据...

    J2EE复习积累(四)-Log4J

    ** 描述中的"NULL"意味着没有提供具体的博客内容摘要,但我们可以通过标题推测,这篇博客可能包含了作者在学习或使用J2EE过程中对Log4J的理解和经验积累,可能会涵盖Log4J的基本概念、配置、使用方法以及一些高级...

    Log4j笔记 第九章 封装Log4j

    - 在工厂类中,使用`org.apache.log4j.Logger.getLogger()`方法根据类名创建Logger实例。 - 配置log4j.properties或log4j.xml文件,设置全局的日志级别、Appender和Layout。 4. **示例代码** ```java public ...

    log4j的jar包

    这个版本的JAR文件是Log4j的核心库,包含了所有用于日志记录的类和方法。开发人员可以将这个JAR文件添加到他们的Java项目的类路径中,以便利用Log4j的功能。 描述还提到了"一个参考配置文件",这通常是指Log4j的...

    手把手教你使用log4j

    Log4j是Java平台上广泛使用的日志记录框架,尤其在企业级应用开发中不可或缺。本教程将深入浅出地教你如何有效地利用log4j进行日志管理,包括配置、API使用以及实践中的最佳实践。 首先,理解Log4j的基本概念至关...

Global site tag (gtag.js) - Google Analytics