【问题标题】:Log4J2 - assigning file appender filename at runtimeLog4J2 - 在运行时分配文件附加程序文件名
【发布时间】: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 %logger{36} - %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 %d{yyyy-MM-dd/HH: mm:ss.SSS/zzz} [%t] %-5level %logger{36} - %msg%n), null)

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

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

【问题讨论】:

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

标签: java log4j log4j2


【解决方案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 %logger{36} - %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的实现细节。唯一的问题是您必须在记录任何内容之前定义系统属性。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-07-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-27
    • 1970-01-01
    • 2023-04-05
    相关资源
    最近更新 更多