log4j2使用整理

關鍵概念

  • LoggerConfig: 日誌配置, 用於整合多個 Appender, 進行日誌打印.
  • Appender: 追加器, 用於操做 Layout 和 Manager, 往單一目的地進行日誌打印.
  • Layout: 佈局, 用於把 LogEvent 日誌事件序列化成字節序列, 不一樣 Layout 實現具備不一樣的序列化方式.
  • Manager: 管理器, 用於管理輸出目的地, 如: RollingFileManager 用於管理文件滾動以及將字節序列寫入到指定文件中
  • Filter: 過濾器, 用於對 LogEvent 日誌事件加以過濾, LoggerConfig 和 Appender 均可以配置過濾器, 也就是說日誌事件會通過一總一分兩層過濾.

日誌等級

FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL

   Configuration status="OFF":
   這個status配置的是,Log4j2 組件自己日誌級別,指的是若是 Log4j2 自己出錯,打印出的日誌級別配置。

日誌名稱、繼承體系

  • 名稱和繼承體系
Logger中存在與JAVA體系相似的繼承關係,Logger中的超類是RootLogger,它是全部Logger的父類

Logger的繼承關係是經過**名稱**隱式實現的
好比:一個名爲 com.a 就是 com.a.b 的父logger,而 com.a 的父類則是 RootLogger.

日誌結構

各類日誌框架適配

slf4j提供了各類各樣的適配器,用來將某種日誌框架委託給slf4

經過適配轉換爲新的日誌框架輸出方案 html

而後根據須要填入對應的適配器以及新的日誌框架橋接器以及引入新的日誌框架 好比 spring

就能夠統一爲log4j2日誌輸出了apache

  • 注意:程序根據classpath依賴的橋接器類型,和日誌框架類型,判斷出logger.info應該以什麼框架輸出!
  • 特別注意了,若是classpath中不當心引了兩個橋接器,那會直接報錯的!

報錯出現死循環

如上圖所示,在這種狀況下,你調用了slf4j-api,就會陷入死循環中!
1,slf4j-api去調了slf4j-log4j12
2,slf4j-log4j12又去調用了log4j
3,log4j去調用了log4j-over-slf4j
4,log4j-over-slf4j又調了slf4j-api,陷入死循環

日誌配置屬性解析

  • 類圖

  • 默認配置
<!--?xml version="1.0" encoding="UTF-8"?-->
<!-- OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL log4j2日誌等級 -->
<configuration status="WARN">
    <appenders>
        <console name="Console" target="SYSTEM_OUT">
            <patternlayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
        </console>
    </appenders>
    <loggers>
        <root level="error">
            <appenderref ref="Console" />
        </root>
    </loggers>
</configuration>
  • interpolator 插值器
在配置文件中, 基本上全部的值的配置均可以經過參數佔位符引用環境變量信息, 格式爲:${prefix:key}.

當參數佔位符 ${prefix:key} 帶有 prefix 前綴時, Interpolator 會從指定 prefix 對應的 StrLookup 實例中
進行 key 查詢

當參數佔位符 ${key} 沒有 prefix 時, Interpolator 則會從默認查找器中進行查詢.
prefix 主要有:sys、env等十多種

Interpolator 中默認支持的 StrLookup 
查找方式以下
(StrLookup 查找器實現類均在 org.apache.logging.log4j.core.lookup 包下)
  • 屬性(Properties)配置
<!--?xml version="1.0" encoding="UTF-8"?-->
<configuration>
    <properties>
        <property name="customKey_1">customValue_1</property>
        <property name="customKey_2">customValue_2</property>
    </properties>
</configuration>

** ** 注意:Properties 元素必定要配置在最前面, 不然不生效.****api

  • Appenders
