log4j2.xml文件詳解及在日志中加入全局guid

log4j2.xml文件及在日志中加入全局guid

<Configuration status="WARN" monitorInterval="30">
    <Appenders>
    	<!-- 輸出到控制臺 -->
        <Console name="STDOUT" target="SYSTEM_OUT">
        	<!-- 
        	   %d 日期
        	   %p 日志級別
        	   %c 輸出所屬的類目,通常就是所在類的全名 
        	  [%t] 線程
        	   - %m 輸出代碼中指定的消息
        	   %n  換行
        	   %L : 日志輸出所在行數
               %M : 日志輸出所在方法名
        	 -->
           <PatternLayout pattern="%d %p %c [%t] - %m%n"/>
        </Console>
 
		<!-- 這個會打印出所有的info及以下級別的信息,每次大小超過size,則這size大小的日志會自動存入按年份-月份-日建立的文件夾下面並進行壓縮,作為存檔 -->
		<RollingFile name="RollingFileInfo" fileName="${sys:user.home}/logs/info.log"
			filePattern="${sys:user.home}/logs/provider/${date:yyyy-MM-dd}/info-%d{yyyy-MM-dd}-%i.log.gz">
			<!--控制臺隻輸出level及以上級別的信息(onMatch),其他的直接拒絕(onMismatch) -->
			<ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY" />
			<PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n" />
			<Policies>
				 <SizeBasedTriggeringPolicy size="100 MB" />
				 <!-- 切割文件的話最多切割多少個 -->
				 <DefaultRolloverStrategy max="20"/>
			</Policies>
		</RollingFile>
		
		<!-- 按照天來存儲,過瞭這天的東西會被保存為壓縮包,並且配置瞭大小分割 -->
		<RollingFile name="InfoFileAppender" fileName="${sys:user.home}/logs/info.log"
                     filePattern="${sys:user.home}/logs/provider/${date:yyyy-MM-dd}/info-%d{yyyy-MM-dd}-%i.log.gz">
            <PatternLayout pattern="%d %-5p %c:%L [%t] - %m%n"/>
            <Policies>
            	<!-- 時間滾動策略,默認1小時 -->
                <TimeBasedTriggeringPolicy modulate="true" interval="24"/>
            </Policies>
        </RollingFile>
        
       
    </Appenders>
 
	<!--然後定義logger,隻有定義瞭logger並引入的appender,appender才會生效-->
    <Loggers>
    	<Logger name="com.opensymphony.xwork2.ognl.OgnlValueStack" level="ERROR"/>
        <logger name="org.springframework" level="INFO"></logger>
        <logger name="org.mybatis" level="INFO"></logger>
        <Logger name="net.sf.ehcache" level="INFO"/>
        <Logger name="com.alisoft.xplatform.asf" level="WARN"/>
        <Logger name="com.mbi" level="ERROR"/>
        <Logger name="net.mlw" level="INFO"/>
        <Logger name="java.sql" level="INFO"/>
        <Logger name="org.hibernate.type" level="ERROR"/>
        <Logger name="com.opensymphony.webwork" level="ERROR"/>
        <Logger name="org.apache" level="INFO"/>
        <Logger name="org.jgroups" level="WARN"/>
        <Logger name="org.jboss.axis" level="INFO"/>
        <Logger name="org.jboss.management" level="INFO"/>
        <Logger name="org.apache.commons.httpclient" level="ERROR"/>
        <Logger name="org.springframework" level="INFO"/>
        <Logger name="org.springboot" level="INFO" />
 
		<!-- 缺省日志級別,如果package有定制級別,則按package的定制級別走,即使package級別更低 -->
        <Root level="INFO">
            <AppenderRef ref="STDOUT"/>
            <AppenderRef ref="RollingFileInfo"/>
            <!-- <AppenderRef ref="InfoFileAppender"/> -->
        </Root>
    </Loggers>
    
</Configuration>
<AppenderRef ref="STDOUT"/>

隻有定義瞭這個,上面的才會真實有效

  • 日志信息輸出到文件中,超過指定大小壓縮存檔
  • 日志信息輸出到文件中,按照日期來壓縮存檔

