LOG4J Json-Template-Layout如何仅添加指定HTTP头至headers对象?
解决Log4j Json-Template-Layout生成指定HTTP头的headers对象问题
方案一:使用MapMessage传递指定字段
直接通过MapMessage构造仅包含目标HTTP头的消息体,日志模板直接提取该消息的内容作为headers对象,完全避免MDC无关内容的混入。
代码示例(Java)
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.message.MapMessage; import javax.servlet.http.HttpServletRequest; import java.util.HashMap; import java.util.Map; public class RequestLogger { private static final Logger logger = LogManager.getLogger(RequestLogger.class); public void logRequest(HttpServletRequest request) { // 仅收集需要的HTTP头/请求字段 Map<String, String> targetHeaders = new HashMap<>(); targetHeaders.put("host", request.getHeader("Host")); targetHeaders.put("method", request.getMethod()); targetHeaders.put("user_agent", request.getHeader("User-Agent")); // 可按需添加其他字段 // 用MapMessage输出日志 logger.info(new MapMessage(targetHeaders)); } }
Log4j2配置(XML示例)
<Configuration status="WARN"> <Appenders> <Console name="Console" target="SYSTEM_OUT"> <JsonTemplateLayout> <Template> { "timestamp": "$${date:yyyy-MM-dd'T'HH:mm:ss.SSSXXX}", "level": "$${level}", "logger_name": "$${loggerName}", "headers": "$${map:}" } </Template> </JsonTemplateLayout> </Console> </Appenders> <Loggers> <Root level="info"> <AppenderRef ref="Console"/> </Root> </Loggers> </Configuration>
${map:}会直接提取MapMessage中的所有键值对,作为headers对象的内容,确保只包含你指定的字段。
方案二:用Map Resolver从MDC筛选指定字段
如果已经将HTTP头存入MDC(但不想输出所有MDC内容),可以通过Map Resolver的构建器语法,仅提取需要的MDC键,构造headers对象。
步骤1:将指定头存入MDC
import org.apache.logging.log4j.ThreadContext; import javax.servlet.http.HttpServletRequest; public class RequestMDCInitializer { public void initMDC(HttpServletRequest request) { // 仅存入需要的字段到MDC ThreadContext.put("http_host", request.getHeader("Host")); ThreadContext.put("http_method", request.getMethod()); ThreadContext.put("http_user_agent", request.getHeader("User-Agent")); } }
步骤2:配置Json-Template-Layout筛选字段
<Configuration status="WARN"> <Appenders> <Console name="Console" target="SYSTEM_OUT"> <JsonTemplateLayout> <Template> { "timestamp": "$${date:yyyy-MM-dd'T'HH:mm:ss.SSSXXX}", "level": "$${level}", "logger_name": "$${loggerName}", "headers": "$${map:builder:put('host', mdc('http_host')):put('method', mdc('http_method')):put('user_agent', mdc('http_user_agent')):build()}" } </Template> </JsonTemplateLayout> </Console> </Appenders> <Loggers> <Root level="info"> <AppenderRef ref="Console"/> </Root> </Loggers> </Configuration>
这里通过map:builder逐个添加需要的键值对,每个值从MDC中读取指定的键,最终构建出仅包含目标字段的headers对象,不会混入其他MDC元素。
方案对比
- MapMessage方案:无需依赖MDC,日志内容更独立,适合单次日志输出指定字段的场景;
- Map Resolver+MDC方案:适合需要在多个日志中复用同一批HTTP头字段的场景,只需初始化一次MDC即可。
内容的提问来源于stack exchange,提问作者Jack Bourner
相关产品推荐
相关产品推荐

