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

Posted

技术标签:

【中文标题】如何以编程方式在运行时添加 Log4J2 附加程序?【英文标题】:How to add Log4J2 appenders at runtime programmatically? 【发布时间】:2013-03-04 16:52:21 【问题描述】:

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

我打算在 log4j2.xml 中定义它,然后像这样根据情况选择附加程序(不会编译):

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

【问题讨论】:

这几乎没有重复,因为它是一个 log4j2 问题。链接的问题是指 log4j1(它甚至没有公开与 log4j2 相同的方法)和 slf4j。 我不确定关闭此问题的人是否知道它的实际含义。 现在,作为一种解决方法,我放弃了 log4j2 并迁移到了允许从 XML 配置动态构建的 Log4J(“Log4J1”)。 哦,我忘了我评论过这个。所以基本上 log4j2 背后的大想法是你不能(也不应该)以编程方式设置附加程序。所以你不能按设计来做。 阅读 RoutingAppender logging.apache.org/log4j/2.x/manual/… 可能 Log4j2 想要避免声明性和编程配置的混合,不知道为什么,但 RoutingAppender 解决方案似乎更干净。 【参考方案1】:

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

我觉得他们不想让你这样做,但这对我有用:

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

【讨论】:

太美了! :) 谢谢 - 我用它来做这个 - codingcraftsman.wordpress.com/2015/04/28/… 您通过转换为 org.apache.logging.log4j.core.Logger 节省了我的时间!谢谢!! 这对我来说非常有效:dontpanicblog.co.uk/2018/04/29/test-log4j2-with-junit【参考方案2】:

不知道有没有用: Appender 可以通过调用当前 Configuration 的 addLoggerAppender 方法添加到 Logger 中。 参考:http://logging.apache.org/log4j/2.x/manual/architecture.html

【讨论】:

addLoggerAppender 方法的文档说明它用于单元测试。【参考方案3】:

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

新的ConfigurationBuilder API 允许用户构造组件定义。使用此 API,无需直接使用实际配置对象(如 LoggerConfig 和 FileAppender),这需要大量了解 Log4j 如何在后台工作的知识。组件定义被添加到 ConfigurationBuilder 中,一旦收集了所有定义,所有实际的配置对象(如 Loggers 和 Appenders)就会被构建。感觉有点像 XML 配置语法,只不过你是在写 Java 代码。

请注意,新的ConfigurationBuilder API 允许用户代码创建新配置或完全替换现有配置。如果您的用例不同,并且您想在 Log4j 启​​动后以编程方式修改(而不是替换)现有配置,那么您将需要使用实际的配置对象。在这种情况下,请参阅手册的Programmatically Modifying the Current Configuration after Initialization 部分。

【讨论】:

我会注意到,我一直在寻找这个答案,它指向文档,但是文档中的示例现在使用了不推荐使用的方法,并且从未真正对我有用。我必须添加这样的东西才能让它工作: context.getRootLogger().addAppender(configuration.getAppender(appender.getName()));你也不能直接传入 appender,因为那也不起作用.... 如果您能提出一个 log4j2 JIRA 并提出修复文档的建议(给出正确方法的示例代码)以便其他人可以从您的经验中受益,我会很棒。 @RemkoPopma 现在是 log4j 2.12 版本。绝对需要一个更干净的 API 来停止和清除以编程方式创建的附加程序和记录器。 请在邮件列表中提出这个问题,最好提供补丁或拉取请求。 我正在考虑放弃 log4j。他们把事情复杂化到了荒谬的地步。你需要 2 小时来编写自己的日志框架,但要花 2 周时间来研究这个废话。【参考方案4】:

如上所述,我无法让https://logging.apache.org/log4j/2.x/manual/customconfig.html#AddingToCurrent 工作,至少不是我期望的那样(我的附加程序永远不会收到路由到它的消息)。我终于偶然发现了一个对我有用的模式 - 允许我在运行时添加一个 appender,并让该 appender 实际上将日志消息路由到它。

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

    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] %C2 (%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();

对我来说,一个关键点是调用 addAppender 并直接传递你的 appender 是行不通的,但按名称要求你的 appender 似乎是可行的。这没有意义……但是自从工作以来,我厌倦了在应该如此简单的事情上浪费时间……

【讨论】:

非常感谢您的回答!官方文档现在连log4j 2.14的接口都不匹配。这应该在官方文档中!【参考方案5】:

在 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() --> 将返回“Config”中的 Appenders。对我来说这是一个BUG

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

【讨论】:

以上是关于如何以编程方式在运行时添加 Log4J2 附加程序?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 VBA 以编程方式添加引用

带有路由附加程序的 Log4J2 不归档文件

Log4J2 - 在运行时分配文件附加程序文件名

WinForm C#如何将方法附加到以编程方式创建的控件

以编程方式在运行时删除或添加属性到CoreData

以编程方式将应用程序图标添加到安装时停靠