Log4j2 JacksonLayout序列化JSON未包含contextData的解决方法
问题原因
你调用JsonLayout.createDefaultLayout()生成的默认布局配置,默认关闭了ThreadContext(即contextMap/contextData)内容的序列化输出,仅会序列化日志的基础字段(时间、级别、线程、消息等),因此存在ThreadContext里的user属性会在序列化阶段被丢弃,接收端反序列化后自然拿不到对应值。
解决方法
不要使用默认的createDefaultLayout()方法,手动构建JsonLayout实例,显式开启contextMap序列化开关即可。
代码配置示例
替换原有SocketAppender构建逻辑中设置Layout的代码段:
// 替换原有的 .setLayout(JsonLayout.createDefaultLayout()) JsonLayout logLayout = JsonLayout.newBuilder() // 传入当前Logger关联的日志配置,必填 .setConfiguration(((LoggerContext) LogManager.getContext(false)).getConfiguration()) // 核心配置:开启ThreadContext/contextMap内容序列化 .setIncludeContextMap(true) // 可选配置:将contextMap序列化为键值对对象(而非键值对列表),适配直接反序列化为MutableLogEvent的场景 .setPropertiesAsList(false) // 其余按需配置,比如是否包含异常栈、日志来源类信息等 .setIncludeStacktrace(true) .build(); SocketAppender appender = SocketAppender.newBuilder() .setName(appenderName) .setHost(inetAddress.getHostName()) .setPort(port) .setProtocol(Protocol.TCP) .setLayout(logLayout) .build(); appender.start(); logger.addAppender(appender);
配置验证
配置生效后,序列化输出的JSON中会新增contextMap字段,结构类似:
{ "instant" : { "epochSecond" : 1655893941, "nanoOfSecond" : 869382600 }, "thread" : "AWT-EventQueue-0", "level" : "INFO", "loggerName" : "(sensitive)", "message" : "(sensitive)", "contextMap": { "user": "实际登录用户名" }, "endOfBatch" : false, "loggerFqcn" : "org.apache.log4j.Category", "threadId" : 25, "threadPriority" : 6 }
接收端按原有逻辑反序列化后,MutableLogEvent的contextData会自动映射contextMap中的内容,使用%X{user}格式化日志时即可正常取到用户名。
补充说明
如果使用配置文件(log4j2.xml/log4j2.properties)配置JsonLayout,只需给JsonLayout节点添加includeContextMap="true"属性即可:
<JsonLayout includeContextMap="true" propertiesAsList="false"/>
内容的提问来源于stack exchange,提问作者colouredmirrorball
相关产品推荐
相关产品推荐

