Log4j源代碼學習

  瞭解log4j的源代碼來源於項目中一次需求,咱們想將系統全部的warn日誌統一收集到common-warn.log的日誌中去,以便於系統對其進行監控處理。因而模擬自動生成的error配置完成了warn的配置,可是測試發現common-warn.log中居然有error日誌,並且業務的正常日誌中居然也存在error和warn日誌。這樣至關於日誌重複打了好多地方,無疑增長了日誌量,同時增長了磁盤消耗。html

原始配置:apache

 <appender name="DEFAULT-APPENDER" class="org.apache.log4j.DailyRollingFileAppender">
        <param name="file" value="${log_root}/${sys_host_name}/app-service.log"/>
        <param name="append" value="true"/>
        <param name="encoding" value="UTF-8"/>
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern"
                   value="%d [%X{loginUserEmail}/%X{loginUserID}/%X{remoteAddr}/%X{clientId} - %X{requestURIWithQueryString}] %-5p %c{2} - %m%n"/>
        </layout>
    </appender>

    <!-- [公共Appender] 彙總錯誤 -->
    <appender name="ERROR-APPENDER" class="org.apache.log4j.DailyRollingFileAppender">
        <param name="file" value="${log_root}/${sys_host_name}/common-error.log"/>
        <param name="append" value="true"/>
        <param name="encoding" value="UTF-8"/>
        <param name="threshold" value="error"/>`
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern"
                   value="%d [%X{loginUserEmail}/%X{loginUserID}/%X{remoteAddr}/%X{clientId} - %X{requestURIWithQueryString}] %-5p %c{2} - %m%n"/>
        </layout>
    </appender>

    <!-- [公共Appender] 彙總警告 -->
    <appender name="WARN-APPENDER" class="org.apache.log4j.DailyRollingFileAppender">
        <param name="file" value="${log_root}/${sys_host_name}/common-warn.log"/>
        <param name="append" value="true"/>
        <param name="encoding" value="UTF-8"/>
        <param name="threshold" value="WARN"/>
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern"
                   value="%d [%X{loginUserEmail}/%X{loginUserID}/%X{remoteAddr}/%X{clientId} - %X{requestURIWithQueryString}] %-5p %c{2} - %m%n"/>
        </layout>
    </appender>

    <!-- [應用Logger]  - 默認 -->
    <logger name="APP-LOG" additivity="false">
        <level value="${log_level}"/>
        <appender-ref ref="DEFAULT-APPENDER"/>
        <appender-ref ref="WARN-APPENDER"/>
        <appender-ref ref="ERROR-APPENDER"/>
    </logger>

  


因此個人核心訴求就是:將小於等於info的日誌打印到app-service.log,將error打印到common-error.log, 將warn打印到common-warn.log。 app

1. Log4j核心類

     核心抽象:測試

  • Logger 用於對日誌記錄行爲的抽象,提供記錄不一樣級別日誌的統一接口;
  • Level對日誌級別的抽象;
  • Appender是對記錄日誌形式的抽象,標示了日誌打印的目的地;
  • Layout是對日誌行格式的抽象;
  • LoggingEvent是對一第二天志記錄過程當中所須要的信息的抽象,能夠理解成一個上下文;

  整個日誌打印的過程能夠理解爲Loger拿着LoggingEvent去找Appender, 讓Appender按照Layout的形式將日誌打印到指定的位置。 而Level起的啥做用呢? Logger和Appender都是有原則的不能說你讓我打印我就打印,必須知足個人規則我纔給你打印,這裏的規則就是指Level(出來混都是要講原則的)。spa

覈對類圖:日誌

 

 


2. 初始化過程

  核心邏輯在LogManager的靜態代碼塊,根據配置信息解析初始化Logger,Appender和Layout等核心組件;htm

     

 

 

3. 日誌打印  

  核心的日誌打印流程, 中間還有不少控制的細節,具體能夠看源代碼:對象

     

 

4. 日誌控制

  回到咱們的出發點,如何實現:
  將小於等於info的日誌打印到app-service.log,將error打印到common-error.log, 將warn打印到common-warn.log。 blog

  • 1. 重寫Appender中2.5.2的方法(isAsSevereAsThreshold),自定義三個Appender的類,Appender1判斷知足小於等於info的LoggingEvent才進行打印,目標指定爲app-service.log;Appender2判斷知足等於warn的LoggingEvent才進行打印,目標指定爲common-warn.log;Appender3判斷知足等於error的LoggingEvent才進行打印,目標指定爲common-error.log;這樣可以知足咱們的需求,可是這樣就會存兩個問題
    •  存在一個潛規則就是:開發在配置的時候必需要使用自定義的Appender才能夠知足,若是某同窗使用默認的話,就可能存在日誌打印錯亂,影響監控;
    •  若是某個開發在Logger配置的時候忘記指定error的Appender,那麼error日誌將不會打印,存在日誌丟失,風險很大;
  • 2. 添加2.5.3中提到的Filter配置,進行Appender過濾。log4j支持DenyAllFilter,LevelMatchFilter,LevelRangeFilter,StringMatchFilter的配置。經過LevelRangeFilter能夠指定該Appender支持的日誌範圍。該方案解決了上個方案a存在的問題,可是沒法解決b可能存在的問題;
  • 3. 重寫Logger的日誌打印的方法,在遍歷Appender執行的時候,首先篩選出Level匹配(這裏只相等)的Appender進行打印,若是沒有匹配的Appender,再按照默認的策略進行打印。這樣能夠經過設置Appender的threshold便可實現,並且還能夠防止Appender漏配置致使的日誌缺失問題。該方案既能夠兼容日誌丟失,又能夠知足咱們的需求,可是logger對象中的AppenderAttachableImpl存儲Appdender的List ,Logger中直接存放的是實現類,沒有提供可擴展的方式,好像不太好實現。 求大神指點。 

      目前項目中使用的方案爲2, 同時app-service.log的Appender不配置Filter默認接受error和warn的日誌, 可是warn和error經過Fileter進行區分不會相互影響,這樣能夠知足業務監控warn和error日誌的需求,不須要修改任何代碼,同時知足不會丟失日誌的問題。可是存在error和warn日誌重複打印的問題。 接口

 

最終的解決方案配置:

    <appender name="DEFAULT-APPENDER" class="org.apache.log4j.DailyRollingFileAppender">
        <param name="file" value="${log_root}/${sys_host_name}/app-default.log"/>
        <param name="append" value="true"/>
        <param name="encoding" value="UTF-8"/>
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern"
                   value="%d [%X{loginUserEmail}/%X{loginUserID}/%X{remoteAddr}/%X{clientId} - %X{requestURIWithQueryString}] %-5p %c{2} - %m%n"/>
        </layout>
    </appender>

    <!-- [公共Appender] 彙總錯誤 -->
    <appender name="ERROR-APPENDER" class="org.apache.log4j.DailyRollingFileAppender">
        <param name="file" value="${log_root}/${sys_host_name}/common-error.log"/>
        <param name="append" value="true"/>
        <param name="encoding" value="UTF-8"/>
        <param name="threshold" value="error"/>`
        <!-- 僅打印error級別的日誌 -->
        <filter class="org.apache.log4j.varia.LevelRangeFilter">
            <param name="levelMin" value="ERROR" />
            <param name="levelMax" value="ERROR"/>
            <param name="acceptOnMatch" value="true"/>
        </filter>
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern"
                   value="%d [%X{loginUserEmail}/%X{loginUserID}/%X{remoteAddr}/%X{clientId} - %X{requestURIWithQueryString}] %-5p %c{2} - %m%n"/>
        </layout>
    </appender>

    <!-- [公共Appender] 彙總警告 -->
    <appender name="WARN-APPENDER" class="org.apache.log4j.DailyRollingFileAppender">
        <param name="file" value="${log_root}/${sys_host_name}/common-warn.log"/>
        <param name="append" value="true"/>
        <param name="encoding" value="UTF-8"/>
        <param name="threshold" value="WARN"/>
        <!-- 僅打印warn級別的日誌 -->
        <filter class="org.apache.log4j.varia.LevelRangeFilter">
            <param name="levelMin" value="WARN" />
            <param name="levelMax" value="WARN"/>
            <param name="acceptOnMatch" value="true"/>
        </filter>
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern"
                   value="%d [%X{loginUserEmail}/%X{loginUserID}/%X{remoteAddr}/%X{clientId} - %X{requestURIWithQueryString}] %-5p %c{2} - %m%n"/>
        </layout>
    </appender>

    <!-- [應用Logger]  - 默認 -->
    <logger name="APP-LOG" additivity="false">
        <level value="${log_level}"/>
        <appender-ref ref="DEFAULT-APPENDER"/>
        <appender-ref ref="WARN-APPENDER"/>
        <appender-ref ref="ERROR-APPENDER"/>
    </logger>
相關文章
相關標籤/搜索