簡單說 Appender 就是一個管道,定義了日誌內容的去向 (保存位置)。
配置一個或者多個Filter,Filter的過濾機制和Servlet的Filter有些差異,下文會進行說明。
配置Layout來控制日誌信息的輸出格式。
配置Policies以控制日誌什麼時候 (When) 進行滾動。
配置Strategy以控制日誌如何 (How) 進行滾動。

 框架支持多種Appender實現
 ConsoleAppender,FileAppender,RollingFileAppender,

 AsyncAppender,RollingRandomAccessFileAppender,RandomAccessFileAppender,

 JdbcAppender,JpaAppender,KafkaAppender,RoutingAppender

經常使用Appender介紹安全

  1. ConsoleAppender
控制檯追加器, 用於把日誌輸出到控制檯, 通常本地調試時使用。
 對應標籤<console>

示例服務器

<!--?xml version="1.0" encoding="UTF-8"?-->
<configuration status="warn" dest="err" verbose="false">

    <appenders>
        <!-- follow和direct不能同時爲true,若是follow爲true則會跟隨底層輸出流的變化,direct爲true則固定指向輸出流 -->
        <console name="console" target="SYSTEM_OUT" follow="false" direct="true">
            <patternlayout pattern="%date{yyyy-MM-dd HH:mm:ss.SSS} %C.%M %message%n" />
        </console>
    </appenders>
    <loggers>
        <root additivity="true" level="error" includelocation="true">
            <appenderref ref="console" level="info" />
        </root>
    </loggers>

</configuration>
  1. RollingFileAppender
文件滾動追加器, 用於向本地磁盤文件中追加日誌, 同時能夠經過觸發策略 (TriggeringPolicy)

和滾動策略 (RolloverStrategy) 控制日誌文件的分片, 避免日誌文件過大

對應標籤<rollingfile>

觸發策略:mybatis

· TimeBasedTriggeringPolicy: 基於時間週期性觸發滾動, 通常按天滾動
   · SizeBasedTriggeringPolicy: 基於文件大小觸發滾動, 能夠控制單個日誌文件的大小上限

滾動策略app

· DefaultRolloverStrategy: 默認滾動策略
	 該策略內部維護一個最小索引和最大索引, 每次滾動時, 會刪除歷史文件,
	 
	 以後剩餘文件所有進行一輪重命名, 最後建立新的不帶有索引後綴的文件進行日誌追加

· DirectWriteRolloverStrategy: 直接寫滾動策略
	該策略內部會維護一個一直自增的文件索引, 每次滾動時直接建立新的帶有索引後綴的文件進行日誌追加, 
	
	同步清理歷史的文件.

示例框架

<!--?xml version="1.0" encoding="UTF-8"?-->
<configuration status="warn" dest="err" verbose="false">

    <properties>
        <property name="logDir">/Users/lixin46/workspace/demo/logdemo/logs</property>
        <property name="pattern">%date{yyyy-MM-dd HH:mm:ss.SSS} %C.%M %message%n</property>
    </properties>
    <appenders>
        <console name="console">
            <patternlayout pattern="${pattern}" />
        </console>
        <!-- 使用DirectWriteRolloverStrategy策略時,不須要配置fileName -->
        <rollingfile name="fileAppender" filename="${logDir}/request.log" filepattern="${logDir}/request.log-%d-%i">
            <patternlayout pattern="${pattern}" />
            <!-- 全部策略中,只要任意策略知足就會觸發滾動 -->
            <policies>
                <!-- 滾動時間週期,只有數量,單位取決於filePattern中%d的配置 -->
                <timebasedtriggeringpolicy interval="1" />
                <sizebasedtriggeringpolicy size="10b" />
            </policies>
            <!-- 限制最多保留5個文件,索引自增 -->
            <!--<DirectWriteRolloverStrategy maxFiles="5"/>-->
            <!-- 限制最多保留5個文件,索引從2到6 -->
            <defaultrolloverstrategy fileIndex="max" min="2" max="6" />
        </rollingfile>
    </appenders>

    <loggers>
        <root level="info">
            <appenderref ref="console" level="info" />
            <appenderref ref="fileAppender" level="info" />
        </root>
    </loggers>

