linux上设置了log4j没有产生日志文件_关于 log4j 升级到 log4j2 的小结
關于升級 jar 包等前提要求
- 刪掉原先的 log4j-1.XX 等 jar 包
- 從 1.XX 升級到 2.XX 平穩升級需要的 jar 包,其中包括用 sl4j-1.7.25 (1.7.21 暫時也不需要升級) 的版本包,具體可以看自己的工程配置是否需要
- slf4j-log4j-升級到 2.8.2.zip
- 新建 log4j2.xml 配置文件
對于 tomcat 項目的版本要求:(以 7.0.43 為分界線),目前 jdk1.8 可以在 tomcat 7.0.32 ,7.0.94 正常啟動代碼
三種配置方式:
1、關于 log4j2.xml 的默認存放位置(WEB 項目可以使用)
按照官方推薦默認放到 resource 目錄下面,名稱必須叫 log4j2.xml ,其余文件名會讀取失敗,無需配置其它文件,如下圖:
2、關于使用自定義路徑配置文件(推薦 jar 包讀取外部配置文件,比如 Eserver ItmsService 等模塊)
2.1 在代碼的 web.xml 文件里,增加如下配置,其中 param-value 為配置文件的絕對路徑,包含 file:// 開頭文件
<!-- 配置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 文件的開頭關于 servlet 的版本,因為 tomcat 7.0 之后,lib 包里面的 servlet-api.jar 包的版本是 3.0,所以必須修改 web.xml 的版本聲明,否則會無法初始化 log4j2。
(將圖一三個標紅的地方應該改為 3.0),結果如圖二 圖一:
圖二:
<?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、自定義路徑并且實現相關 jar 包的預留接口(不需要改動代碼和配置,目前只需要替換相關的 jar 包,把新建的 log4j2.xml 改名為 log4j.xml ,并且放在原先同級目錄即可)
針對目前代碼現狀,為了不改動配置和代碼,實現了 log4j-1.2-api-2.8.2.jar 預留的相關接口,具體哪個接口需要查看原本工程初始化 log4j 的類用的是哪個接口,比如 org.apache.log4j.xml.DOMConfigurator 類里面的相關接口,如下所示:
private static Logger logger = LoggerFactory.getLogger(DOMConfigurator.class); // 如下相關通用實現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 包,即可無縫完成升級
關于 log4j2.xml 配置文件中的注意事項
1、關于 log4j2 日志等級組合過濾器的問題
<!--日志級別以及優先級排序: 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 級別2、關于 DefaultRolloverStrategy 默認刪除以及個數的問題
注意%d{MM-dd-yyyy}要用年月日格式,不能加上時分秒,并且最后要有%i,這樣log4j2才能判斷出哪天一共產生幾個文件 示例: <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"?> <!--日志級別以及優先級排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL --> <!--Configuration后面的status,這個用于設置log4j2自身內部的信息輸出,可以不設置,當設置成trace時,你會看到log4j2內部各種詳細輸出--> <!--monitorInterval:Log4j能夠自動檢測修改配置 文件和重新配置本身,設置間隔秒數--> <configuration status="WARN" monitorInterval="30"><!--先定義所有的appender--><appenders><!--這個輸出控制臺的配置--><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><!--文件會打印出所有信息,這個log每次運行程序會自動清空,由append屬性決定,這個也挺有用的,適合臨時測試用--><!--<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>--><!-- 這個會打印出所有的info及以下級別的信息,每次大小超過size,則這size大小的日志會自動存入按年份-月份建立的文件夾下面并進行壓縮,作為存檔--><RollingFile name="sql" fileName="/export/home/rms/WEB/logs/sql/sql"filePattern="/export/home/rms/WEB/logs/sql/sql.%d{yyyy-MM-dd}-%i"><!--控制臺只輸出level及以上級別的信息(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屬性如不設置,則默認為最多同一文件夾下7個文件,這里設置了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才會生效--><loggers><!--過濾掉spring和mybatis的一些無用的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>衍生多線程配置問題
不同的線程輸出日志到不同的文件中
不同的線程輸出日志到不同的文件中有關 Log4j2 的內容很多,在此不一一列出,這里只介紹一種常用方法。如果在開發中遇到任何問題,推薦去官方文檔中尋找解決方案。
實現 StrLookup
修改 log4j2.xml 配置文件如下,主要是添加 Routes 標簽:
實現 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();} }測試方法如下:
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();}}不同線程不同級別的日志輸出到不同的文件中
要實現該功能,還要從 RoutingAppender 身上做文章。RoutingAppender 主要用來評估 LogEvents,然后將它們路由到下級 Appender。目標 Appender 可以是先前配置的并且可以由其名稱引用的 Appender,或者可以根據需要動態地創建 Appender。RoutingAppender 應該在其引用的任何 Appenders 之后配置,以確保它可以正確關閉。 RoutingAppender 中的 name 屬性用來指定該 Appender 的名字,它可以包含多個 Routes 子節點,用來標識選擇 Appender 的條件,而 Routes 只有一個屬性 “pattern”,該 pattern 用來評估所有注冊的 Lookups,并且其結果用于選擇路由。在 Routes 下可以有多個 Route,每個 Route 都必須配置一個 key,如果這個 key 匹配 “pattern” 的評估結果,那么這個 Route 就被選中。同時每個 Route 都必須引用一個 Appender,如果這個 Route 包含一個 ref 屬性,那么這個 Route 將引用一個在配置中定義的 Appender,如果這個 Route 包含一個 Appender 的定義,那么這個 Appender 將會根據 RoutingAppender 的上下文創建并被重用。 廢話說多了,直接上配置才簡潔明了。log4j2.xml 配置如下:
<?xml version="1.0" encoding="UTF-8"?> <!-- status 的含義為是否記錄 log4j2 本身的 event 信息,默認是 OFF --> <Configuration status="OFF"><Properties><!-- 自定義一些常量,之后使用${變量名}引用 --><Property name="logFilePath">logs</Property><Property name="logFileName">testLog</Property></Properties><Appenders><!-- 很直白,Console 指定了結果輸出到控制臺 --><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>輸出結果到指定文件</File> --><!-- <RollingFile>同樣輸出結果到指定文件,但是使用 buffer,速度會快點</RollingFile> --><!-- filePattern:表示當日志到達指定的大小或者時間,產生新日志時,舊日志的命名路徑 --><!-- PatternLayout:和 log4j 一樣,指定輸出日志的格式,append 表示是否追加內容,值默認為 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"/><!-- 注意,如果有多個 ThresholdFilter,那么 Filters 標簽是必須的 --><Filters><!-- 首先需要過濾不符合的日志級別,把不需要的首先 DENY 掉,然后在 ACCEPT 需要的日志級別,次序不能顛倒 --><!-- INFO 及以上級別拒絕輸出 --><ThresholdFilter level="INFO" onMatch="DENY" onMismatch="NEUTRAL"/><!-- 只輸出 DEBUG 級別信息 --><ThresholdFilter level="DEBUG" onMatch="ACCEPT" onMismatch="DENY"/></Filters><Policies><!-- 時間策略,每隔 24h 產生新的日志文件 --><TimeBasedTriggeringPolicy/><!-- 大小策略,每到 30MB 時產生新的日志文件 --><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 --><!-- 級別在 ERROR 之上的都拒絕輸出 --><!-- 在組合過濾器中,接受使用 NEUTRAL(中立),被第一個過濾器接受的日志信息,會繼續用后面的過濾器進行過濾,只有符合所有過濾器條件的日志信息,才會被最終寫入日志文件 --><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 整數,指定可以排隊的 events 最大數量,如果使用 BlockingQueue,這個數字必須是 2 的冪次--><!-- includeLocation 默認值是 FALSE,如果指定為 TRUE,會降低性能,但是推薦設置為 TRUE,否則不打印位置行信息--><Async name="async" bufferSize="262144" includeLocation="true"><AppenderRef ref="RollingFileDebug_${thread:threadName}"/><AppenderRef ref="RollingFileInfo_${thread:threadName}"/><AppenderRef ref="RollingFileError_${thread:threadName}"/><!-- 只要是級別比 ERROR 高的,包括 ERROR 就輸出到控制臺 --><AppenderRef ref="ConsolePrint" level="ERROR"/></Async></Appenders><Loggers><!-- logger 用于定義 log 的 level 以及所采用的 appender,如果無需自定義,可以使用 root 解決,root 標簽是 log 的默認輸出形式 --><!-- 級別順序(低到高):TRACE < DEBUG < INFO < WARN < ERROR < FATAL --><Root level="DEBUG" includeLocation="true"><!-- appender-ref 中的值必須是在前面定義的 appender --><AppenderRef ref="async"/></Root></Loggers> </Configuration>Asynchronous 全局配置
根據官方的性能測試我們知道,Loggers all async 的性能最高,但是我們在上邊使用的是 Sync 模式(方法一,因為 Appender 默認是 synchronous 的)或 Async Appender 模式(方法二),那么如何更進一步讓所有的 Loggers 都是 Asynchronous 的,讓我們的配置更完美呢?想要使用 Loggers all async 只需要做兩步操作。 因為 Loggers all async 是基于 LMAX Disruptor 實現的,所以我們首先需要添加這個依賴
<dependency><groupId>com.lmax</groupId><artifactId>disruptor</artifactId><version>3.4.2</version> </dependency>其次是設置系統屬性
log4j2.contextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector可以在前面提到的 ThreadLookup 類中,添加靜態代碼塊
static {System.setProperty("log4j2.contextSelector", "org.apache.logging.log4j.core.async.AsyncLoggerContextSelector"); }在 src/main/resources 目錄下添加 log4j2.component.properties 配置文件,其內容為
log4j2.contextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector混合使用 Synchronous 和 Asynchronous Loggers
依舊需要依賴 com.lmax:disruptor,但不需要設置系統屬性 log4j2.contextSelector,在配置中可以混合使用同步和異步的 loggers,使用 <AsyncRoot> 或者 <AsyncLogger> 去指定需要異步的 loggers,<AsyncLogger> 元素還可以包含 <Root> 和 <Logger> 用于同步的 loggers。 一個混合了同步和異步的 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 日志的注意事項
在使用異步日志的時候需要注意一些事項,如下:
總結
以上是生活随笔為你收集整理的linux上设置了log4j没有产生日志文件_关于 log4j 升级到 log4j2 的小结的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何编写第三方接口_Python接口测试
- 下一篇: python dataframe gro