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

Posted

技术标签:

【中文标题】Log4J2 - 在运行时分配文件附加程序文件名【英文标题】:Log4J2 - assigning file appender filename at runtime 【发布时间】:2013-01-29 13:02:15 【问题描述】:

我在类路径中有一个 log4j2.xml 配置文件。其中一个附加程序是文件附加程序,我想在 Java 应用程序的运行时设置目标文件名。

根据docs,我应该可以在 log4j2.xml 文件中使用双“$”和上下文前缀:

<appenders>
    <File name="MyFile" fileName="$$sys:logFilename">
        <PatternLayout pattern="%-4r %d$datestamp [%t] %-5level %logger36 - %msg%n"/>
    </File>
</appenders>

其中“sys”前缀表示配置器将在系统属性中查找属性“logFilename”。所以在应用程序中,我调用(相当早):

System.setProperty("logFilename", filename);

我还在 xml 文件中开启了 log4j2 的自动重新配置:

<configuration status="debug" monitorInterval="5">>

不幸的是,这没有任何效果,并且永远不会创建日志文件。部分 log4j2 状态输出如下:

2013-02-13 15:36:37,574 调试在类 org.apache.logging.log4j.core.appender.FileAppender 上为元素文件调用 createAppender 参数(fileName="$sys:logFilename", append= “null”,locking="null",name="MyFile",immediateFlush="null",suppressExceptions="null",bufferedIO="null",PatternLayout(%-4r %dyyyy-MM-dd/HH: mm:ss.SSS/zzz [%t] %-5level %logger36 - %msg%n), null)

2013-02-13 15:36:37,576 调试启动文件管理器 $sys:logFilename

如何在运行时设置 File Appender 中“fileName”的值? 或者,如何在运行时简单地将新的 File Appender 添加到根记录器?在 Log4j 2.0 中大部分用于更改配置的 API 都是隐藏的。

【问题讨论】:

进行 SO 搜索。已经回答:***.com/questions/10699358/… 这是一个 Log4j 2.0 的问题,所以 API 与 Log4j 1.2 有很大的不同,之前的答案中的很多方法都没有暴露出来。 【参考方案1】:

您可以做的是,在运行应用程序时,将 logFilename 作为参数传递给 JVM:

java -DlogFilename=myAppName.log -jar /path/to/myApp.jar

【讨论】:

【参考方案2】:

从 log4j2 版本 2.5 开始,这是实现此目的的最简单方法:

在你的log4j2.xml

<Appenders>
   <File name="MyFile" filename="$sys:logFilename">
   ...

在你的主MyApp.java文件中

public class MyApp 

    Logger log;

    static 
          System.setProperty("logFilename", ...);
          log = LogManager.getLogger();
    

    public static void main(String... args) ...

CATCH:您应该在加载 log4j2 之前设置 logFilename 系统属性。在这个例子中调用LogManager.getLogger之前。

【讨论】:

这不行,它只会创建$sys/logFilename文件 这在我的命令行独立应用程序中对我有用。您可能会遇到问题,因为您依赖的一些其他代码比您想象的更早地初始化了 log4j2。你能描述一下你尝试这个的环境吗?它是 Web 应用程序还是命令行工具? +1 表示警告!这就是问题所在。我试图这样做,但总是得到第二个空文件$sys/logFilename【参考方案3】:

我知道这个话题很老,但答案并不适合我。这是一个允许您在运行时重新配置现有 Appender 的函数:

static void updateLogger(String file_name, String appender_name, String package_name)
LoggerContext context = (LoggerContext) LogManager.getContext(false);
    Configuration configuration = context.getConfiguration();
    Layout<? extends Serializable> old_layout = configuration.getAppender(appender_name).getLayout();

    //delete old appender/logger
    configuration.getAppender(appender_name).stop();
    configuration.removeLogger(package_name);

    //create new appender/logger
    LoggerConfig loggerConfig = new LoggerConfig(package_name, Level.INFO, false);
    FileAppender appender = FileAppender.createAppender(file_name, "false", "false", appender_name, "true", "true", "true",
            "8192", old_layout, null, "false", "", configuration);
    appender.start();
    loggerConfig.addAppender(appender, Level.INFO, null);
    configuration.addLogger(package_name, loggerConfig);

    context.updateLoggers();

您可以指定文件名、appender 名称和要记录的包名称。

示例记录器:

<File name="fileWriter_api" fileName="$LOG_DIR/api.log" append="false">
  <PatternLayout pattern="$PATTERN"/>
</File>

可以像这样重新配置调用:

updateLogger("log/api_new.log", "fileWriter_api", "my.package");

【讨论】:

这是一个很好的答案! 这适用于命名的附加程序和包,但会停止所有其他附加程序。您是否遇到过这个问题,是否知道如何解决它? 我会省略 loggerConfig.addAppender(appender, Level.INFO, null); 行中的 leve.INFO 规范,因为即使您更改记录器的日志级别,它也无法通过此附加程序记录 DEBUG 或 TRACE 事件. 你为我节省了很多时间。谢谢。【参考方案4】:

h/t rgoers FileAppender 不支持文件名上的两个美元符号,因为在启动 appender 时打开了文件。您用两个美元符号表示的是您希望(可能)为每个事件使用不同的文件名。

使用单个 $(如$sys:logFilename),系统将在系统属性中查找属性“logFilename”。

因此,log4j2.xml 应该有:

<appenders>
    <File name="MyFile" fileName="$sys:logFilename">
        <PatternLayout pattern="%-4r %d$datestamp [%t] %-5level %logger36 - %msg%n"/>
    </File>
</appenders>

Java 应用程序应该设置系统属性:

System.setProperty("logFilename", filename);

重新配置记录器:

org.apache.logging.log4j.core.LoggerContext ctx =
    (org.apache.logging.log4j.core.LoggerContext) LogManager.getContext(false);
ctx.reconfigure();

这会产生所需的行为。

【讨论】:

我不确定这是否是因为 API 已更改,但这对我不起作用。为了让它发挥作用,我必须做的是$sys:logFilename 使用版本 2.0-beta9 和单个 $ 这将创建两个文件,一个具有正确名称但内容为空,另一个具有所有日志输出的字面名称为 $sys:logFilename.log LoggerContext.reconfigure 在 log4j2 版本 2.5 中被删除。所以这个方案不能用。 @AlexYursha 我目前正在使用org.apache.logging.log4j:log4j-core:2.6.1,并且使用该方法没有问题(甚至没有收到弃用警告)。 你可以使用this solution而不依赖log4j2的实现细节。唯一的问题是您必须在记录任何内容之前定义系统属性。

以上是关于Log4J2 - 在运行时分配文件附加程序文件名的主要内容,如果未能解决你的问题,请参考以下文章

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

创建一个 MiniDump,不包括运行时分配的内存范围

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

创建迁移文件时分配默认值

log4j2 未找到 1 个记录器的附加程序

Kivy- 在选择 Recycleview 时分配变量