</configuration>

3.FileAppenderdom

主要用於本地測試
<!--?xml version="1.0" encoding="UTF-8"?-->
<configuration status="warn" name="MyApp" packages="">
  <appenders>
	  <!-- append,boolean,指定是不是追加寫入(append=true,默認狀況),仍是覆蓋寫入(append=false)-->
    <file name="MyFile" filename="logs/app.log" append="true">
      <patternlayout>
        <pattern>%d %p %c{1.} [%t] %m%n</pattern>
      </patternlayout>
    </file>
  </appenders>
  <loggers>
    <root level="error">
      <appenderref ref="MyFile" />
    </root>
  </loggers>
</configuration>

4,RandomAccessFileAppender

和FileAppender相似,可是使用了ByteBuffer+RandomAccessFile的方式來代替BufferedOutputStream

5.RollingRandomAccessFileAppender

和RollingFileAppender相似,使用了ByteBuffer+RandomAccessFile的方式代替BufferedOutputStream

6.RoutingAppender

經過路由規則來評價一個 log event 後,決定它下一個被髮往的 appender。

RoutingAppender 有一個重要的參數名爲 routes,是 Routes 型數據,用來描述該 appender 的路由規則

7.SMTPAppender

SMTPAppender 主要用來給指定的 E-mail 發送 log event

(這種狀況通常用在 event 的安全級別超過 ERROR 或 FATAL 時,event 的安全分級能夠參考【此文】之日誌記錄小節)。

SMTPAppender 有不少重要的參數以完成 log event 發送到指定 E-mail。

8.SocketAppender

將 log event 輸出到一個遠程服務器上(需指定服務器名和端口號),數據能夠以任意指定的格式經由 TCP 或 UDP 協議發

9.AsynchAppender

引用其餘Appender,被引用的Appender能夠作到異步輸出日誌

一個 LogEvent 異步地寫入多個不一樣輸出地。

在 AsynchAppender 中有一個參數,名爲 「appender-ref」,用來指定要發送到的 appender 的名稱。

AsynchAppender 維護了一個隊列,隊列中存放了須要異步發送的 LogEvent,

隊列中 LogEvent 的個數能夠經過「bufferSize」 參數來指定。

另外,還有一個 「blocking」 參數來指定是否對 AsynchAppender 的 LogEvent 隊列上鎖,若是 blocking=true,

那麼在隊列滿員的狀況下,新到達的 LogEvent 將等待,直到有空位。

若 blocking=false,那麼在隊列滿員的狀況下,將把新到的 LogEvent 轉到 error appender
  • PatternLayout
模式佈局是咱們最常使用的, 它經過 PatternProcessor 模式解析器, 對模式字符串進行解析,

獲得一個 List<patternconverter> 轉換器列表和 List<formattinginfo> 格式信息列表.

在 PatternLayout 序列化時, 會遍歷每一個 PatternConverter, 從 LogEvent 中取不一樣的值進行序列化輸出
  • Filters
Filters 決定日誌事件可否被輸出。過濾條件有三個值:ACCEPT(接受),DENY(拒絕),NEUTRAL(中立)
log4j2中的過濾器ACCEPT和DENY以後,後續的過濾器就不會執行了,只有在NEUTRAL的時候纔會執行後續的過濾器

全局 Filter 節點<filters> 必須放在<properties>節點以後

過濾器做用域

1.全局範圍

 即直接配置在 configuration 最外層:該做用域的 Filter 直接過濾日誌信息而不傳遞至 Logger 作進一步處理;

若配置多個全局 filter,則有且僅有一個起效,同時 logger 定義的 level 也將失效 (若 filter 中配置了 level);

Logger 和 Appender 的 filter 將覆蓋全局的 filter

