一、簡述
本文主要講如何基於Log4j2來實現自定義的Appender。一般用途是用於Log4j2自帶的Appender不足以滿足我們的需求,或者需要我們對日志進行攔截統計等操作時,需要我們自定義Appender。
二、自定義Appender
方法:實現一個類,讓它繼承自Log4j2的AbstractAppender,然后你重寫其append方法,並添加一個@PluginFactory標記的createAppender方法。
舉例:例如,我們要實現一個通過日志輸出的Level來統計計數來實現監控的一個Appender,並需要在配置日志時,實現對一些附加屬性的配置,可以如下實現。
package com.test.utils.logs; import org.apache.logging.log4j.core.Filter; import org.apache.logging.log4j.core.Layout; import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.appender.AbstractAppender; import org.apache.logging.log4j.core.config.plugins.Plugin; import org.apache.logging.log4j.core.config.plugins.PluginAttribute; import org.apache.logging.log4j.core.config.plugins.PluginElement; import org.apache.logging.log4j.core.config.plugins.PluginFactory; import org.apache.logging.log4j.core.layout.PatternLayout; import java.io.Serializable; @Plugin(name = "Statistics", category = "Core", elementType = "appender", printObject = true) public class StatisticsAppender extends AbstractAppender { /** 日志級別大於等於此級別及以上會進行判斷錯誤。默認:ERROR */ private String failedOnLogLevel; /** 指定時間內,出現多少次該日志級別,會被認為是錯誤。默認:10 */ private Integer failedOnLogLevelCount; /** 該日志級別以上持續出現多長時間,會被認為是錯誤。默認:30000 */ private Integer failedOnLogLevelInMisSecond; /** 當連續小於該日志級別多長時間后,恢復為正常狀態。默認:120000 */ private Integer recoveryOnLessLogLevelInMisSecond; protected StatisticsAppender(String name, Filter filter, Layout<? extends Serializable> layout, String failedOnLogLevel, Integer failedOnLogLevelCount, Integer failedOnLogLevelInMisSecond, Integer recoveryOnLessLogLevelInMisSecond) { super(name, filter, layout); this.failedOnLogLevel = failedOnLogLevel; this.failedOnLogLevelCount = failedOnLogLevelCount; this.failedOnLogLevelInMisSecond = failedOnLogLevelInMisSecond; this.recoveryOnLessLogLevelInMisSecond = recoveryOnLessLogLevelInMisSecond; } @Override public void append(LogEvent logEvent) { //此處省略告警過濾統計代碼。 // ..... String msg = logEvent.getMessage().getFormattedMessage(); System.out.println(msg); } @PluginFactory public static StatisticsAppender createAppender(@PluginAttribute("name") String name, @PluginElement("Filter") final Filter filter, @PluginElement("Layout") Layout<? extends Serializable> layout, @PluginAttribute("failedOnLogLevel") String failedOnLogLevel, @PluginAttribute("failedOnLogLevelCount") Integer failedOnLogLevelCount, @PluginAttribute("failedOnLogLevelInMisSecond") Integer failedOnLogLevelInMisSecond, @PluginAttribute("recoveryOnLessLogLevelInMisSecond") Integer recoveryOnLessLogLevelInMisSecond) { if (name == null) { LOGGER.error("No name provided for MyCustomAppenderImpl"); return null; } if (layout == null) { layout = PatternLayout.createDefaultLayout(); } if (failedOnLogLevel == null) { failedOnLogLevel = "ERROR"; } if (failedOnLogLevelCount == null) { failedOnLogLevelCount = 10; } if (failedOnLogLevelInMisSecond == null) { failedOnLogLevelInMisSecond = 30000; } if (recoveryOnLessLogLevelInMisSecond == null) { recoveryOnLessLogLevelInMisSecond = 120000; } return new StatisticsAppender(name, filter, layout, failedOnLogLevel, failedOnLogLevelCount, failedOnLogLevelInMisSecond, recoveryOnLessLogLevelInMisSecond); } }
說明:注意黃色區域的地方,另外createAppender方法中,紅色的參數表示XML中要配置的Appender屬性。
三、配置log4j2.xml文件
<?xml version="1.0" encoding="UTF-8"?> <configuration status="ON" packages="org.apache.logging.log4j.core,io.sentry.log4j2,com.test.utils.logs"> <appenders> <Console name="Console" target="SYSTEM_OUT"> <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/> </Console> <RollingFile name="RollingFile" fileName="datamerge-logs/app.log" filePattern="datamerge-logs/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz"> <PatternLayout pattern="%d{yyyy.MM.dd 'at' HH:mm:ss z} %-5level %class{36} %L %M - %msg%xEx%n"/> <SizeBasedTriggeringPolicy size="300 MB"/> </RollingFile> <Sentry name="Sentry"/> <Statistics name="StatisticsMonitor" failedOnLogLevel="ERROR" failedOnLogLevelCount="10" failedOnLogLevelInMisSecond="30000" recoveryOnLessLogLevelInMisSecond="120000"/> </appenders> <loggers> <root level="INFO"> <appender-ref ref="Console"/> <!--<appender-ref ref="RollingFile"/>--> <!--<appender-ref ref="Sentry" level="ERROR" />--> <appender-ref ref="StatisticsMonitor"/> </root> </loggers> </configuration>
說明,請仔細閱讀黃色區域的內容。packages中要標注Appender所在的包名(不同的包名請使用","分隔)
四、調用
正常調用日志即可。需要說明的是,Appender會在程序啟動后第一次調用日志時,實例化一次Appender,之后就不會再實例化了。之后會多次調用append方法。