想在日志中加入全局guid需要修改日志的格式

加入自定義參數H

<PatternLayout pattern="%d %-5p %c:%L [%t] -%H %n"/>
/**
 * 有時候需要在日志中實現類似aop的效果,統一加進去某些參數。對於這種需要,log4j2則可以使用插件機制
 * Plugin 表示的是這是一個插件,name是名稱,category為PatternConverter.CATEGORY(目前插件隻有這個選擇)
   ConverterKeys表示的就是自定義的參數,可以多個
 * @author yp-tc-m-7129
 *
 */
@Plugin(name = "LogPatternConverter", category = PatternConverter.CATEGORY)
@ConverterKeys({ "H" })
public class LogPatternConverter extends LogEventPatternConverter {
	
	/**
	 * 檢查全局guid是否正確 - GUID[45a696c385f341efbebf05fd0b3b1344] - TYPE[MANUAL] 
	 * @param args
	 */
	/*public static void main(String[] args) {
		System.out.println(getPayplusLogUUID());
	}*/
	
	private static final LogPatternConverter INSTANCE = new LogPatternConverter();
 
    public static LogPatternConverter newInstance(final String[] options) {
        return INSTANCE;
    }
 
    private LogPatternConverter(){
        super("LogId", "logId");
    }
 
	/**
	 * 另外的格式化日志,在日志中加入一個全局guid
	 * 這裡有兩個參數,LogEvent是系統已經存在的一些可選數據,StringBuilder 表示的是最終的輸出字符流。一般都是將自定義的append進去
	 */
	@Override
	public void format(LogEvent event, StringBuilder builder) {
		final Message msg = event.getMessage();
		if (msg != null) {
			String result = msg.getFormattedMessage();
			result = getPayplusLogUUID() + result;
			builder.append(result);
		}
	}
	
	/**
	 * 業務日志全局UUID
	 *
	 * @return
	 */
	protected  String getPayplusLogUUID() {
		StringBuilder builder = new StringBuilder();
		if (!ThreadContextUtils.contextInitialized()) {
			ThreadContextUtils.initContext("applicationName", null, ThreadContextType.MANUAL);
		}
		builder.append("- GUID[");
		builder.append(ThreadContextUtils.getContext().getThreadUID());
		builder.append("] - TYPE[");
		builder.append(ThreadContextUtils.getContext().getType());
		builder.append("] ");
		return builder.toString();
	}
 
}

這樣就在日志中加入瞭全局guid用於查詢日志處理問題瞭。

log4j2.x配置文件中各標簽

log4j2.0以後我們通常在log4j2.xml中配置相關參數,在配置的時候我們需要理解這些參數的具體含義,下面列出瞭這些參數的解釋。

1、Logger 完成日志信息的處理

<logger name="com.srd.ljzd" level="INFO" additivity="true">
    <appender-ref ref="INFO" />
    <appender-ref ref="WARN" />
    <appender-ref ref="ERROR" />
    <appender-ref ref="Mail" />
</logger>

logger中的name是指代碼的包名或類名,路徑要寫全,可以配置不同包中的日志輸出到不同的文件中。level是日志輸出級別,定義輸出的層次和決定信息是否輸出,

DEBUG<INFO<WARN<ERROR

additivity設置事件是否在root logger輸出,為瞭避免重復輸出,可以在Logger 標簽下設置additivity為”false”。

2、Appender 設置在哪輸出日志信息

  • FileAppender:普通地輸出到本地文件
  • FlumeAppender:將幾個不同源的日志匯集、集中到一處。
  • JMSQueueAppender VS. JMSTopicAppender:與JMS相關的日志輸出
  • RewriteAppender:對日志事件進行掩碼或註入信息
  • RollingFileAppender:對日志文件進行封存(詳細)
  • RoutingAppender:在輸出地之間進行篩選路由
  • SMTPAppender:將LogEvent發送到指定郵件列表
  • SocketAppender:將LogEvent以普通格式發送到遠程主機
  • SyslogAppender:將LogEvent以RFC 5424格式發送到遠程主機
  • AsynchAppender:將一個LogEvent異步地寫入多個不同輸出地
  • ConsoleAppender:將LogEvent輸出到命令行
  • FailoverAppender:維護一個隊列,系統將嘗試向隊列中的Appender依次輸出LogEvent,直到有一個成功為止