2.Logger 範圍

配置在某個具體的 Logger 中,該 filter 不會傳遞至父級的 Logger 中,即便 additivity 配置爲 true

3.Appender 範圍

做用於 Appender 是否處理日誌過濾操做

4.Appender Reference 範圍

做用於 Logger 路由該過濾操做至某個 appender 上

常見的Filters

1.LevelRangeFilter

minLevel 須要配置的是高級別,maxLevel 配置的是低級別

<levelrangefilter minLevel="fatal" maxLevel="info" onMatch="ACCEPT" onMismatch="DENY" />

2.TimeFilter

<timefilter start="05:00:00" end="05:30:00" onMatch=" NEUTRAL " onMismatch="DENY" />

3.ThresholdFilter

這個 Filter 負責按照所配置的日誌級別過濾 Log Event,等於或超出所配置級別的 log Event 將返回 onMatch 結果。(threshold : 閾值, 臨界值; 門檻,入口)

<thresholdfilter level="TRACE" onMatch="NEUTRAL" onMismatch="DENY" />
  • Logger
分爲兩個 Root(必須配置) 和 Logger

示例:

<!--?xml version="1.0" encoding="UTF-8"?-->
<configuration status="warn" dest="err" verbose="false">

    <appenders>
        <console name="console">
            <patternlayout pattern="%date{yyyy-MM-dd HH:mm:ss.SSS} %C.%M %message%n" />
        </console>
    </appenders>
    <loggers>
        <root level="error" includelocation="true">
            <appenderref ref="console" level="info">
                <thresholdfilter level="warn" onMatch="NEUTRAL" onMismatch="DENY" />
            </appenderref>
            <property name="customeKey">customeValue</property>
            <thresholdfilter level="warn" onMatch="NEUTRAL" onMismatch="DENY" />
        </root>
        <logger name="com.lixin" additivity="true" level="info" includelocation="true">
            <appenderref ref="console" level="info">
                <thresholdfilter level="warn" onMatch="NEUTRAL" onMismatch="DENY" />
            </appenderref>
            <property name="customeKey">customeValue</property>
            <thresholdfilter level="warn" onMatch="NEUTRAL" onMismatch="DENY" />
        </logger>
    </loggers>

</configuration>

解析:

- additivity: 日誌可加性, 若是配置爲 true, 則在日誌打印時, 會經過 Logger 繼承關係遞歸調用父 Logger 引用的 Appender 進行日誌打印.
注意: 該屬性默認爲 true. 在遞歸打印日誌時, 會忽略父 Logger 的 level 配置

