log4j 的一个实用工具类--NDC–可在每个日志前自动加上一个tag--介绍
博客专区 > zgw06629 的博客 > 博客详情
log4j 的一个实用工具类--NDC–可在每个日志前自动加上一个tag--介绍
zgw06629 发表于3年前
log4j 的一个实用工具类--NDC–可在每个日志前自动加上一个tag--介绍
  • 发表于 3年前
  • 阅读 81
  • 收藏 0
  • 点赞 0
  • 评论 0

在现实的场景中经常有这样的需求,在纷繁的日志文件中,通过搜索某一个关键字(如订单号),能方便清晰的列出某一业务(如支付)的完整的处理流程。

一个笨办法是在每个日志中加上该关键字,如下所示:

logger.info("[{}] entering pay",orderId);
logger.info("[{}] check whether order is repeated ",orderId);
logger.info("[{}] save order to db",orderId);
logger.error("[{}]", orderId, e);
......

有没有更方便的方法满足这一业务要求呢? 而不用这么麻烦要在每个日志中都要显式加上tag,所幸log4j自身就提供了这么一个方便易用的工具类--NDC。

只要在入口方法中设置tag,离开方法前remove即可。见如下示例代码:

protected static final Logger logger = LoggerFactory
            .getLogger(NDCDemo.class);
    void test1(long orderId){ //入口方法
        NDC.push("["+orderId+"]"); //进入方法设置tag
        logger.info("entering test1"); //正常记录日志 无需显式添加tag
        test2();
        test3();
        test6();
        NDC.remove(); //离开方法删除tag
    }
    private void test6() {
        logger.info("entering test6");
    }
    private void test3() {
        logger.info("entering test3");
        test5();
    }
    private void test5() {
        logger.info("entering test5");
    }
    private void test2() {
        logger.info("entering test2");
        test4();
    }
    private void test4() {
        logger.info("entering test4");
    }
    public static void main(String[] args) {       
        NDCDemo app = new NDCDemo();
        app.test1(System.currentTimeMillis());
    }

以及日志输出,注意每个日志信息前都有了上述代码所设置的tag。

[04 21:10:02,032 INFO ] [main] com.tcl.gateway.log4j.NDCDemo - [1428153002029]-entering test1
[04 21:10:02,035 INFO ] [main] com.tcl.gateway.log4j.NDCDemo - [1428153002029]-entering test2
[04 21:10:02,035 INFO ] [main] com.tcl.gateway.log4j.NDCDemo - [1428153002029]-entering test4
[04 21:10:02,035 INFO ] [main] com.tcl.gateway.log4j.NDCDemo - [1428153002029]-entering test3
[04 21:10:02,035 INFO ] [main] com.tcl.gateway.log4j.NDCDemo - [1428153002029]-entering test5
[04 21:10:02,035 INFO ] [main] com.tcl.gateway.log4j.NDCDemo - [1428153002029]-entering test6

同时配置文件中输出模板需要添加一个字符x(表示从NDC取消息)。如下所示:

<layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" 
                value="[%d{dd HH:mm:ss,SSS\} %-5p] [%t] %c - %x-%m%n" />
        </layout>

这样的话即使在多用户并发的情况下(如servlet和dubbo service)也容易根据某一关键字(如订单号、ip)来定位出完整的业务链。

另外除了NDC外还有一个工具类--MDC–也适用于这一场景,使用方式和NDC差不多,仍沿用上述示例,仅需部分改动:

void test1(int orderId){
        MDC.put("orderId", "["+orderId+"]"); // NDC.push --> MDC.put(key , value)
        logger.info("entering test1");
        test2();
        test3();
        test6();
        MDC.remove("orderId"); //NDC.remove --> MDC.remove(key)
    }

配置文件的输出模板中加一个X,如下所示:

<layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" 
                value="[%d{dd HH:mm:ss,SSS\} %-5p] [%t] %c -%X{orderId}-%m%n" />
        </layout>

另外他们两者的区别及更多用法见各自的javadoc。

标签: log4j NDC MDC
共有 人打赏支持
粉丝 14
博文 54
码字总数 30471
×
zgw06629
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: