巧用CurrentThread.Name來統一標識日志記錄(java-logback篇)


                            _       
                           | |      
  __ _  __ _  ___ _ __   __| | __ _ 
 / _` |/ _` |/ _ \ '_ \ / _` |/ _` |
| (_| | (_| |  __/ | | | (_| | (_| |
 \__,_|\__, |\___|_| |_|\__,_|\__,_|
        __/ |                       
       |___/                        

▄︻┻┳═一巧用CurrentThread.Name來統一標識日志記錄

▄︻┻┳═一巧用CurrentThread.Name來統一標識日志記錄(續)

▄︻┻┳═一巧用CurrentThread.Name來統一標識日志記錄(完結篇)

▄︻┻┳═一asp.net攔截器

▄︻┻┳═一巧用CurrentThread.Name來統一標識日志記錄(java-logback篇)


 

java版本支付中心,日志組件使用的是logback。logback.xml里日志pattern配置如下:

    <!--本地日志目錄-->
    <property name="USER_HOME" value="${catalina.base}/logs/logback-srv" />
    <property name="LOG_MSG" value="%X{sid}%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5p [%c] - %m%n" />
    <property name="LOG_DIR" value="${USER_HOME}/%d{yyyyMMdd}"/>
    <!--2017-08-22 10:43:19.307 [DubboServerHandler-10.0.0.178:38001-thread-187] INFO  [com.emax.paycenter.backend.facade.IPayCenterFacadeImpl]-->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>${LOG_MSG}</pattern>
        </encoder>
    </appender>

 

pattern里有%t,即代表的是線程Id(起初,我誤認為這個%t指的是線程Id!!!),而每一筆交易請求的處理是在一個單獨的線程里,那么它就可以標記每一筆交易請求對應的所有日志。日志文件截圖如下:

分析日志發現,這個線程標識如截圖里的“DubboServerHandler-10.0.0.178:38001-thread-195”會被不同的交易請求重用,不能唯一標記一次請求的所有處理日志,這顯然加大了線上問題的排障難度。昨天晚上,項目組里我們2人決定要針對這一點不足做一次改進。

之前的.net版支付中心,我對統一標記一筆交易請求的所有日志做過一次重構,見巧用CurrentThread.Name來統一標識日志記錄】顯然,java的也有必要用一個唯一的標識來標記一筆交易請求的所有日志。

當前線程的線程Id是只讀的,我們改不了。那該怎么實現呢?
此前.net的經驗告訴我用currentThread的Name屬性來搞。可是問題來了,我在交易處理的第一個語句里給當前線程名賦值后,此后的各module各方法里的每一條log.info語句都要顯式記錄上當前線程名,改動太多了。而且,這樣的代碼不免有股怪怪的味道。
當然,另一個辦法是按照.net版那種思路,做個日志代理類,對上面的調用log.info並顯式記錄當前線程名做個封裝,然后,邏輯代碼里記日志就調用這個代理類。這樣實現的弊端與上面的方案半斤八兩。

那怎么辦呢?

問唄。
先問度娘,無解。
接着問同事,說可能要自己寫一個apperder。對logback底層代碼的未知會加大解決問題的難度。
【百度:logback 自定義appender
讀logback源碼系列文章(五)——Appender http://kyfxbl.iteye.com/blog/1173788】

無心插柳

我早上上班后,先了解了一下構造一個唯一字符串標識來給當前線程名賦值。然后在交易處理的的第一個語句前,寫了如下兩行代碼,

public BaseResponse invoke(String requestJSON, BaseRequest baseRequest) throws Exception {
        String threadName = String.format("%s_%s_%s", baseRequest.getMethod(), new SimpleDateFormat("HHmmssS").format(new Date()), UUID.randomUUID().toString().toUpperCase().substring(0, 5)); Thread.currentThread().setName(threadName);

        log.info("#IPayCenterFacadeImpl,調用服務:{}", baseRequest.getMethod());
        log.info("#IPayCenterFacadeImpl,請求參數:{}", requestJSON);
        //1.獲取API接口實現
        IPayCenterApi payCenterApi = (IPayCenterApi) payCenterServiceFactory.getService(baseRequest.getMethod());

        //2.處理業務邏輯
        BaseResponse result = payCenterApi.handle(requestJSON);

        return result;
    }

 

不經意間,在運行代碼時,我發現%t那段的線程信息標識是我給當前線程名設置的那個字符串標識。
這才發現,%t或%thread輸出的原來是產生日志的線程名!!

【調試代碼可知 Thread.currentThread().getName():DubboServerHandler-192.168.40.80:28005-thread-2,Thread.currentThread().getId():246】

經過了這個波折,我們的問題最終得到解決,興奮異常。看看下面的日志截圖,一股強烈的成就感油然而生 O(∩_∩)O

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM