Log4j2在webMethods中按Appender生成独立日志异常排查
问题
在webMethods中使用Log4j2生成日志文件,需求是运行时由用户传入Logger名称、日志级别和消息,为每个Appender生成独立日志文件。当前配置和代码如下,但无论传入哪个Logger名称,所有日志都只写入最后一个Appender对应的EFG.log文件。
Log4j2 XML配置
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="DEBUG"> <Appenders> <RollingFile name="ROLL_ITLFileHandler" fileName="/esblogdata/logs/ITLFileHandler.log" filePattern="/esblogdata/logs/ITLFileHandler%d{yyyy-MM-dd}.log"> <PatternLayout> <Pattern>%m%n</Pattern> </PatternLayout> <Policies> <TimeBasedTriggeringPolicy interval="1" modulate="true"/> </Policies> </RollingFile> </Appenders> <Appenders> <RollingFile name="ROLL_PublishCarrierEvent" fileName="/esblogdata/logs/PublishCarrierEvent.log" filePattern="/esblogdata/logs/PublishCarrierEvent%d{yyyy-MM-dd}.log"> <PatternLayout> <Pattern>%m%n</Pattern> </PatternLayout> <Policies> <TimeBasedTriggeringPolicy interval="1" modulate="true"/> </Policies> </RollingFile> </Appenders> <Appenders> <RollingFile name="ROLL_ABC" fileName="/esblogdata/logs/ABC.log" filePattern="/esblogdata/logs/ABC%d{yyyy-MM-dd}.log"> <PatternLayout> <Pattern>%m%n</Pattern> </PatternLayout> <Policies> <TimeBasedTriggeringPolicy interval="1" modulate="true"/> </Policies> </RollingFile> </Appenders> <Appenders> <RollingFile name="ROLL_EFG" fileName="/esblogdata/logs/EFG.log" filePattern="/esblogdata/logs/EFG%d{yyyy-MM-dd}.log"> <PatternLayout> <Pattern>%m%n</Pattern> </PatternLayout> <Policies> <TimeBasedTriggeringPolicy interval="1" modulate="true"/> </Policies> </RollingFile> </Appenders> <Loggers> <Logger name="ITLFileHandler" level="DEBUG" additivity="true"> <AppenderRef ref="ROLL_ITLFileHandler"/> </Logger> <Logger name="PublishCarrierEvent" level="DEBUG" additivity="true"> <AppenderRef ref="ROLL_PublishCarrierEvent"/> </Logger> <Logger name="ABC" level="DEBUG" additivity="true"> <AppenderRef ref="ROLL_ABC"/> </Logger> <Logger name="EFG" level="DEBUG" additivity="true"> <AppenderRef ref="ROLL_EFG"/> </Logger> <Root level="DEBUG"> <AppenderRef ref="ROLL_ITLFileHandler"/> <AppenderRef ref="ROLL_PublishCarrierEvent"/> <AppenderRef ref="ROLL_ABC"/> <AppenderRef ref="ROLL_EFG"/> </Root> </Loggers> </Configuration>
Java日志写入代码
//Set Level - severity received from user in in run time as INFO, DEBUG etc., Level level = Level.getLevel(severity); ConfigurationFactory factory = XmlConfigurationFactory.getInstance(); //LOG4J_CFG points to the location where log4j2 XML is kept ConfigurationSource configurationSource = new ConfigurationSource(new FileInputStream(new File(LOG4J_CFG))); Configuration configuration = factory.getConfiguration(null, configurationSource); // Get context instance LoggerContext context = new LoggerContext("test"); //Start logging system context.start(configuration); // Get a reference for logger (logger name will be passed in runtime by user which will be similar to the Logger name Ex: ITLFilehandler, ABC, XYZ in above XML Logger logger = context.getLogger(loggerName); logger.log(level, finalMessage); context.close();
解决方案
问题根源
- XML配置错误:Log4j2规范要求所有Appender必须定义在同一个
<Appenders>标签内,多个独立的<Appenders>标签会导致只有最后一个标签内的配置被加载,前面的Appender全部被忽略,最终所有日志都只能写入最后一个Appender对应的文件。 - 代码设计不合理:每次日志请求都创建并关闭LoggerContext,违背Log4j2最佳实践,不仅浪费资源,还可能引发配置加载异常。
修复步骤
1. 修正Log4j2 XML配置
将所有Appender合并到同一个<Appenders>标签下,并调整Logger的additivity属性避免日志重复输出:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="DEBUG"> <Appenders> <RollingFile name="ROLL_ITLFileHandler" fileName="/esblogdata/logs/ITLFileHandler.log" filePattern="/esblogdata/logs/ITLFileHandler%d{yyyy-MM-dd}.log"> <PatternLayout> <Pattern>%m%n</Pattern> </PatternLayout> <Policies> <TimeBasedTriggeringPolicy interval="1" modulate="true"/> </Policies> </RollingFile> <RollingFile name="ROLL_PublishCarrierEvent" fileName="/esblogdata/logs/PublishCarrierEvent.log" filePattern="/esblogdata/logs/PublishCarrierEvent%d{yyyy-MM-dd}.log"> <PatternLayout> <Pattern>%m%n</Pattern> </PatternLayout> <Policies> <TimeBasedTriggeringPolicy interval="1" modulate="true"/> </Policies> </RollingFile> <RollingFile name="ROLL_ABC" fileName="/esblogdata/logs/ABC.log" filePattern="/esblogdata/logs/ABC%d{yyyy-MM-dd}.log"> <PatternLayout> <Pattern>%m%n</Pattern> </PatternLayout> <Policies> <TimeBasedTriggeringPolicy interval="1" modulate="true"/> </Policies> </RollingFile> <RollingFile name="ROLL_EFG" fileName="/esblogdata/logs/EFG.log" filePattern="/esblogdata/logs/EFG%d{yyyy-MM-dd}.log"> <PatternLayout> <Pattern>%m%n</Pattern> </PatternLayout> <Policies> <TimeBasedTriggeringPolicy interval="1" modulate="true"/> </Policies> </RollingFile> </Appenders> <Loggers> <Logger name="ITLFileHandler" level="DEBUG" additivity="false"> <AppenderRef ref="ROLL_ITLFileHandler"/> </Logger> <Logger name="PublishCarrierEvent" level="DEBUG" additivity="false"> <AppenderRef ref="ROLL_PublishCarrierEvent"/> </Logger> <Logger name="ABC" level="DEBUG" additivity="false"> <AppenderRef ref="ROLL_ABC"/> </Logger> <Logger name="EFG" level="DEBUG" additivity="false"> <AppenderRef ref="ROLL_EFG"/> </Logger> <Root level="DEBUG"> <!-- 若不需要Root日志写入所有文件,可移除以下AppenderRef --> <!-- <AppenderRef ref="ROLL_ITLFileHandler"/> <AppenderRef ref="ROLL_PublishCarrierEvent"/> <AppenderRef ref="ROLL_ABC"/> <AppenderRef ref="ROLL_EFG"/> --> </Root> </Loggers> </Configuration>
additivity="false":确保每个Logger的日志仅写入自身关联的Appender,不会被Root Logger重复输出。
2. 优化Java代码
复用全局LoggerContext,避免重复创建和销毁:
// 应用启动时初始化一次配置 static { System.setProperty("log4j.configurationFile", LOG4J_CFG); } // 日志写入方法 public void writeLog(String loggerName, String severity, String finalMessage) { Level level = Level.getLevel(severity); // 处理无效级别,默认使用DEBUG if (level == null) { level = Level.DEBUG; } // 使用Log4j2标准API获取Logger,自动关联全局Context Logger logger = LogManager.getLogger(loggerName); logger.log(level, finalMessage); }
内容的提问来源于stack exchange,提问作者Ragav J
相关产品推荐
相关产品推荐

