linux上设置了log4j没有产生日志文件_关于 log4j 升级到 log4j2 的小结
關(guān)于升級(jí) jar 包等前提要求
- 刪掉原先的 log4j-1.XX 等 jar 包
- 從 1.XX 升級(jí)到 2.XX 平穩(wěn)升級(jí)需要的 jar 包,其中包括用 sl4j-1.7.25 (1.7.21 暫時(shí)也不需要升級(jí)) 的版本包,具體可以看自己的工程配置是否需要
- slf4j-log4j-升級(jí)到 2.8.2.zip
- 新建 log4j2.xml 配置文件
對(duì)于 tomcat 項(xiàng)目的版本要求:(以 7.0.43 為分界線),目前 jdk1.8 可以在 tomcat 7.0.32 ,7.0.94 正常啟動(dòng)代碼
三種配置方式:
1、關(guān)于 log4j2.xml 的默認(rèn)存放位置(WEB 項(xiàng)目可以使用)
按照官方推薦默認(rèn)放到 resource 目錄下面,名稱(chēng)必須叫 log4j2.xml ,其余文件名會(huì)讀取失敗,無(wú)需配置其它文件,如下圖:
2、關(guān)于使用自定義路徑配置文件(推薦 jar 包讀取外部配置文件,比如 Eserver ItmsService 等模塊)
2.1 在代碼的 web.xml 文件里,增加如下配置,其中 param-value 為配置文件的絕對(duì)路徑,包含 file:// 開(kāi)頭文件
<!-- 配置log4j2 --><listener><listener-class>org.apache.logging.log4j.web.Log4jServletContextListener</listener-class></listener><context-param><description>日志配置文件的路徑</description><param-name>log4jConfiguration</param-name><param-value>file:///export/home/rms/EServer4WS/WEB-INF/log4j2.xml</param-value></context-param>2.2 修改 web.xml 文件的開(kāi)頭關(guān)于 servlet 的版本,因?yàn)?tomcat 7.0 之后,lib 包里面的 servlet-api.jar 包的版本是 3.0,所以必須修改 web.xml 的版本聲明,否則會(huì)無(wú)法初始化 log4j2。
(將圖一三個(gè)標(biāo)紅的地方應(yīng)該改為 3.0),結(jié)果如圖二 圖一:
圖二:
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns="http://java.sun.com/xml/ns/javaee"xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"id="WebApp_ID" version="3.0">3、自定義路徑并且實(shí)現(xiàn)相關(guān) jar 包的預(yù)留接口(不需要改動(dòng)代碼和配置,目前只需要替換相關(guān)的 jar 包,把新建的 log4j2.xml 改名為 log4j.xml ,并且放在原先同級(jí)目錄即可)
針對(duì)目前代碼現(xiàn)狀,為了不改動(dòng)配置和代碼,實(shí)現(xiàn)了 log4j-1.2-api-2.8.2.jar 預(yù)留的相關(guān)接口,具體哪個(gè)接口需要查看原本工程初始化 log4j 的類(lèi)用的是哪個(gè)接口,比如 org.apache.log4j.xml.DOMConfigurator 類(lèi)里面的相關(guān)接口,如下所示:
private static Logger logger = LoggerFactory.getLogger(DOMConfigurator.class); // 如下相關(guān)通用實(shí)現(xiàn)log4j2初始化代碼 public static void configureAndWatch(String configFilename){LoggerContext logContext = (LoggerContext) LogManager.getContext(false);File conFile = new File(configFilename);logContext.setConfigLocation(conFile.toURI());logContext.reconfigure();logger.debug("init log4j2 ok");}該方式只需要按照第一步刪除舊的 jar 包,上傳新的 jar 包,特別是 log4j-1.2-api-2.8.2.jar 包,即可無(wú)縫完成升級(jí)
關(guān)于 log4j2.xml 配置文件中的注意事項(xiàng)
1、關(guān)于 log4j2 日志等級(jí)組合過(guò)濾器的問(wèn)題
<!--日志級(jí)別以及優(yōu)先級(jí)排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL --> <Filters><ThresholdFilter level="warn" onMatch="DENY" onMismatch="NEUTRAL"/><ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/> </Filters> 表示只輸出 info <= level < warn 的 level 日志,也就是只打印 info 級(jí)別2、關(guān)于 DefaultRolloverStrategy 默認(rèn)刪除以及個(gè)數(shù)的問(wèn)題
注意%d{MM-dd-yyyy}要用年月日格式,不能加上時(shí)分秒,并且最后要有%i,這樣log4j2才能判斷出哪天一共產(chǎn)生幾個(gè)文件 示例: <RollingFile name="RollingFile" fileName="logs/app.log" filePattern="logs/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz">3、完整的 log4j2.xml 配置
<?xml version="1.0" encoding="UTF-8"?> <!--日志級(jí)別以及優(yōu)先級(jí)排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL --> <!--Configuration后面的status,這個(gè)用于設(shè)置log4j2自身內(nèi)部的信息輸出,可以不設(shè)置,當(dāng)設(shè)置成trace時(shí),你會(huì)看到log4j2內(nèi)部各種詳細(xì)輸出--> <!--monitorInterval:Log4j能夠自動(dòng)檢測(cè)修改配置 文件和重新配置本身,設(shè)置間隔秒數(shù)--> <configuration status="WARN" monitorInterval="30"><!--先定義所有的appender--><appenders><!--這個(gè)輸出控制臺(tái)的配置--><console name="con" target="SYSTEM_OUT"><!--輸出日志的格式--><Filters><ThresholdFilter level="ERROR" onMatch="ACCEPT" onMismatch="DENY"/></Filters><PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss:SSS}] [%p] - %l - %m%n"/></console><!--文件會(huì)打印出所有信息,這個(gè)log每次運(yùn)行程序會(huì)自動(dòng)清空,由append屬性決定,這個(gè)也挺有用的,適合臨時(shí)測(cè)試用--><!--<File name="log" fileName="log/test.log" append="false"><PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n"/></File>--><!-- 這個(gè)會(huì)打印出所有的info及以下級(jí)別的信息,每次大小超過(guò)size,則這size大小的日志會(huì)自動(dòng)存入按年份-月份建立的文件夾下面并進(jìn)行壓縮,作為存檔--><RollingFile name="sql" fileName="/export/home/rms/WEB/logs/sql/sql"filePattern="/export/home/rms/WEB/logs/sql/sql.%d{yyyy-MM-dd}-%i"><!--控制臺(tái)只輸出level及以上級(jí)別的信息(onMatch),其他的直接拒絕(onMismatch)--><Filters><ThresholdFilter level="warn" onMatch="DENY" onMismatch="NEUTRAL"/><ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/></Filters><PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss:SSS}] [%p] - %l - %m%n"/><Policies><TimeBasedTriggeringPolicy/><SizeBasedTriggeringPolicy size="100 MB"/></Policies></RollingFile><RollingFile name="log" fileName="/export/home/rms/WEB/logs/log/log"filePattern="/export/home/rms/WEB/logs/log/log.%d{yyyy-MM-dd}-%i"><Filters><ThresholdFilter level="error" onMatch="DENY" onMismatch="NEUTRAL"/><ThresholdFilter level="warn" onMatch="ACCEPT" onMismatch="DENY"/></Filters><PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss:SSS}] [%p] - %l - %m%n"/><Policies><TimeBasedTriggeringPolicy/><SizeBasedTriggeringPolicy size="100 MB"/></Policies><!-- DefaultRolloverStrategy屬性如不設(shè)置,則默認(rèn)為最多同一文件夾下7個(gè)文件,這里設(shè)置了20 --><DefaultRolloverStrategy max="20"/></RollingFile><RollingFile name="err" fileName="/export/home/rms/WEB/logs/err/err"filePattern="/export/home/rms/WEB/logs/err/err.%d{yyyy-MM-dd}-%i"><Filters><ThresholdFilter level="FATAL" onMatch="DENY" onMismatch="NEUTRAL"/><ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/></Filters><PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss:SSS}] [%p] - %l - %m%n"/><Policies><TimeBasedTriggeringPolicy/><SizeBasedTriggeringPolicy size="100 MB"/></Policies></RollingFile></appenders><!--然后定義logger,只有定義了logger并引入的appender,appender才會(huì)生效--><loggers><!--過(guò)濾掉spring和mybatis的一些無(wú)用的DEBUG信息--><logger name="org.springframework" level="error"></logger><logger name="org.mybatis" level="error"></logger><logger name="org.apache.struts2" level="error"></logger><logger name="org.apache.zookeeper" level="error"></logger><logger name="com.opensymphony.xwork2" level="error"></logger><root level="info"><appender-ref ref="con"/><appender-ref ref="sql"/><appender-ref ref="log"/><appender-ref ref="err"/></root></loggers> </configuration>衍生多線程配置問(wèn)題
不同的線程輸出日志到不同的文件中
不同的線程輸出日志到不同的文件中有關(guān) Log4j2 的內(nèi)容很多,在此不一一列出,這里只介紹一種常用方法。如果在開(kāi)發(fā)中遇到任何問(wèn)題,推薦去官方文檔中尋找解決方案。
實(shí)現(xiàn) StrLookup
修改 log4j2.xml 配置文件如下,主要是添加 Routes 標(biāo)簽:
實(shí)現(xiàn) StrLookup 中的 lookup 方法,代碼如下:
import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.config.plugins.Plugin; import org.apache.logging.log4j.core.lookup.StrLookup;(name = "thread", category = StrLookup.CATEGORY) public class ThreadLookup implements StrLookup {public String lookup(String s) {return Thread.currentThread().getName();}public String lookup(LogEvent logEvent, String s) {return logEvent.getThreadName() == null ? Thread.currentThread().getName(): logEvent.getThreadName();} }測(cè)試方法如下:
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger;public class TestLog2 {private static final Logger logger = LogManager.getLogger(TestLog2.class);public static void main(String[] args) {new Thread(() -> {logger.info("info");logger.debug("debug");logger.error("error");}).start();new Thread(() -> {logger.info("info");logger.debug("debug");logger.error("error");}).start();}}不同線程不同級(jí)別的日志輸出到不同的文件中
要實(shí)現(xiàn)該功能,還要從 RoutingAppender 身上做文章。RoutingAppender 主要用來(lái)評(píng)估 LogEvents,然后將它們路由到下級(jí) Appender。目標(biāo) Appender 可以是先前配置的并且可以由其名稱(chēng)引用的 Appender,或者可以根據(jù)需要?jiǎng)討B(tài)地創(chuàng)建 Appender。RoutingAppender 應(yīng)該在其引用的任何 Appenders 之后配置,以確保它可以正確關(guān)閉。 RoutingAppender 中的 name 屬性用來(lái)指定該 Appender 的名字,它可以包含多個(gè) Routes 子節(jié)點(diǎn),用來(lái)標(biāo)識(shí)選擇 Appender 的條件,而 Routes 只有一個(gè)屬性 “pattern”,該 pattern 用來(lái)評(píng)估所有注冊(cè)的 Lookups,并且其結(jié)果用于選擇路由。在 Routes 下可以有多個(gè) Route,每個(gè) Route 都必須配置一個(gè) key,如果這個(gè) key 匹配 “pattern” 的評(píng)估結(jié)果,那么這個(gè) Route 就被選中。同時(shí)每個(gè) Route 都必須引用一個(gè) Appender,如果這個(gè) Route 包含一個(gè) ref 屬性,那么這個(gè) Route 將引用一個(gè)在配置中定義的 Appender,如果這個(gè) Route 包含一個(gè) Appender 的定義,那么這個(gè) Appender 將會(huì)根據(jù) RoutingAppender 的上下文創(chuàng)建并被重用。 廢話(huà)說(shuō)多了,直接上配置才簡(jiǎn)潔明了。log4j2.xml 配置如下:
<?xml version="1.0" encoding="UTF-8"?> <!-- status 的含義為是否記錄 log4j2 本身的 event 信息,默認(rèn)是 OFF --> <Configuration status="OFF"><Properties><!-- 自定義一些常量,之后使用${變量名}引用 --><Property name="logFilePath">logs</Property><Property name="logFileName">testLog</Property></Properties><Appenders><!-- 很直白,Console 指定了結(jié)果輸出到控制臺(tái) --><Console name="ConsolePrint" target="SYSTEM_OUT"><PatternLayout pattern="%d{yyyy.MM.dd HH:mm:ss z} %t %-5level %class{36} %L %M - %msg%xEx%n"/></Console><!-- <File>輸出結(jié)果到指定文件</File> --><!-- <RollingFile>同樣輸出結(jié)果到指定文件,但是使用 buffer,速度會(huì)快點(diǎn)</RollingFile> --><!-- filePattern:表示當(dāng)日志到達(dá)指定的大小或者時(shí)間,產(chǎn)生新日志時(shí),舊日志的命名路徑 --><!-- PatternLayout:和 log4j 一樣,指定輸出日志的格式,append 表示是否追加內(nèi)容,值默認(rèn)為 true --><Routing name="RollingFileDebug_${thread:threadName}"><Routes pattern="$${thread:threadName}"><Route><RollingFile name="RollingFileDebug_${thread:threadName}"fileName="${logFilePath}/${logFileName}_${thread:threadName}_debug.log"filePattern="${logFilePath}/$${date:yyyy-MM}/${logFileName}-%d{yyyy-MM-dd}-${thread:threadName}-debug_%i.log.gz"><PatternLayout pattern="%d{yyyy.MM.dd HH:mm:ss z} %-5level %class{36} %L %M - %msg%xEx%n"/><!-- 注意,如果有多個(gè) ThresholdFilter,那么 Filters 標(biāo)簽是必須的 --><Filters><!-- 首先需要過(guò)濾不符合的日志級(jí)別,把不需要的首先 DENY 掉,然后在 ACCEPT 需要的日志級(jí)別,次序不能顛倒 --><!-- INFO 及以上級(jí)別拒絕輸出 --><ThresholdFilter level="INFO" onMatch="DENY" onMismatch="NEUTRAL"/><!-- 只輸出 DEBUG 級(jí)別信息 --><ThresholdFilter level="DEBUG" onMatch="ACCEPT" onMismatch="DENY"/></Filters><Policies><!-- 時(shí)間策略,每隔 24h 產(chǎn)生新的日志文件 --><TimeBasedTriggeringPolicy/><!-- 大小策略,每到 30MB 時(shí)產(chǎn)生新的日志文件 --><SizeBasedTriggeringPolicy size="30MB"/></Policies></RollingFile></Route></Routes></Routing><Routing name="RollingFileInfo_${thread:threadName}"><Routes pattern="$${thread:threadName}"><Route><RollingFile name="RollingFileInfo_${thread:threadName}"fileName="${logFilePath}/${logFileName}_${thread:threadName}_info.log"filePattern="${logFilePath}/$${date:yyyy-MM}/${logFileName}-%d{yyyy-MM-dd}-${thread:threadName}-info_%i.log.gz"><Filters><!-- onMatch:Action to take when the filter matches. The default value is NEUTRAL --><!-- onMismatch: Action to take when the filter does not match. The default value is DENY --><!-- 級(jí)別在 ERROR 之上的都拒絕輸出 --><!-- 在組合過(guò)濾器中,接受使用 NEUTRAL(中立),被第一個(gè)過(guò)濾器接受的日志信息,會(huì)繼續(xù)用后面的過(guò)濾器進(jìn)行過(guò)濾,只有符合所有過(guò)濾器條件的日志信息,才會(huì)被最終寫(xiě)入日志文件 --><ThresholdFilter level="ERROR" onMatch="DENY" onMismatch="NEUTRAL"/><ThresholdFilter level="INFO" onMatch="ACCEPT" onMismatch="DENY"/></Filters><PatternLayout pattern="%d{yyyy.MM.dd HH:mm:ss z} %-5level %class{36} %L %M - %msg%xEx%n"/><Policies><TimeBasedTriggeringPolicy/><SizeBasedTriggeringPolicy size="30MB"/></Policies></RollingFile></Route></Routes></Routing><Routing name="RollingFileError_${thread:threadName}"><Routes pattern="$${thread:threadName}"><Route><RollingFile name="RollingFileError_${thread:threadName}"fileName="${logFilePath}/${logFileName}_${thread:threadName}_error.log"filePattern="${logFilePath}/$${date:yyyy-MM}/${logFileName}-%d{yyyy-MM-dd}-${thread:threadName}-error_%i.log.gz"><Filters><ThresholdFilter level="ERROR" onMatch="ACCEPT" onMismatch="DENY"/></Filters><PatternLayout pattern="%d{yyyy.MM.dd HH:mm:ss z} %-5level %class{36} %L %M - %msg%xEx%n"/><Policies><TimeBasedTriggeringPolicy/><SizeBasedTriggeringPolicy size="30MB"/></Policies></RollingFile></Route></Routes></Routing><!-- bufferSize 整數(shù),指定可以排隊(duì)的 events 最大數(shù)量,如果使用 BlockingQueue,這個(gè)數(shù)字必須是 2 的冪次--><!-- includeLocation 默認(rèn)值是 FALSE,如果指定為 TRUE,會(huì)降低性能,但是推薦設(shè)置為 TRUE,否則不打印位置行信息--><Async name="async" bufferSize="262144" includeLocation="true"><AppenderRef ref="RollingFileDebug_${thread:threadName}"/><AppenderRef ref="RollingFileInfo_${thread:threadName}"/><AppenderRef ref="RollingFileError_${thread:threadName}"/><!-- 只要是級(jí)別比 ERROR 高的,包括 ERROR 就輸出到控制臺(tái) --><AppenderRef ref="ConsolePrint" level="ERROR"/></Async></Appenders><Loggers><!-- logger 用于定義 log 的 level 以及所采用的 appender,如果無(wú)需自定義,可以使用 root 解決,root 標(biāo)簽是 log 的默認(rèn)輸出形式 --><!-- 級(jí)別順序(低到高):TRACE < DEBUG < INFO < WARN < ERROR < FATAL --><Root level="DEBUG" includeLocation="true"><!-- appender-ref 中的值必須是在前面定義的 appender --><AppenderRef ref="async"/></Root></Loggers> </Configuration>Asynchronous 全局配置
根據(jù)官方的性能測(cè)試我們知道,Loggers all async 的性能最高,但是我們?cè)谏线吺褂玫氖?Sync 模式(方法一,因?yàn)?Appender 默認(rèn)是 synchronous 的)或 Async Appender 模式(方法二),那么如何更進(jìn)一步讓所有的 Loggers 都是 Asynchronous 的,讓我們的配置更完美呢?想要使用 Loggers all async 只需要做兩步操作。 因?yàn)?Loggers all async 是基于 LMAX Disruptor 實(shí)現(xiàn)的,所以我們首先需要添加這個(gè)依賴(lài)
<dependency><groupId>com.lmax</groupId><artifactId>disruptor</artifactId><version>3.4.2</version> </dependency>其次是設(shè)置系統(tǒng)屬性
log4j2.contextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector可以在前面提到的 ThreadLookup 類(lèi)中,添加靜態(tài)代碼塊
static {System.setProperty("log4j2.contextSelector", "org.apache.logging.log4j.core.async.AsyncLoggerContextSelector"); }在 src/main/resources 目錄下添加 log4j2.component.properties 配置文件,其內(nèi)容為
log4j2.contextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector混合使用 Synchronous 和 Asynchronous Loggers
依舊需要依賴(lài) com.lmax:disruptor,但不需要設(shè)置系統(tǒng)屬性 log4j2.contextSelector,在配置中可以混合使用同步和異步的 loggers,使用 <AsyncRoot> 或者 <AsyncLogger> 去指定需要異步的 loggers,<AsyncLogger> 元素還可以包含 <Root> 和 <Logger> 用于同步的 loggers。 一個(gè)混合了同步和異步的 Loggers 配置如下:
<?xml version="1.0" encoding="UTF-8"?> <!-- No need to set system property "Log4jContextSelector" to any valuewhen using <asyncLogger> or <asyncRoot>. --> <Configuration status="WARN"><Appenders><!-- Async Loggers will auto-flush in batches, so switch off immediateFlush. --><RandomAccessFile name="RandomAccessFile" fileName="asyncWithLocation.log"immediateFlush="false" append="false"><PatternLayout><Pattern>%d %p %class{1.} [%t] %location %m %ex%n</Pattern></PatternLayout></RandomAccessFile></Appenders><Loggers><!-- pattern layout actually uses location, so we need to include it --><AsyncLogger name="com.foo.Bar" level="trace" includeLocation="true"><AppenderRef ref="RandomAccessFile"/></AsyncLogger><Root level="info" includeLocation="true"><AppenderRef ref="RandomAccessFile"/></Root></Loggers> </Configuration>在上面示例的配置中,root logger 就是同步的,但是 com.foo.Bar 的 logger 就是異步的。
使用 Log4j 日志的注意事項(xiàng)
在使用異步日志的時(shí)候需要注意一些事項(xiàng),如下:
總結(jié)
以上是生活随笔為你收集整理的linux上设置了log4j没有产生日志文件_关于 log4j 升级到 log4j2 的小结的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 如何编写第三方接口_Python接口测试
- 下一篇: python dataframe gro