簡體   English   中英

如何根據 java 系統屬性有條件地添加 log4j2 appender?

[英]How do I conditionally add log4j2 appender depending on java system property?

我試圖弄清楚如何根據是否給定/設置了 java 系統屬性向記錄器添加附加程序。

所以假設我有一個這樣的基本配置:

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

所以現在我想找出一種方法,如果我提供參數 -PaddAppender2,則有條件地只添加第二個附加程序。 像這樣:

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

我怎么做?

例如,我知道我可以在給定屬性(“logLevel”)上使級別動態化(如果未給出屬性,則“信息”是默認值):

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

我查看了 filters 的文檔,但我無法弄清楚。 那當然是如果過濾器甚至是 go 的正確方法。

沒有任何腳本的解決方案:

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

類似於rgoers解決方案,但使用而不是 該解決方案受益於 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都會評估腳本。 因此,可以在運行時立即啟用/禁用附加程序(通過更改系統屬性的值)。 另一方面,腳本評估會對日志性能產生負面影響。

Robert 提供的解決方案有效,但效率不高,因為每個日志記錄都會評估腳本一次。

該評估腳本只有一次更有效的解決方案是使用ScriptAppenderSelector與一起NullAppender

根據文檔:

ScriptAppenderSelector

構建配置時,ScriptAppenderSelector appender 調用 Script 來計算 appender 名稱。 Log4j 然后使用 ScriptAppenderSelector 的名稱創建 AppenderSet 下列出的 appender 之一。 配置后,Log4j 會忽略 ScriptAppenderSelector。

空附加程序

忽略日志事件的 Appender。 用於與 version 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>

參考

我無法僅通過配置文件找出解決方案,但我找到了一個以編程方式解決問題的方法。

請注意,在我們的特定情況下,我們總是記錄到“本地日志”(“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>

基於此線程中的一些想法,以下是我為有條件地登錄到控制台所做的工作。

示例用例

  1. 始終記錄到文件附加程序。
  2. 僅在某些環境中登錄到控制台。

解決方案

  • 對於控制台日志記錄,設置系統屬性additional.log.appender=console
  • 或者,通過省略此屬性來禁用控制台日志記錄。
  • 在 Logger AppenderRef 中,使用${sys:additional.log.appender:-null}
    • 如果設置了系統屬性,則將日志發送到控制台附加程序,如果未設置,則默認為 null 附加程序。 (null appender 忽略日志)

系統屬性

# set for console logging
additional.log.appender=console

log4j2.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>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM