如何根据java系统属性有条件地添加log4j2 appender?

alen0pnh  于 2022-11-06  发布在  Java
关注(0)|答案(6)|浏览(188)

我试图弄清楚如何根据是否给定/设置了java系统属性来向记录器添加附加器。
假设我有这样一个基本配置:

<Logger name="myLogger" level="info" additivity="false">
  <AppenderRef ref="myAppender1" />
  <AppenderRef ref="myAppender2" />
</Logger>

所以现在我想找出一种方法,如果我提供了一个参数-PaddAppender 2,那么就有条件地只添加第二个appender。

<Logger name="myLogger" level="info" additivity="false">
  <AppenderRef ref="myAppender1" />
  <?if (${sys:enableAppender2:-false) == "true"}>
  <AppenderRef ref="myAppender2" />
  </?if> 
</Logger>

我该怎么做呢?
例如,我可以在给定的属性(“logLevel”)上动态设置级别,如下所示(如果没有给定该属性,则“info”为默认值):

<Logger name="test" level="${sys:logLevel:-info}" additivity="false">

我看了看documentation for filters,我想不出来。当然,如果过滤器是正确的方式去这里。

pu3pd22g

pu3pd22g1#

无需任何脚本的解决方案:

<?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>
rfbsl7qr

rfbsl7qr2#

Robert提供的解决方案可以工作,但效率不高,因为每个日志记录只评估一次脚本。
一个更有效的解决方案是将ScriptAppenderSelectorNullAppender一起使用,该解决方案只对脚本求值一次:
根据文件:

脚本追加器选择器

建置组态时,ScriptAppenderSelector附加程式会呼叫指令码来计算附加程式名称。Log4j接着会使用ScriptAppenderSelector的名称,建立AppenderSet下列示的其中一个附加程式名称。组态之后,Log4j会忽略ScriptAppenderSelector。

空追加器

忽略日志事件的追加器。用于与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>

参考

6l7fqoea

6l7fqoea3#

类似于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>

请注意,每次发生Log4j事件时,ScriptFilter都会对脚本进行求值。因此,可以在运行时启用/禁用附加程序(通过更改系统属性的值),并且立即生效。另一方面,脚本求值可能会对事件记录性能产生负面影响。

unhi4e5o

unhi4e5o4#

我无法单独通过配置文件找到解决方案,但我找到了一个通过编程解决问题的方法。
请注意,在我们的特定情况下,我们总是记录到“本地日志”(“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);
        }
    }
}

如果有人知道如何通过配置文件单独做到这一点,这将是伟大的。

mec1mxoz

mec1mxoz5#

处理此问题的方法是使用筛选器。在这种情况下,可以使用脚本筛选器。

<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>
w6mmgewl

w6mmgewl6#

基于本文中的一些想法,下面是我对有条件地登录到控制台所做的工作。

用例示例

1.始终记录到文件附加程序。
1.仅在某些环境中登录到控制台。

溶液

  • 对于控制台日志记录,请设置系统属性additional.log.appender=console
  • 或者,通过省略此属性禁用控制台日志记录。
  • 在记录器AppenderRef中,使用${sys:additional.log.appender:-null}
  • 如果设置了系统属性,则将日志发送到控制台附加器;如果未设置,则默认为空附加器。(空附加器忽略日志)
    系统属性

# set for console logging

additional.log.appender=console

日志4j2.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
    <Appenders>
        <RollingFile name="file"
            fileName="my-file.log"
            filePattern="my-file%i.log">
            <PatternLayout pattern="%d %5p [%t] %c - %m%n" />
            <Policies>
                <SizeBasedTriggeringPolicy size="10 MB" />
            </Policies>
            <DefaultRolloverStrategy max="10" />
        </RollingFile>

        <Console name="console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d %5p [%t] %c - %m%n" />
        </Console>

        <Null name="null" />
    </Appenders>

    <Loggers>
        <Logger name="com.acme" level="DEBUG">
        </Logger>

        <Root level="INFO">
            <AppenderRef ref="file" />
            <AppenderRef ref="${sys:additional.log.appender:-null}" />
        </Root>
    </Loggers>
</Configuration>

相关问题