其中ConsoleAppender、RollingFileAppender和SMTPAppender較為常用。如果想詳細瞭解,可以參考log4j的官方文檔

  • ConsoleAppender將輸出寫到System.err或System.out。如果想將輸出寫到System.out,設置Console標簽下的target為”SYSTEM_OUT”即可;如果想將輸出寫到System.err,設置Console標簽下的target為”SYSTEM_ERR “即可。
  • RollingFileAppender跟FileAppender的基本用法一樣。但RollingFileAppender可以設置log文件的size(單位:KB/MB/GB)上限、數量上限,當log文件超過設置的size上限,會自動被壓縮。RollingFileAppender可以理解為滾動輸出日志,如果log4j 2記錄的日志達到上限,舊的日志將被刪除,騰出的空間用於記錄新的日志,DefaultRolloverStrategy 標簽的max設置壓縮文件的上限(默認值為7)。
  • SMTPAppender主要用來給指定的E-mail發送log event。
<SMTP name="Mail" subject="****SaaS系統正式版異常信息" to="[email protected]" from="[email protected]" smtpUsername="[email protected]" smtpPassword="LENG****1234" smtpHost="mail.lengjing.info" smtpDebug="false" smtpPort="25" bufferSize="10">
    <PatternLayout pattern="[%-5p]:%d{YYYY-MM-dd HH:mm:ss} [%t] %c{1}:%L - %msg%n" />
        </SMTP>

SMTPAppender默認情況下隻發送ERROR級別以上的日志,在測試的時候會發現低級別的日志是不會通過郵箱發送的。

3、Layout 設置日志信息的輸出格式

layout有以下幾種:

  • org.apache.log4j.HTMLLayout(以HTML表格形式佈局)
  • org.apache.log4j.SimpleLayout(包含日志訊息的級別和訊息字符串)
  • org.apache.log4j.TTCCLayout(包含日志產生的時間、執行緒、類別等訊息)
  • org.apache.log4j.PatterLayout(可以靈活地指定佈局格式)

詳細配置可以參考官方文檔。

4、Filters

Filter可以過濾log事件,並控制log輸出,詳細配置可以參考官方文檔。

例如ThresholdFilter 可以實現單個log級別的過濾功能。

5、Status

<Configuration status="OFF" monitorInterval="30">

log4j 2定義的status級別有8個:ALL,TRACE, DEBUG, INFO, WARN, ERROR ,FATAL,OFF。其實status屬性是幫助開發者找錯用的,它可以檢測log4j 2的配置文件是否有錯,也可以檢測到死循環的logger。

6、monitorInterval

<Configuration status="OFF" monitorInterval="30">

通過設置monitorInterval屬性,即可設置log4j 2自動檢測配置文件的時間間隔(單位:秒),最小間隔為5秒。log4j 2檢測到配置文件有變化,會重新配置自己。

7、Policies 配置日志相關策略

  • SizeBasedTriggeringPolicy:設置日志大小達到一定大小後打包生成壓縮文件。
  • TimeBasedTriggeringPolicy:基於時間的觸發策略。該策略主要是完成周期性的log文件封存工作。有兩個參數:
  • intervalinteger型,指定兩次封存動作之間的時間間隔。單位:以日志的命名精度來確定單位,比如yyyy-MM-dd-HH 單位為小時,yyyy-MM-dd-HH-mm 單位為分鐘。
  • modulateboolean型,說明是否對封存時間進行調制。若modulate=true,則封存時間將以0點為邊界進行偏移計算。比如,modulate=true,interval=4hours,那麼假設上次封存日志的時間為03:00,則下次封存日志的時間為04:00,之後的封存時間依次為08:00,12:00,16:00。

