一、简述
本文主要讲如何基于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方法。