Log4j2中JsonTemplateLayout遇非MapMessage时如何配置消息回退?
Log4j2 JsonTemplateLayout 兼容非MapMessage日志的解决方案
问题场景
用Log4j2的JsonTemplateLayout自定义JSON日志模板,业务代码里用MapMessage能正常提取模板所需字段,但Spring等第三方库输出的日志用普通Message,导致自定义模板没法解析并记录这些消息内容(比如Spring启动日志),需要实现当消息不是Map类型时自动回退到正常记录原始消息的逻辑。
核心解决思路
利用Log4j2 JsonTemplateLayout支持的条件判断语法,在自定义模板里判断当前日志消息的类型:
- 如果是
MapMessage,按原有逻辑提取Map中的字段 - 否则直接输出格式化后的原始消息内容
实现步骤
1. 修改自定义JSON模板
在你的事件模板文件(比如custom-json-template.json)中,给message字段添加$if条件判断:
{ "timestamp": { "$resolver": "timestamp", "pattern": { "format": "yyyy-MM-dd'T'HH:mm:ss.SSSXXX", "timeZone": "UTC" } }, "level": { "$resolver": "level", "field": "name" }, "logger": { "$resolver": "logger", "field": "name" }, "message": { "$if": { "condition": { "$resolver": "message", "field": "class", "$tests": { "isInstanceOf": "org.apache.logging.log4j.message.MapMessage" } }, "then": { "data": { "$resolver": "message", "field": "data" } }, "else": { "content": { "$resolver": "message", "field": "formattedMessage" } } } }, "thread": { "$resolver": "thread", "field": "name" } }
2. 模板逻辑说明
- 条件判断:通过
$tests.isInstanceOf检查消息是否属于MapMessage类型 - 分支处理:
then分支:如果是MapMessage,提取其data字段(即业务代码中传入的Map键值对)else分支:如果是普通消息,直接输出格式化后的原始消息内容
3. 配置Log4j2引用模板
在log4j2.xml(或对应配置文件)中,确保JsonTemplateLayout引用这个自定义模板:
<Configuration status="INFO"> <Appenders> <Console name="Console" target="SYSTEM_OUT"> <JsonTemplateLayout eventTemplateUri="classpath:custom-json-template.json" /> </Console> </Appenders> <Loggers> <Root level="info"> <AppenderRef ref="Console" /> </Root> </Loggers> </Configuration>
这样配置后,无论是业务代码的MapMessage日志,还是第三方库的普通日志,都能正常按JSON格式输出:Map类型消息会展示结构化的data字段,普通消息则展示原始内容。
内容的提问来源于stack exchange,提问作者osrs10
相关产品推荐
相关产品推荐

