在現實的場景中常常有這樣的需求,在紛繁的日誌文件中,經過搜索某一個關鍵字(如訂單號),能方便清晰的列出某一業務(如支付)的完整的處理流程。java
一個笨辦法是在每一個日誌中加上該關鍵字,以下所示:apache
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便可。見以下示例代碼:app
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取消息)。以下所示:spa
<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差很少,仍沿用上述示例,僅需部分改動:code
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,以下所示:orm
<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。xml