傳統 log4j2.xml 靜態配置無法滿足「每個任務/用戶/業務單獨日志文件」需求(如 job.001.log、job.002.log)。需運行時動態創建 Logger、Appender、Layout。
LogManager.getContext(false))public class JobLogFactory {
private JobLogFactory() {}
public static void start(int jobId) {
LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
Configuration config = ctx.getConfiguration();
// 1. Layout
Layout layout = PatternLayout.createLayout(
PatternLayout.DEFAULT_CONVERSION_PATTERN, config, null, null, true, false, null, null);
// 2. FileAppender
String fileName = String.format("logs/test/syncshows-job-%s.log", jobId);
Appender appender = FileAppender.createAppender(
fileName, "true", "false", "" + jobId, null, "true", "true", null, layout, null, null, null, config);
appender.start();
config.addAppender(appender);
// 3. LoggerConfig
AppenderRef ref = AppenderRef.createAppenderRef("" + jobId, null, null);
LoggerConfig loggerConfig = LoggerConfig.createLogger(
"false", Level.ALL, "" + jobId, "true", new AppenderRef[]{ref}, null, config, null);
loggerConfig.addAppender(appender, null, null);
config.addLogger("" + jobId, loggerConfig);
// 4. 更新生效
ctx.updateLoggers();
}
public static void stop(int jobId) {
LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
Configuration config = ctx.getConfiguration();
config.getAppender("" + jobId).stop();
config.getLoggerConfig("" + jobId).removeAppender("" + jobId);
config.removeLogger("" + jobId);
ctx.updateLoggers();
}
public static Logger createLogger(int jobId) {
start(jobId);
return LoggerFactory.getLogger("" + jobId); // SLF4J 橋接
}
}
for (int i = 0; i < 50000; i++) {
Logger logger = JobLogFactory.createLogger(i);
logger.info("Testing {}", i);
JobLogFactory.stop(i); // 必須釋放,否則文件句柄耗盡
}
stop() 釋放資源,否則大量 Logger 導致 Too many open filesLogManager.getContext(false) 獲取非單例上下文,隔離不同任務配置RollingFileAppender + 基於大小/時間滾動策略