对于一个项目,我有一个多次启动的程序,我想将其每次运行记录到不同的文件中。我已经准备好了所需的一切,例如保存特定运行的预期日志记录位置的变量。
现在的问题是我无法正确更新 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又回到了旧的文件路径:我怀疑它以某种方式诉诸于从 log4j2.properties 推断出的某些默认配置,并且不受我所做的更改的影响。
调试级别应该不是问题,因为 log4j2.properties 中的所有级别都设置为 DEBUG。
<?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>
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
输出日志:
logs
├── job-280.log
├── job-ZZZ.log
└── job-ZZZ-ZH.log
logs
├── 280
│ └── app.log
├── ZZZ
│ └── app.log
└── ZZZ-ZH
└── app.log