我试图找出如何根据是否给出/设置java系统属性来向记录器添加appender。
所以,让我说我有这样的基本配置:
<Logger name="myLogger" level="info" additivity="false">
<AppenderRef ref="myAppender1" />
<AppenderRef ref="myAppender2" />
</Logger>
所以现在我想找出一种方法,如果我提供参数-PaddAppender2,有条件地只添加第二个appender。像这样:
<Logger name="myLogger" level="info" additivity="false">
<AppenderRef ref="myAppender1" />
<?if (${sys:enableAppender2:-false) == "true"}>
<AppenderRef ref="myAppender2" />
</?if>
</Logger>
我该怎么做?
我知道我可以例如在给定属性(&#34; logLevel&#34;)上创建动态级别(如果未给出属性,则&#34; info&#34;是默认值):
<Logger name="test" level="${sys:logLevel:-info}" additivity="false">
我看了documentation for filters,我无法弄明白。当然,如果过滤器甚至是走到这里的正确方法。
答案 0 :(得分:3)
与rgoers解决方案类似,但使用nashorn代替groovy。这个解决方案得益于Nashorn引擎的一部分 Java 8因此不需要额外的依赖项。
<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(通过更改系统属性的值)。另一方面,脚本评估会对日志记录性能产生负面影响。
答案 1 :(得分:1)
Robert提供的解决方案有效,但是效率不高,因为每个日志记录都会对脚本进行一次评估。
仅对脚本进行一次评估的更有效的解决方案是将ScriptAppenderSelector
与NullAppender
一起使用:
根据文档:
构建配置后,ScriptAppenderSelector附加程序调用脚本来计算附加程序名称。然后,Log4j使用ScriptAppenderSelector的名称创建在AppenderSet下列出的名称的附加程序之一。配置后,Log4j将忽略ScriptAppenderSelector。
忽略日志事件的Appender。用于与1.2版兼容, 可方便地编写ScriptAppenderSelector 。
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn" name="ScriptAppenderSelectorExample">
<Appenders>
<ScriptAppenderSelector name="SelectConsole">
<Script language="groovy"><![CDATA[
if (System.getProperty("CONSOLE_APPENDER_ENABLED", 'true').equalsIgnoreCase('true')) {
return "Console"
} else {
return "Null"
}
]]></Script>
<AppenderSet>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</Console>
<Null name="Null" />
</AppenderSet>
</ScriptAppenderSelector>
<ScriptAppenderSelector name="SelectFile">
<Script language="groovy"><![CDATA[
if (System.getProperty("FILE_APPENDER_ENABLED", 'true').equalsIgnoreCase('true')) {
return "File"
} else {
return "Null"
}
]]></Script>
<AppenderSet>
<File name="File" fileName="application.log">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
</File>
<Null name="Null" />
</AppenderSet>
</ScriptAppenderSelector>
<ScriptAppenderSelector name="SelectSMTP">
<Script language="groovy"><![CDATA[
if (System.getProperty("SMTP_APPENDER_ENABLED", 'true').equalsIgnoreCase('true')) {
return "SMTP"
} else {
return "Null"
}
]]></Script>
<AppenderSet>
<SMTP name="SMTP"
subject="App: Error"
from="log4j@example.com"
to="support@example.com"
smtpHost="smtp.example.com"
smtpPort="25"
bufferSize="5">
</SMTP>
<Null name="Null" />
</AppenderSet>
</ScriptAppenderSelector>
</Appenders>
<Loggers>
<Root level="info">
<AppenderRef ref="SelectConsole"/>
<AppenderRef ref="SelectFile"/>
<AppenderRef ref="SelectSMTP"/>
</Root>
</Loggers>
</Configuration>
答案 2 :(得分:0)
我无法单独通过配置文件找出解决方案,但我找到了一个以编程方式解决问题的解决方案。
请注意,在我们的特定情况下,我们始终记录到“本地日志”(“splunk local”),但在给定的情况下(由属性控制),我们还希望将相同的信息记录到另一个位置(不是相对的)并定期读取并转发到splunk服务器(“splunk forwarder”)。
这就是为什么我们可以将大多数属性从一个记录器复制到另一个记录器。
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);
}
}
}
如果有人知道如何通过配置文件单独执行此操作,那就太棒了。
答案 3 :(得分:0)
要处理的方式是使用过滤器。在这种情况下,您可以使用脚本过滤器。
<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>
答案 4 :(得分:0)
无需任何脚本的解决方案:
<?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>