- level: 用於控制容許打印的日誌級別上線, 在配置示例中, 只有級別 &lt;=info 的 LogEvent 纔會被放行, 級別優先級順序爲 OFF<fatal<error<warn<info<debug<trace<all 注意: level 屬性的配置時可選的, 在獲取 時會經過 logger 繼承關係遞歸獲取, rootlogger 的級別默認爲 error, 其餘默認爲 null. 也就是說, 若是全都不配置 的話, 則全部 級別都默認爲 error. - includelocation: 若是配置爲 true, 則打印日誌時能夠附帶日誌點源碼位置信息輸出. 同步日誌上下文默認爲 異步默認爲 false. loggerconfig 元素下能夠單獨配置 property 元素, 添加屬性鍵值對, 這些屬性會在每次打印日誌時, 被追加到 logevent 的 contextdata 中 支持配置過濾器, 在判斷是否打印日誌時, 先過濾器判斷過濾, 而後再級別判斷過濾 appenderref: 顧名思義, 就是配置當前 引用的 appender. 同時, appenderref 也支持配置 和 filter, 進行更細粒度的日誌過濾 等於總開關, 則爲各個子開關, 兩個開關都經過才能打印日誌 ``` 最後總體的配置示例 ```xml <?xml version="1.0" encoding="UTF-8" ?>
<!-- 設置log4j2的自身log級別爲INFO -->
<!-- OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
<configuration status="INFO" monitorinterval="30">
	<properties>
    	<property name="filePath">${sys:catalina.home}/logs</property>
  	</properties>
    <appenders>
        <console name="Console" target="SYSTEM_OUT">
        	<filters>
            	<!-- 過濾器 僅放行DEBUG及以上級別的日誌 (OFF,FATAL,ERROR,WARN,INFO)	 -->
        		<!-- 若是不是要調試項目,請不要將日誌等級調到DEBUG及如下。	-->
                <thresholdfilter level="INFO" />
                <!-- 過濾器 僅放行FATAL如下級別的日誌 (INFO,DEBUG,TRACE,ALL)	 -->
                <thresholdfilter level="OFF" onMatch="DENY" onMismatch="NEUTRAL" />
            </filters>
            <patternlayout pattern="%d{yyyy-MM-dd HH:mm:ss,SSS} [%p] - %l - %m%n" />
        </console>
 
 		<!-- 將全部日誌輸出到 Redirect_Logger.log 並設置不累加 -->
 		<file name="log" filename="${filePath}/Redirect_logger.log" append="false">
 			<filters>
            	<!-- 過濾器 僅放行DEBUG及以上級別的日誌 (OFF,FATAL,ERROR,WARN,INFO) -->
                <thresholdfilter level="DEBUG" />
                <!-- 過濾器 僅放行FATAL如下級別的日誌 (INFO,DEBUG,TRACE,ALL) -->
                <thresholdfilter level="FATAL" onMatch="DENY" onMismatch="NEUTRAL" />
            </filters>
	       <patternlayout pattern="%d{yyyy-MM-dd HH:mm:ss,SSS} [%p] - %l - %m%n" />
    	</file>
 		<!-- 這個會打印出全部的info及如下級別的信息,每次大小超過size,則這size大小的日誌會自動存入按年份-月份創建的文件夾下面並進行壓縮,做爲存檔-->
        <rollingfile name="RollingFileInfo" filename="${sys:catalina.home}/logs/info.log" filepattern="${sys:catalina.home}/logs/info-%d{yyyy-MM-dd}-%i.log">
            <!--控制檯只輸出level及以上級別的信息(onMatch),其餘的直接拒絕(onMismatch)-->        
            <filters>
            	<!-- 過濾器 僅放行INFO及以上級別的日誌 (OFF,FATAL,ERROR,WARN,INFO) -->
                <thresholdfilter level="INFO" />
                <!-- 過濾器 僅放行WARN如下級別的日誌 (INFO,DEBUG,TRACE,ALL) -->
                <thresholdfilter level="WARN" onMatch="DENY" onMismatch="NEUTRAL" />
            </filters>
            <!-- 格式化文件輸出的日誌格式 -->
            <patternlayout pattern="%d{yyyy-MM-dd HH:mm:ss,SSS} [%p] - %l - %m%n" />
            <policies>
                <timebasedtriggeringpolicy interval="24" modulate="true" />
                <sizebasedtriggeringpolicy size="1MB" />
            </policies>
        </rollingfile>
    </appenders>
 
    <loggers>
        <!--過濾掉spring和mybatis的一些無用的DEBUG信息-->
        <logger name="org.springframework" level="INFO"></logger>
        <logger name="org.mybatis" level="INFO"></logger>
        <root level="ALL">
            <appender-ref ref="Console" />
            <appender-ref ref="log" />
            <appender-ref ref="RollingFileInfo" />
        </root>
    </loggers>
</configuration>

引入xiclude

XML配置文件能夠包含XInclude引入其餘文件

示例

<!--?xml version="1.0" encoding="UTF-8"?-->
<configuration xmlns:xi="http://www.w3.org/2001/XInclude" status="warn" name="XIncludeDemo">
  <properties>
    <property name="filename">xinclude-demo.log</property>
  </properties>
  <thresholdfilter level="debug" />
  <xi:include href="log4j-xinclude-appenders.xml" />
  <xi:include href="log4j-xinclude-loggers.xml" />
</configuration>

log4j-xinclude-appenders.xml:

<!--?xml version="1.0" encoding="UTF-8"?-->
<appenders>
  <console name="STDOUT">
    <patternlayout pattern="%m%n" />
  </console>
  <file name="File" filename="${filename}" bufferedio="true" immediateflush="true">
    <patternlayout>
      <pattern>%d %p %C{1.} [%t] %m%n</pattern>
    </patternlayout>
  </file>
</appenders>

log4j-xinclude-loggers.xml:

<!--?xml version="1.0" encoding="UTF-8"?-->
<loggers>
  <logger name="org.apache.logging.log4j.test1" level="debug" additivity="false">
    <threadcontextmapfilter>
      <keyvaluepair key="test" value="123" />
    </threadcontextmapfilter>
    <appenderref ref="STDOUT" />
  </logger>

  <logger name="org.apache.logging.log4j.test2" level="debug" additivity="false">
    <appenderref ref="File" />
  </logger>

  <root level="error">
    <appenderref ref="STDOUT" />
  </root>
</loggers>

異步模式

用異步日誌進行輸出時,日誌輸出語句與業務邏輯語句並非在同一個線程中運行,而是有專門的線程用於進行日誌輸出操做,處理業務
邏輯的主線程不用等待便可執行後續業務邏輯

Log4j2 中的異步日誌實現方式有 AsyncAppender 和 AsyncLogger 兩種

AsyncAppender 採用了 ArrayBlockingQueue 來保存須要異步輸出的日誌事件;
AsyncLogger 則使用了 Disruptor 框架來實現高吞吐(建議採用)
  • 全局異步模式(建議)
  1. maven 增長 disruptor 依賴,Log4j2 版本 2.9 及以上時須要 disruptor-3.3.4.jar 或更高版本;Log4j2 版本 2.9 如下時須要 disruptor-3.0.0.jar 或更高版本
<dependency>
     <groupid>com.lmax</groupid>
     <artifactid>disruptor</artifactid>
     <version>3.3.4</version>
</dependency>
  1. 將系統屬性 log4j2.contextSelector 設置爲org.apache.logging.log4j.core.async.AsyncLoggerContextSelector

方式一:添加一個名字爲 log4j2.component.properties 的文件,放到 classpath 下面

增長屬性:Log4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector

方式二:加載 JVM 啓動參數裏

-DLog4j2.contextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector

方式三:在主程序代碼開頭,加上系統屬性的代碼

System.setProperty("Log4jContextSelector", "org.apache.logging.log4j.core.async.AsyncLoggerContextSelector");

  1. 修改配置文件的使用RandomAccessFile或RollingRandomAccessFile
  • 異步與同步混合使用
  1. 增長disruptor依賴,同上

  2. 使用 <asyncroot> 或 <asyncLogger> 配置來指定須要異步的記錄器

    注意:配置只能包含一個根記錄器(<root> 或 < asyncRoot > 元素),但能夠組合異步和非異步記錄器。例如,包含 < asyncLogger > 元素的配置文件也能夠包含同步記錄器的 < Root > 和 < Logger > 元素

與spring-boot結合

  1. 去掉spring-boot默認的日誌框架,引入log4j2的日誌框架
  2. 配置log4j的配置文件便可
  • spring-boot的profiles結合使用

    根據不一樣profile使用不一樣的配置文件

    在application.properties中根據環境的選擇動態指定logging.config

參考

https://www.jianshu.com/p/d09e4d3a5f2b
https://www.jianshu.com/p/0c882ced0bf5
https://www.cnblogs.com/rjzheng/p/10042911.html
相關文章
相關標籤/搜索