如何根据java系统属性有条件地添加log4j2 appender?
我试图弄清楚如何根据是否给定/设置java系统属性,向记录器添加appender 假设我有一个这样的基本配置:如何根据java系统属性有条件地添加log4j2 appender?,java,log4j,log4j2,nashorn,groovy,Java,Log4j,Log4j2,Nashorn,Groovy,我试图弄清楚如何根据是否给定/设置java系统属性,向记录器添加appender 假设我有一个这样的基本配置: <Logger name="myLogger" level="info" additivity="false"> <AppenderRef ref="myAppender1" /> <AppenderRef ref="myAppender2" /> </Logger> <Logger name="myLogger" lev
<Logger name="myLogger" level="info" additivity="false">
<AppenderRef ref="myAppender1" />
<AppenderRef ref="myAppender2" />
</Logger>
<Logger name="myLogger" level="info" additivity="false">
<AppenderRef ref="myAppender1" />
<?if (${sys:enableAppender2:-false) == "true"}>
<AppenderRef ref="myAppender2" />
</?if>
</Logger>
,我想不出来。当然,如果过滤器是正确的方法,那么这就是问题所在。我无法单独通过配置文件找到解决方案,但我找到了一个通过编程解决问题的方法
请注意,在我们的特定情况下,我们总是登录到“本地日志”(“splunk local”),但在给定的情况下(由属性控制),我们还希望将相同的信息记录到另一个位置(非相对位置),并定期读取并转发到splunk服务器(“splunk转发器”)
这就是为什么我们可以将大多数属性从一个记录器复制到另一个记录器
private static final Logger SPLUNK_LOG = getLogger();
private static Logger getLogger() {
if (!BooleanUtils.toBoolean(SystemUtils.getJavaPropertyValue(ENABLE_PROPERTY_NAME, "false"))) {
return LoggerFactory.getLogger(SPLUNK_LOG_NAME);
} else {
LOG.info("Dynamically adding splunk forwarder appender");
try {
final LoggerContext loggerContext = (LoggerContext) LogManager.getContext();
final Configuration configuration = loggerContext.getConfiguration();
// configure appender based on local splunk appender
final RollingFileAppender splunkLocal = (RollingFileAppender) configuration.getAppender(LOCAL_LOG_NAME);
final RollingFileAppender splunkForwarder = RollingFileAppender.createAppender(FORWARDER_FILE_NAME,
FORWARDER_FILE_PATTERN, FORWARDER_APPEND, FORWARDER_NAME, null, null, null,
splunkLocal.getManager().getTriggeringPolicy(), splunkLocal.getManager().getRolloverStrategy(),
splunkLocal.getLayout(), splunkLocal.getFilter(), null, FORWARDER_ADVERTISE, null, null);
splunkForwarder.start();
// add splunk forwarder appender to splunk logger
final LoggerConfig loggerConfig = configuration.getLoggerConfig(SPLUNK_LOG_NAME);
loggerConfig.addAppender(splunkForwarder, Level.INFO, null);
LOG.info("Successfully added splunk forwarder appender");
return loggerContext.getLogger(SPLUNK_LOG_NAME);
} catch (Exception ex) {
throw new IllegalStateException("Failed to dynamically add splunk forwarder appender", ex);
}
}
}
如果有人知道如何单独通过配置文件来实现这一点,那就太好了。处理这一问题的方法是使用过滤器。在这种情况下,可以使用脚本过滤器
<Logger name="myLogger" level="info" additivity="false">
<AppenderRef ref="myAppender1" />
<AppenderRef ref="myAppender2">
<ScriptFilter onMatch="ACCEPT" onMisMatch="DENY">
<Script language="groovy"><![CDATA[
return System.getProperty("enableAppender2", "false").equalsIgnoreCase("true");
]]></Script>
</ScriptFilter>
</AppenderRef>
</Logger>
类似于解决方案,但使用代替。此解决方案得益于Nashorn引擎是
Java8,因此不需要额外的依赖项
<Scripts>
<Script name="isAppender2Enabled" language="nashorn"><![CDATA[
var System = Java.type('java.lang.System'),
Boolean = Java.type('java.lang.Boolean');
Boolean.parseBoolean(System.getProperty('enableAppender2', 'false'));
]]></Script>
</Scripts>
<Loggers>
<Logger name="myLogger" level="info" additivity="false">
<AppenderRef ref="myAppender1" />
<AppenderRef ref="myAppender2">
<ScriptFilter onMatch="ACCEPT" onMisMatch="DENY">
<ScriptRef ref="isAppender2Enabled" />
</ScriptFilter>
</AppenderRef>
</Logger>
</Loggers>
请注意,ScriptFilter
每次发生Log4j事件时都在评估脚本。因此,可以在运行时启用/禁用appender(通过更改系统属性的值),并立即生效。另一方面,脚本评估可能会对日志记录性能产生负面影响。不使用任何脚本的解决方案:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="error" strict="true">
<Properties>
<Property name="appenderToUse">stdout_${sys:LOG4J_LAYOUT:-plain}</Property>
</Properties>
<Appenders>
<Appender type="Console" name="stdout_plain">
<Layout type="PatternLayout" pattern="%d [%t] %-5p %c - %m%n"/>
</Appender>
<Appender type="Console" name="stdout_json">
<Layout type="JSONLayout" compact="true" eventEol="true" stacktraceAsString="true" properties="true"/>
</Appender>
</Appenders>
<Loggers>
<Root level="info">
<AppenderRef ref="${appenderToUse}"/>
</Root>
</Loggers>
</Configuration>
标准输出${sys:LOG4J_布局:-plain}
Robert提供的解决方案可行,但效率不高,因为每个日志记录将对脚本进行一次评估
仅对脚本进行一次评估的更有效的解决方案是与以下工具一起使用:
根据文件:
脚本附加选择器
构建配置时,ScriptAppenderSelector appender调用脚本以计算appender名称。Log4j然后使用ScriptAppenderSelector的名称创建AppenderSet下列出的一个appender。配置之后,Log4j忽略ScriptAppenderSelector
空附加器
忽略日志事件的追加器。用于与1.2版兼容,并便于编写ScriptAppenderSelector
警告:Nashorn JavaScript引擎在Java 11中被标记为已弃用-请参阅Mark Reinhold的推文:。Java 11中产生了以下警告:警告:Nashorn引擎计划从未来的JDK版本中删除
。您可以使用JVM选项来防止打印警告:-Dnashorn.args=“--无弃用警告”
。与NullAppender
结合使用,此解决方案让我很高兴-现在我可以在需要时打开/关闭控制台appender!即使是内联工作,也没有显式的
声明
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="error" strict="true">
<Properties>
<Property name="appenderToUse">stdout_${sys:LOG4J_LAYOUT:-plain}</Property>
</Properties>
<Appenders>
<Appender type="Console" name="stdout_plain">
<Layout type="PatternLayout" pattern="%d [%t] %-5p %c - %m%n"/>
</Appender>
<Appender type="Console" name="stdout_json">
<Layout type="JSONLayout" compact="true" eventEol="true" stacktraceAsString="true" properties="true"/>
</Appender>
</Appenders>
<Loggers>
<Root level="info">
<AppenderRef ref="${appenderToUse}"/>
</Root>
</Loggers>
</Configuration>