這裡將我在項目中常用配置貢獻給大傢,可以滿足大部分需求。

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="OFF" monitorInterval="30">
    <properties>
        <!--設置日志在硬盤上輸出的目錄-->
        <property name="logPath">D:/ljzx_log</property>
    </properties>
    <Appenders>
        <!--設置在控制臺打印日志-->
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="[%-5p]:%d{YYYY-MM-dd HH:mm:ss} [%t] %c{1}:%L - %msg%n" />
        </Console>
        <!--設置級別為INFO日志輸出到info.log中-->
        <RollingFile name="INFO" filename="${logPath}/info.log"
                     filepattern="${logPath}/%d{YYYYMMdd}-%i-info.log.zip">
            <Filters>
                <!--設置隻輸出級別為INFO的日志-->
                <ThresholdFilter level="INFO"/>
                <ThresholdFilter level="WARN" onMatch="DENY" onMismatch="NEUTRAL"/>
            </Filters>
            <PatternLayout pattern="[ %-5p]:%d{YYYY-MM-dd HH:mm:ss} [%t] %c{1}:%L - %msg%n" />
            <Policies>
                <!--設置每天打包日志一次-->
                <TimeBasedTriggeringPolicy interval="1" modulate="true"/>
                <!--設置日志文件滿1MB後打包-->
                <SizeBasedTriggeringPolicy size="1 MB" />
            </Policies>
            <DefaultRolloverStrategy max="20" />
        </RollingFile>
        <!--設置級別為WARN日志輸出到warn.log中-->
        <RollingFile name="WARN" filename="${logPath}/warn.log"
                     filepattern="${logPath}/%d{YYYYMMdd}-%i-warn.log.zip">
            <Filters>
                <!--設置隻輸出級別為WARN的日志-->
                <ThresholdFilter level="WARN"/>
                <ThresholdFilter level="ERROR" onMatch="DENY" onMismatch="NEUTRAL"/>
            </Filters>
            <PatternLayout pattern="[ %-5p]:%d{YYYY-MM-dd HH:mm:ss} [%t] %c{1}:%L - %msg%n" />
            <Policies>
                <!--設置每天打包日志一次-->
                <TimeBasedTriggeringPolicy interval="1" modulate="true"/>
                <!--設置日志文件滿1MB後打包-->
                <SizeBasedTriggeringPolicy size="1 MB" />
            </Policies>
            <DefaultRolloverStrategy max="20" />
        </RollingFile>
        <!--設置級別為ERROR日志輸出到error.log中-->
        <RollingFile name="ERROR" filename="${logPath}/error.log"
                     filepattern="${logPath}/%d{YYYYMMdd}-%i-error.log.zip">
            <!--設置隻輸出級別為ERROR的日志-->
            <ThresholdFilter level="ERROR"/>
            <PatternLayout pattern="[ %-5p]:%d{YYYY-MM-dd HH:mm:ss} [%t] %c{1}:%L - %msg%n" />
            <Policies>
                <!--設置每天打包日志一次-->
                <TimeBasedTriggeringPolicy interval="1" modulate="true"/>
                <!--設置日志文件滿1MB後打包-->
                <SizeBasedTriggeringPolicy size="1 MB" />
            </Policies>
            <DefaultRolloverStrategy max="20" />
        </RollingFile>
        <!--設置通過郵件發送日志信息-->
        <SMTP name="Mail" subject="XXXXSaaS系統正式版異常信息" to="[email protected]" from="[email protected]" 
              smtpUsername="[email protected]" smtpPassword="LENG****1234" smtpHost="mail.lengjing.info" smtpDebug="false" 
              smtpPort="25" bufferSize="10">
            <PatternLayout pattern="[%-5p]:%d{YYYY-MM-dd HH:mm:ss} [%t] %c{1}:%L - %msg%n" />
        </SMTP>
    </Appenders>
    <Loggers>
        <logger name="com.srd.ljzd" level="INFO" additivity="true">
            <appender-ref ref="INFO" />
            <appender-ref ref="WARN" />
            <appender-ref ref="ERROR" />
            <appender-ref ref="Mail" />
        </logger>
        <root level="DEBUG">
            <appender-ref ref="Console"/>
        </root>
    </Loggers>
</Configuration>

以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。

推薦閱讀: