在运行时更新 Log4J2 Appender 的文件路径

问题描述 投票:0回答:1

对于一个项目,我有一个多次启动的程序,我想将其每次运行记录到不同的文件中。我已经准备好了所需的一切,例如保存特定运行的预期日志记录位置的变量。

现在的问题是我无法正确更新 LoggerContext 的 RollingFileAppenders。看起来它们被正确创建,然后我似乎也能够正确地用新的 Appender 替换旧的 Appender,但是当我实际执行一些

log.debug(...)
或其他任何操作时,配置总是返回到旧的 Appender原因。然后日志记录将无处可去,甚至不会记录到 Appender 之前设置的文件中。

我已经查看了文档,但是this似乎表明我正在做的事情应该有效。

现在,这就是我正在做的事情:

LoggerContext context = (LoggerContext) LogManager.getContext(false);
Configuration config = context.getConfiguration();
RollingFileAppender oldAppender = config.getAppender(appenderName);

if (oldAppender != null) {
    oldAppender.stop();

    if (!newBasePath.endsWith("\\")) {
        newBasePath += "\\";
    }
    if (!logFileName.endsWith(".log")) {
        logFileName += ".log";
    }
    String newFileName = newBasePath + logFileName;
    String newFilePattern = newBasePath + "model_%d{yyyyMMdd}-%i.log.gz";

    // Create a new RollingFileAppender with the new file path, reusing the old configuration
    RollingFileManager manager = oldAppender.getManager();
    RollingFileAppender newAppender = RollingFileAppender.newBuilder()
                .setName(appenderName)
                .withFileName(newFileName)
                .withFilePattern(newFilePattern)
                .withAppend(manager.isAppend())
                .withStrategy(manager.getRolloverStrategy())
                .withPolicy(manager.getTriggeringPolicy())
                .setLayout(oldAppender.getLayout())
                .withLocking(manager.isLocking())
                .build();
    newAppender.start();
//...

这会生成一个新的 Appender,其设置与旧的 Appender 完全相同,除了写入位置,这正是我想要的。我在调试器中确认了这一点。

//remove old appender from Config and Loggers
...
    ((PropertiesConfiguration) config).removeAppender(appenderName);
    .getLoggers().values().forEach(l -> l.removeAppender(appenderName));
    //add rebuilt (new) appender to Config and Loggers
    config.addAppender(newAppender);
    .getLoggers().values().forEach(l -> l.addAppender(newAppender, l.getLevel(), l.getFilter()));

    context.updateLoggers();
}

这将从当前 LoggerContext 的配置中删除旧的 Appender 并插入新的 Appender。在调试器中,我可以看到这似乎也按预期工作。

此屏幕截图显示了更改为新 Appender 之前的 Logger(注意变量中的旧日志文件路径): 设置新Appender之前

这是在执行接下来的几行之后(注意新的日志文件路径):
设置新的Appender后

在此之后,我立即通过一些

log.debug(...)
测试Appender,但是当我调试代码时,我看到Appender又回到了旧的文件路径:
更新Appender后立即调用log.debug(...)

我怀疑它以某种方式诉诸于从 log4j2.properties 推断出的某些默认配置,并且不受我所做的更改的影响。

调试级别应该不是问题,因为 log4j2.properties 中的所有级别都设置为 DEBUG。

java logging log4j2 appender
1个回答
0
投票

log4j2.xml

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
  <Appenders>
    <Routing name="RoutingAppender1">
      <Routes pattern="${ctx:jobId}">
        <Route>
          <RollingFile name="JobLog" fileName="logs/job-${ctx:jobId}.log"
                       filePattern="logs/job-${ctx:jobId}-%d{yyyy-MM-dd}-%i.log.gz">
            <PatternLayout>
              <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
            </PatternLayout>
            <Policies>
              <TimeBasedTriggeringPolicy />
              <SizeBasedTriggeringPolicy size="10MB"/>
            </Policies>
          </RollingFile>
        </Route>
      </Routes>
    </Routing>
    <Routing name="RoutingAppender2">
      <Routes pattern="${ctx:jobId}">
        <Route>
          <RollingFile name="JobLog" fileName="logs/${ctx:jobId}/app.log"
                       filePattern="logs/${ctx:jobId}/app-%d{yyyy-MM-dd}-%i.log.gz">
            <PatternLayout>
              <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
            </PatternLayout>
            <Policies>
              <TimeBasedTriggeringPolicy />
              <SizeBasedTriggeringPolicy size="10MB"/>
            </Policies>
          </RollingFile>
        </Route>
      </Routes>
    </Routing>    
  </Appenders>

  <Loggers>
    <Root level="info">
      <AppenderRef ref="RoutingAppender1"/>
      <AppenderRef ref="RoutingAppender2"/>      
    </Root>
  </Loggers>
</Configuration>

DemoApp.java

package com.example;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.ThreadContext;

public class DemoApp {
    private static final Logger logger = LogManager.getLogger(DemoApp.class);
    public static void executeJob(String jobId) {
        //Set jobId as a variable of ThreadContext
        ThreadContext.put("jobId", jobId);
        logger.info("Job " + jobId + " is starting...");
        // job execution logic
        ThreadContext.clearAll();  // Clear context variables to prevent contamination
    }
    public static void main(String[] args) {
        ThreadContext.put("jobId", "ZZZ");
        
        //Test English
        String msg = "Hello World!";
        System.out.println( msg );
        logger.info(msg);
        logger.warn(msg);
        logger.error(msg);

        executeJob("280");

        //Test CJK
        ThreadContext.put("jobId", "ZZZ-ZH");
        String msgCJK = "你好 世界 !";
        System.out.println( msgCJK );
        logger.info(msgCJK);
        logger.warn(msgCJK);
        logger.error(msgCJK);

    } //main

} //class

输出日志:

路由Appender1

logs
├── job-280.log
├── job-ZZZ.log
└── job-ZZZ-ZH.log

路由Appender2

logs
├── 280
│   └── app.log
├── ZZZ
│   └── app.log
└── ZZZ-ZH
    └── app.log
最新问题
© www.soinside.com 2019 - 2025. All rights reserved.