如何以编程方式在运行时添加Log4J2 appender?

时间:2021-05-09 21:53:20

Is it possible to add Log4J2 appenders programmatically using the specifications from the XML configuration?

是否可以使用XML配置中的规范以编程方式添加Log4J2 appender?

I plan to define it all in the log4j2.xml and then pick appenders situationally like this (won't compile):

我计划在log4j2.xml中定义它,然后像这样选择appender(不会编译):

if (arg[0].equals("log") ) {
    Logger.getLogger("loggerNameFromXMLConfig").addAppender("appenderNameFromXMLConfig");
} else {
    //...
}

5 个解决方案

#1


17  

Edit: for the newest versions of log4j2, see https://*.com/a/33472893/1899566 instead.

编辑:对于最新版本的log4j2,请参阅https://*.com/a/33472893/1899566。

I get the impression they don't want you doing this, but this works for me:

我得到的印象是他们不希望你这样做,但这对我有用:

if (arg[0].equals("log") ) {
  org.apache.logging.log4j.Logger logger
    = org.apache.logging.log4j.LogManager.getLogger("loggerNameFromXMLConfig");
  org.apache.logging.log4j.core.Logger coreLogger
    = (org.apache.logging.log4j.core.Logger)logger;
  org.apache.logging.log4j.core.LoggerContext context
    = (org.apache.logging.log4j.core.LoggerContext)coreLogger.getContext();
  org.apache.logging.log4j.core.config.BaseConfiguration configuration
    = (org.apache.logging.log4j.core.config.BaseConfiguration)context.getConfiguration();

  coreLogger.addAppender(configuration.getAppender("appenderNameFromXMLConfig"));
} else {
  //...
}

#2


21  

There have been a number of requests to support better programmatic configuration for Log4j 2. Sorry it took so long. As of Log4j 2.4, API was added to log4j-core to facilitate programmatic configuration.

已经有很多请求支持Log4j 2的更好的编程配置。抱歉,花了这么长时间。从Log4j 2.4开始,API被添加到log4j-core以便于编程配置。

The new ConfigurationBuilder API allows users to construct component definitions. With this API, there is no need to work directly with actual configuration objects (like LoggerConfig and FileAppender) which require a lot of knowledge on how Log4j works under the hood. Component definitions are added to the ConfigurationBuilder, and once all the definitions have been collected all the actual configuration objects (like Loggers and Appenders) are constructed. It feels a bit like the XML configuration syntax, except that you are writing Java code.

新的ConfigurationBuilder API允许用户构造组件定义。使用此API,无需直接使用实际配置对象(如LoggerConfig和FileAppender),这些对象需要大量了解Log4j如何工作。组件定义被添加到ConfigurationBuilder中,一旦收集了所有定义,就构造了所有实际配置对象(如Loggers和Appender)。感觉有点像XML配置语法,除了您正在编写Java代码。

Note that the new ConfigurationBuilder API allows user code to create a new configuration or completely replace the existing configuration. If your use case is different, and you want to programmatically modify (rather than replace) an existing configuration after Log4j was started, then you will need to work with actual configuration objects. In that case, please see the Programmatically Modifying the Current Configuration after Initialization section of the manual.

请注意,新的ConfigurationBuilder API允许用户代码创建新配置或完全替换现有配置。如果您的用例不同,并且您希望在Log4j启动后以编程方式修改(而不是替换)现有配置,那么您将需要使用实际的配置对象。在这种情况下,请参阅本手册中“以编程方式修改初始化后的当前配置”部分。

#3


1  

I don't know if it's useful: An Appender can be added to a Logger by calling the addLoggerAppender method of the current Configuration. reference:http://logging.apache.org/log4j/2.x/manual/architecture.html

我不知道它是否有用:可以通过调用当前配置的addLoggerAppender方法将Appender添加到Logger中。参考文献:http://logging.apache.org/log4j/2.x/manual/architecture.html

#4


1  

As I noted above, I couldn't get https://logging.apache.org/log4j/2.x/manual/customconfig.html#AddingToCurrent to work, at least, not the way I expected it to (my appender would never get messages routed to it). I did finally stumble across a pattern that works for me - allowing me to add an appender at runtime, and have that appender actually get log messages routed to it.

正如我上面提到的,我无法得到https://logging.apache.org/log4j/2.x/manual/customconfig.html#AddingToCurrent,至少不是我预期的方式(我的appender会永远不会将消息路由到它)。我最终偶然发现了一个适合我的模式 - 允许我在运行时添加一个appender,并让那个appender实际上将日志消息路由到它。

Edit I removed a bunch of confusing code from here that wasn't doing anything....

编辑我从这里删除了一堆令人困惑的代码,没有做任何事......

    LoggerContext lc = (LoggerContext) LogManager.getContext(false);
    FileAppender fa = FileAppender.newBuilder().withName("mylogger").withAppend(false).withFileName(new File(outputDirectory, "ConsoleOutput.txt").toString())
            .withLayout(PatternLayout.newBuilder().withPattern("%-5p %d  [%t] %C{2} (%F:%L) - %m%n").build())
            .setConfiguration(lc.getConfiguration()).build();
    fa.start();
    lc.getConfiguration().addAppender(fa);
    lc.getRootLogger().addAppender(lc.getConfiguration().getAppender(fa.getName()));
    lc.updateLoggers();

A key point for me, was that calling addAppender and passing your appender directly doesn't work, but asking for your appender back by name seems to. Which doesn't make sense... but since working, and I'm tired of wasting time on something that should be so simple....

对我而言,一个关键点是调用addAppender并直接传递你的appender不起作用,但似乎要求你的appender返回名字。哪个没有意义......但是自从工作以来,我已经厌倦了在一些应该如此简单的事情上浪费时间......

#5


0  

In Log4j2 structure

在Log4j2结构中

        ---"Config"---
                Appenders
                        Appender(0)
                            Console
                        Appender(1)
                            File
                    LoggerConfigs
                        -- LoggerConfig(0) 
                        -- LoggerConfig(1)
                        -- LoggerConfig(2)

        ----"LoggerConfig"----
                - AppenderRefs
                    -- AppenderRef(0)
                        -- Name Console
                        -- Level : DEBUG
                - Appenders
                    -- Appender(0)
                        -- Name Console
                        -- Level : DEBUG
                - Level -- ALL

loggerConfig.getAppenders() --> Will return the Appenders in "Config". For me this is a BUG

loggerConfig.getAppenders() - >将在“Config”中返回Appenders。对我来说这是一个BUG

loggerConfig.getAppenderRefs() --> is working well !!

loggerConfig.getAppenderRefs() - >运行良好!!

#1


17  

Edit: for the newest versions of log4j2, see https://*.com/a/33472893/1899566 instead.

编辑:对于最新版本的log4j2,请参阅https://*.com/a/33472893/1899566。

I get the impression they don't want you doing this, but this works for me:

我得到的印象是他们不希望你这样做,但这对我有用:

if (arg[0].equals("log") ) {
  org.apache.logging.log4j.Logger logger
    = org.apache.logging.log4j.LogManager.getLogger("loggerNameFromXMLConfig");
  org.apache.logging.log4j.core.Logger coreLogger
    = (org.apache.logging.log4j.core.Logger)logger;
  org.apache.logging.log4j.core.LoggerContext context
    = (org.apache.logging.log4j.core.LoggerContext)coreLogger.getContext();
  org.apache.logging.log4j.core.config.BaseConfiguration configuration
    = (org.apache.logging.log4j.core.config.BaseConfiguration)context.getConfiguration();

  coreLogger.addAppender(configuration.getAppender("appenderNameFromXMLConfig"));
} else {
  //...
}

#2


21  

There have been a number of requests to support better programmatic configuration for Log4j 2. Sorry it took so long. As of Log4j 2.4, API was added to log4j-core to facilitate programmatic configuration.

已经有很多请求支持Log4j 2的更好的编程配置。抱歉,花了这么长时间。从Log4j 2.4开始,API被添加到log4j-core以便于编程配置。

The new ConfigurationBuilder API allows users to construct component definitions. With this API, there is no need to work directly with actual configuration objects (like LoggerConfig and FileAppender) which require a lot of knowledge on how Log4j works under the hood. Component definitions are added to the ConfigurationBuilder, and once all the definitions have been collected all the actual configuration objects (like Loggers and Appenders) are constructed. It feels a bit like the XML configuration syntax, except that you are writing Java code.

新的ConfigurationBuilder API允许用户构造组件定义。使用此API,无需直接使用实际配置对象(如LoggerConfig和FileAppender),这些对象需要大量了解Log4j如何工作。组件定义被添加到ConfigurationBuilder中,一旦收集了所有定义,就构造了所有实际配置对象(如Loggers和Appender)。感觉有点像XML配置语法,除了您正在编写Java代码。

Note that the new ConfigurationBuilder API allows user code to create a new configuration or completely replace the existing configuration. If your use case is different, and you want to programmatically modify (rather than replace) an existing configuration after Log4j was started, then you will need to work with actual configuration objects. In that case, please see the Programmatically Modifying the Current Configuration after Initialization section of the manual.

请注意,新的ConfigurationBuilder API允许用户代码创建新配置或完全替换现有配置。如果您的用例不同,并且您希望在Log4j启动后以编程方式修改(而不是替换)现有配置,那么您将需要使用实际的配置对象。在这种情况下,请参阅本手册中“以编程方式修改初始化后的当前配置”部分。

#3


1  

I don't know if it's useful: An Appender can be added to a Logger by calling the addLoggerAppender method of the current Configuration. reference:http://logging.apache.org/log4j/2.x/manual/architecture.html

我不知道它是否有用:可以通过调用当前配置的addLoggerAppender方法将Appender添加到Logger中。参考文献:http://logging.apache.org/log4j/2.x/manual/architecture.html

#4


1  

As I noted above, I couldn't get https://logging.apache.org/log4j/2.x/manual/customconfig.html#AddingToCurrent to work, at least, not the way I expected it to (my appender would never get messages routed to it). I did finally stumble across a pattern that works for me - allowing me to add an appender at runtime, and have that appender actually get log messages routed to it.

正如我上面提到的,我无法得到https://logging.apache.org/log4j/2.x/manual/customconfig.html#AddingToCurrent,至少不是我预期的方式(我的appender会永远不会将消息路由到它)。我最终偶然发现了一个适合我的模式 - 允许我在运行时添加一个appender,并让那个appender实际上将日志消息路由到它。

Edit I removed a bunch of confusing code from here that wasn't doing anything....

编辑我从这里删除了一堆令人困惑的代码,没有做任何事......

    LoggerContext lc = (LoggerContext) LogManager.getContext(false);
    FileAppender fa = FileAppender.newBuilder().withName("mylogger").withAppend(false).withFileName(new File(outputDirectory, "ConsoleOutput.txt").toString())
            .withLayout(PatternLayout.newBuilder().withPattern("%-5p %d  [%t] %C{2} (%F:%L) - %m%n").build())
            .setConfiguration(lc.getConfiguration()).build();
    fa.start();
    lc.getConfiguration().addAppender(fa);
    lc.getRootLogger().addAppender(lc.getConfiguration().getAppender(fa.getName()));
    lc.updateLoggers();

A key point for me, was that calling addAppender and passing your appender directly doesn't work, but asking for your appender back by name seems to. Which doesn't make sense... but since working, and I'm tired of wasting time on something that should be so simple....

对我而言,一个关键点是调用addAppender并直接传递你的appender不起作用,但似乎要求你的appender返回名字。哪个没有意义......但是自从工作以来,我已经厌倦了在一些应该如此简单的事情上浪费时间......

#5


0  

In Log4j2 structure

在Log4j2结构中

        ---"Config"---
                Appenders
                        Appender(0)
                            Console
                        Appender(1)
                            File
                    LoggerConfigs
                        -- LoggerConfig(0) 
                        -- LoggerConfig(1)
                        -- LoggerConfig(2)

        ----"LoggerConfig"----
                - AppenderRefs
                    -- AppenderRef(0)
                        -- Name Console
                        -- Level : DEBUG
                - Appenders
                    -- Appender(0)
                        -- Name Console
                        -- Level : DEBUG
                - Level -- ALL

loggerConfig.getAppenders() --> Will return the Appenders in "Config". For me this is a BUG

loggerConfig.getAppenders() - >将在“Config”中返回Appenders。对我来说这是一个BUG

loggerConfig.getAppenderRefs() --> is working well !!

loggerConfig.getAppenderRefs() - >运行良好!!