本文屬於轉載,方便本身查看。html
原文地址:Log4j1 升級 Log4j2 實戰java
在任何系統中,日誌都是很是重要的組成部分,它是反映系統運行狀況的重要依據,也是排查問題時的必要線索。絕大多數人都承認日誌的重要性,可是又有多少人仔細想過該怎麼打日誌,日誌對性能的影響究竟有多大呢?git
新的Log4j 2.0版本有了大幅的性能提高、新的插件系統,以及配置設置方面的不少改善。Log4j 1.x 在高併發狀況下出現死鎖致使cpu使用率異常飆升,而Log4j2.0基於LMAX Disruptor的異步日誌在多線程環境下性能會遠遠優於Log4j 1.x和logback ——官方測試結果。github
本次升級是以thrift服務化項目爲例子進行的,後續會在其餘項目中進行,本次工做內容爲:web
吞吐量測試 正則表達式
平均耗時 spring
其中:apache
<?xml version="1.0" encoding="UTF-8"?> <Configuration> <Properties> <Property name="pattern_layout">%d %-5p (%F:%L) - %m%n</Property> <Property name="LOG_HOME">/var/***/logs</Property> </Properties> <Appenders> <Console name="console" target="SYSTEM_OUT" follow="true"> <PatternLayout pattern="${pattern_layout}"/> </Console> <RollingRandomAccessFile name="file" fileName="${LOG_HOME}/${sys:app.key}.log" filePattern="${LOG_HOME}/${sys:app.key}.log.%d{yyyy-MM-dd}"> <PatternLayout pattern="${pattern_layout}"/> <Policies> <TimeBasedTriggeringPolicy/> </Policies> </RollingRandomAccessFile> <RollingRandomAccessFile name="access_kpi" fileName="${LOG_HOME}/${sys:app.key}_access_kpi.log" filePattern="${LOG_HOME}/${sys:app.key}_access_kpi.log.%d{yyyy-MM-dd}"> <PatternLayout pattern="${pattern_layout}"/> <Policies> <TimeBasedTriggeringPolicy/> </Policies> </RollingRandomAccessFile> <RollingRandomAccessFile name="jmonitorappender" fileName="${LOG_HOME}/${sys:app.key}.jmonitor.log" filePattern="${LOG_HOME}/${sys:app.key}.jmonitor.%d{yyyy-MM-dd}.log.gz"> <PatternLayout pattern="${pattern_layout}"/> <Policies> <TimeBasedTriggeringPolicy/> </Policies> </RollingRandomAccessFile> <RollingRandomAccessFile name="jmonitorlogstoreappender" fileName="${LOG_HOME}/${sys:app.key}.jmonitor.logstore.log" filePattern="${LOG_HOME}/${sys:app.key}.jmonitor.logstore.%d{yyyy-MM-dd}.log.gz"> <PatternLayout pattern="${pattern_layout}"/> <Policies> <TimeBasedTriggeringPolicy/> </Policies> </RollingRandomAccessFile> <Scribe name="errorLog"> <ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/> <Property name="hostname">${sys:app.key}</Property> <Property name="scribeHost">127.0.0.1</Property> <Property name="scribePort">4252</Property> <Property name="scribeCategory">cos_errorlog</Property> <Property name="printExceptionStack">false</Property> <Property name="addStackTraceToMessage">false</Property> <Property name="timeToWaitBeforeRetry">6000</Property> <Property name="sizeOfInMemoryStoreForward">100</Property> <PatternLayout pattern="%d %p $${sys:app.host} $${sys:app.ip} errorlog appkey=$${sys:app.key} location=%F:%L rawlog=%replace{%replace{%m}{=}{:}}{\n|\t}{} rawexception=%replace{%replace{%ex}{=}{:}}{\n|\t}{}%n"/> </Scribe> </Appenders> <Loggers> <Logger name="access_kpi" level="INFO" includeLocation="true" additivity="false"> <AppenderRef ref="access_kpi"/> </Logger> <!-- tair Loggers --> <Logger name="com.taobao.tair3.client" level="WARN" includeLocation="true" additivity="false"> <AppenderRef ref="file"/> <AppenderRef ref="errorLog"/> </Logger> <!-- 3rdparty Loggers --> <Logger name="org.springframework" level="WARN"/> <Logger name="org.apache.zookeeper" level="ERROR"/> <Logger name="org.springframework.web" level="WARN"/> <!-- Root Logger --> <Root level="INFO" includeLocation="true"> <AppenderRef ref="file"/> <AppenderRef ref="console"/> <AppenderRef ref="errorLog"/> </Root> </Loggers> </Configuration>
咱們先看看Configuration的一些特性:json
<Configuration status="WARN"> ... </Configuration>
該片斷代表log4j2配置文件的全部內容都在這個標籤內,其status屬性爲「WARN」說明:log4j2內部的日誌會將日誌級別大於WARN的日誌打印到Console。除了該字段,Configuration還包括其餘屬性,詳見:ConfigurationSyntax。api
<Appenders> <Console name="Console" target="SYSTEM_OUT"> <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/> </Console> </Appenders>
全部的Appender將在<Appenders>和</Appenders>之間定義。上述例子定義了ConsoleAppender並關聯PatternLayout,關於Appender和Layout請看上述相關小節。
<Loggers> <Logger name="com.foo.Bar" level="trace" additivity="false" includeLocation="true"> <AppenderRef ref="Console"/> </Logger> <Root level="error"> <AppenderRef ref="Console"/> </Root> </Loggers>
全部的Logger將在<Loggers>和</Loggers>之間定義。上述例子經過<Root>定義了全部Logger的根結點(RootLogger),並經過<AppenderRef>標籤關聯名稱爲「Console」的Appender,關於Logger請看上述相關小節。
此處有必要說明additivity字段,經過配置該字段,咱們能夠規定是否將日誌事件傳遞到Logger的父結點處理,其默認值爲true(即默認交給parent Logger處理)。
Logger默認不會獲取location信息,所以,若咱們的Layout或Filter等須要location信息,咱們必須給相應的設置「includeLocation=true」
<Filters> <Marker marker="EVENT" onMatch="ACCEPT" onMismatch="NEUTRAL"/> <DynamicThresholdFilter key="loginId" defaultThreshold="ERROR" onMatch="ACCEPT" onMismatch="NEUTRAL"> <KeyValuePair key="User1" value="DEBUG"/> </DynamicThresholdFilter> </Filters>
log4j2還有一個很重要的組件——Filter,詳見Filter小節。此處經過<Filters>和</Filters>代表這是一個組合Filter,裏邊包括MarkerFilter和DynamicThresholdFilter。onMatch表示和onMismatch表示通過Filter過濾後的結果,該結果有三個取值:ACCEPT、NEUTRAL和DENY。log4j2在處理LogEvents時,會經過該Filter進行過濾,若返回結果爲ACCEPT,則直接處理(略過其它Filter和日誌級別的過濾);若返回DENY則直接終止該LogEvents;若返回NEUTRAL,則不作決策,讓後續代碼作處理。
此處,Filter是經過Configuration的直接子元素配置,所以,LogEvents若被該Filter過濾以後則不會傳遞給Logger處理。
Log4j2提供了異步Logger,經過不一樣線程實現I/O操做,目的在於爲咱們的應用程序提升性能。咱們先來看一看它主要在哪些方面作改進:
如下開始說明*服務化項目如何由:Log4j1.x 升級到 Log4j2
須要肯定項目pom文件中依賴的其餘的jar中也再也不依賴log4j及slf4j-log4j12,具體方式能夠經過IDE提供的功能或者直接使用mvn dependency:tree肯定依賴關係。
因爲引用的jar中不少依然使用的爲log4j,所以已經升級過log4j2的項目,每次在新增依賴的時候,必定須要肯定一下,引用的jar是否含有對低版本的依賴,而且exclusion掉。
<exclusions> <exclusion> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> </exclusion> <exclusion> <groupId>log4j</groupId> <artifactId>log4j</artifactId> </exclusion> </exclusions>
<properties> <org.slf4j-version>1.7.12</org.slf4j-version> <log4j2-version>2.3</log4j2-version> </properties> <dependency> <groupId>org.slf4j</groupId> <artifactId>jcl-over-slf4j</artifactId> <version>${org.slf4j-version}</version> <scope>runtime</scope> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-1.2-api</artifactId> <version>${log4j2-version}</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-slf4j-impl</artifactId> <version>${log4j2-version}</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>${log4j2-version}</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>${log4j2-version}</version> </dependency> <dependency> <groupId>com.lmax</groupId> <artifactId>disruptor</artifactId> <version>3.2.0</version> </dependency> <dependency> <groupId>com.sankuai.meituan</groupId> <artifactId>scribe-log4j2</artifactId> <version>1.0.9</version> </dependency>
在JVM啓動參數中增長 -DLog4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector 開啓異步日誌。(目前針對scribe的appender爲同步appender,若是不開啓異步機制會致使線程block)
刪除原log4j.xml配置文件,新增log4j2.xml,注意:須要保證log4j2.xml在resource根目錄內,不然會致使配置文件加載不到(即log4j2.xml須要在class根目錄內)
private static final Logger LOGGER = LoggerFactory.getLogger(Boot.class);
使用slf4j進行log的定義,注意須要保證項目中再也不依賴於slf4j1。若是啓動時有以下提示,說明依然依賴了多個slf4j
http://logging.apache.org/log4j/2.x/manual/migration.html#Configuring_Log4j_2
http://logging.apache.org/log4j/2.x/guidelines.html
http://logging.apache.org/log4j/2.x/performance.html
http://www.infoq.com/cn/articles/things-of-java-log-performance