WebSphere中FINE级日志显示NULL_MESSAGE_KEY_PASSED问题求助
在部署于WebSphere Application Server(WAS)的Java EJB应用(EAR包形式)中,使用java.util.logging.Logger记录日志,代码示例如下:
Logger logger = Logger.getLogger("com.company.app"); logger.fine(()->"message");
当在WAS控制台的troubleshooting -> log and trace -> [server] -> Change log detail levels中设置日志级别为*=info时,日志输出正常;但设置为*=all时,所有FINE、FINER、FINEST级别的日志(如logger.fine("example"))都会被记录为PoolManager W NULL_MESSAGE_KEY_PASSED,原日志消息丢失。
这是WebSphere自带的java.util.logging实现与标准JDK实现的差异导致的:
- 当设置全局日志级别为
*=all时,WAS的日志框架会强制触发日志消息的资源束(ResourceBundle)解析逻辑,它默认认为所有日志消息都是资源键,而非直接的字符串内容。 - 若直接传入字符串或Lambda表达式作为日志消息,WAS会尝试查找对应的资源键,但找不到匹配的资源条目,就会输出
NULL_MESSAGE_KEY_PASSED警告,同时丢弃原日志消息。 - 尤其是Lambda形式的日志(
logger.fine(()->"message")),WAS的日志处理模块未正确适配JDK 8+的Supplier类型参数,进一步加剧了解析失败的问题。
方法1:使用资源束绑定日志消息
遵循WAS的日志规范,为日志器配置对应的资源束,用资源键替代直接的字符串:
// 初始化Logger时指定资源束的基名 Logger logger = Logger.getLogger("com.company.app", "com.company.app.messages"); // 使用资源键记录日志 logger.fine("log.example.message");
然后在应用类路径下创建资源文件com/company/app/messages.properties,添加对应的键值对:
log.example.message=message
方法2:针对特定日志器单独设置级别
避免使用*=all的全局配置,改为针对应用日志器单独设置全级别输出,这样WAS不会对该日志器的消息强制进行资源束解析:
在WAS控制台的日志详细级别设置中,输入:
*=info: com.company.app=all
这样既保留全局info级别,又让应用日志器输出所有级别的日志,且不会触发资源束解析错误。
方法3:替换为第三方日志框架
绕过WAS自带的java.util.logging实现,改用SLF4J+Logback或Log4j2等第三方日志框架:
- 在EAR包中添加对应日志框架的依赖(注意排除WAS自带的冲突依赖)。
- 将代码中的
java.util.logging.Logger替换为SLF4J的org.slf4j.Logger。 - 配置日志框架的输出规则,完全脱离WAS的日志控制,避免兼容性问题。
内容的提问来源于stack exchange,提问作者simonalexander2005

