首頁 > 軟體

java log is判斷引發的一系列事件解析

2022-11-07 14:00:19

首先來源是 老大code Review的時候 說到紀錄檔,讓我從 log.debug 加上一個if 判斷,log.isDebug ,這一聽就想到是 為了防止debug 紀錄檔不列印,導致的String拼接等 沒必要的損耗

嗯嗯 老大說的確實有道理,改吧

我靠,這一查幾百個 log 需要加,這一個一個改也太累了

總 需求列表

  • log 自動加上if判斷 如果外面有if判斷了,忽略
  • 最後 寫了個idea 外掛。。。。

log 自動加上if判斷 調研

剛上來,我先百度下 是不是有現成的,我現在用的lombok,按道理應該有一個屬性 控制 是否加if的,嗯嗯 沒錯,找找,我一般先看看 @Sl4J 給我提供了什麼引數設定

@Retention( RetentionPolicy . SOURCE )
@Target({ElementType.TYPE})
public @interface Slf4j{
    String topic() default
    }

思考 這個topic幹什麼的啊?

說實話 我之前沒有用過這個屬性。。。。狗頭。。

@Slf4j 註解有個topic 屬性可以進行設定要採用的logger,
topic 的值對應的就是logback.xml中定的logger name。root logger是預設就存在的。

到這 你可能要問了,root logger 是預設實現,你說是預設實現就是預設實現了? 證據呢?

對應的啟動Config類為 ch.qos.logback.classic.BasicConfigurator

嗯嗯 根上是ROOT

有一個細節,我們在設定logback.xml的時候 都會寫這種

<logger name="com" level="DEBUG" >
    <appender-ref ref="STDOUT"/>
</logger>
<logger name="com.example.demo" level="warn" >
    <appender-ref ref="STDOUT"/>
</logger>

你是不是好奇 這種的name怎麼解析的?

他是從頭開始 遍歷包名 從loggerCache 中看看是否有匹配的,一層層找

思考

不說這些理論了,一句話 按照上面設定 logback.xml 在 com.example.demo.controller 下的類執行會列印log.info紀錄檔麼?

@RestController
@RequestMapping
@Slf4j
public class DemoController {
    @RequestMapping("/test")
    public String test(){
        log.info("sad");
        return "success";
    }
}

嗯嗯 這麼一實驗 沒列印啊

有人可能問了,那把2個logger 順序反過來? 不用試了,也不行

這一看 com.example.demo的warn生效了啊,debug/info 都沒列印出來,那為什麼呢?

先看一個圖

下面就要看下 這個children 當時怎麼賦值的了 其實就是從 最底下 往上找,在這裡找到了 com.example.demo 的設定並且應用,是因為 logger類中

int h;
do {
    h = LoggerNameUtil.getSeparatorIndexOf(name, i);
    String childName;
    if (h == -1) {
        childName = name;
    } else {
        childName = name.substring(0, h);
    }
    i = h + 1;
    synchronized(logger) {
        childLogger = logger.getChildByName(childName);
        if (childLogger == null) {
            childLogger = logger.createChildByName(childName);
            this.loggerCache.put(childName, childLogger);
            this.incSize();
        }
    }
    logger = childLogger;
} while(h != -1);

一直找到最後,返回的就是最後/最靠近 目標類的logger 設定

小結

logger 設定不是按照pom.xml的那種優先順序,而是包名匹配 最多的生效,如果你發現 紀錄檔列印和你想的不一樣,你可以去看下 LoggerContext 類中 loggerCache 屬性的值,檢查下

如果是一個業務系統,可能是一種logback.xml模板,如果你是中介軟體/元件,就需要對logback.xml 進行改動了,因為中介軟體可能是 binlog監聽等等 巨量資料量的,如果按照業務系統那種搞法 有的紀錄檔是沒必要,根據你的業務 請自由設定

說回來 lombok 到底有沒有自動加if的外掛啊

lombok @Sl4j 是沒有了,百度下吧

好吧,這也什麼都沒有,官網看看,哎 也沒有,按道理應該有啊,也不難。。。

我突然在想是不是這個優化 也不像我們想的那麼有優化效果,肯定還是有必要的

log isDebug 判斷的必要性

錯誤案例

現象描述:發現某些伺服器的pv數不高,但伺服器的load卻不低,高於平均水平

錯誤分析

分析過程: 通過記憶體監控發現,GC的動作比較頻繁,但無法找到原因,一次PLA偶然的發現了大量如log.debug(“memberId:” + member.getMemberId())程式碼

原因分析

在程式碼中發現如下程式碼段很多: log.debug(“memberId:” + member.getMemberId())

以上程式碼執行時,分兩步:

  • 先執行的是括號中的字串相”+”的動作,而每次”+”運算都會導致新字串的生成,這樣就產生了很多“中間字串”,在極大次數被呼叫時,這種字串被建立和銷燬的數量非常龐大,從而造成了jvm gc頻繁執行,進而影響了效能。
  • 再執行log.debug()函數,在生產環境log level一般大於info,所以實際不會列印debug資訊綜上所述,這些程式碼在生產環境不會產生紀錄檔,但會執行字串”+”運算,而這些運算是無意義的,所以需要先判斷紀錄檔的優先順序,方式是log.isXXXEnabled() { log.XXX(……); }

Log Level的級別: Fatal->error->warn->info->debug,級別從高到低 一般我們生成環境的log level都是error,所以對於Error以上級別的紀錄檔,不用判斷;對於error以下級別的都要加上判斷。

總結

is 判斷還是有必要的,目前沒什麼別的辦法,我在寫一個idea 外掛,來一個按鈕/快捷鍵 自動新增log if判斷,正好玩玩

後續

行吧,既然說了做一個idea 外掛,搞起來,週末花了幾個小時搞了一版,提交了idea 稽核 ,等待稽核中 起名叫java-tools 開發會用的功能 我會迭代進去,有什麼是你們需要的可以評論下,我會排下優先順序 開發

簡單效果:

@Slf4j
public class A {
    public void a(){
        log.info("21") ;
    }
}

點選 ctrl + 8 一起按 或者 右鍵

變為

@Slf4j
public class A {
    public void a(){
        if(log. isInfoEnabled()){
        log. info("21");
        }
    }
}

以上就是java log is判斷引發的一系列事件解析的詳細內容,更多關於log is判斷引發事件的資料請關注it145.com其它相關文章!


IT145.com E-mail:sddin#qq.com