Spring Boot应用如何将Tomcat访问日志以JSON格式打印到控制台
问题根因
配置失效、输出乱码的核心原因有两个:
- 你把Log4j2的日志模式占位符直接套用到了Tomcat原生访问日志的pattern配置上,两者的占位符规则完全不兼容。Tomcat AccessLogValve只识别自身定义的访问日志占位符(比如
%h代表客户端IP、%t代表请求时间、%r代表请求行、%s代表响应状态码),根本不认识%d、%p、%logger、%replace这些Log4j2专属的模式语法,最终出现占位符解析失败、乱码、字段值错位。 - 你写的
server.tomcat.accesslog.console.pattern不是Spring Boot内嵌Tomcat的合法配置项,这个参数不会被识别生效。
推荐方案:桥接Tomcat访问日志到Log4j2统一输出
这个方案可以直接复用你现有的log4j2.xml JSON格式配置,不需要单独适配Tomcat的日志语法,输出格式完全统一,不会出现解析乱码、JSON非法问题。
- 删掉
application.properties里之前写的所有server.tomcat.accesslog.*配置,关闭Tomcat原生访问日志输出。 - 引入Log4j2 Tomcat日志桥接依赖,Maven项目在pom.xml添加如下依赖,版本号和项目现有Log4j2版本保持一致即可:
<dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-appserver</artifactId> </dependency>
- 在
log4j2.xml中配置访问日志输出规则,和现有业务日志的JSON模板保持对齐,示例配置:
<!-- 控制台输出Appender,配置你需要的JSON结构 --> <Appenders> <Console name="Console" target="SYSTEM_OUT"> <JsonLayout properties="true" compact="false" eventEol="true"> <KeyValuePair key="time" value="$${date:yyyy-MM-dd'T'HH:mm:ss.SSSZ}"/> <KeyValuePair key="level" value="${level}"/> <KeyValuePair key="correlation-id" value="$${ctx:X-Correlation-Id}"/> <KeyValuePair key="source" value="ACCESS_LOGS"/> <KeyValuePair key="message" value="${message}"/> </JsonLayout> </Console> </Appenders> <!-- 专门捕获Tomcat访问日志的Logger,绑定控制台Appender --> <Loggers> <Root level="INFO"> <AppenderRef ref="Console"/> </Root> <Logger name="org.apache.catalina.core.ContainerBase.[Tomcat].[localhost].[/]" level="INFO" additivity="false"> <AppenderRef ref="Console"/> </Logger> </Loggers>
- 在Spring Boot启动类中注册Log4j2版的Tomcat访问日志阀:
@Bean public TomcatServletWebServerFactory tomcatServletWebServerFactory() { TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory(); Log4j2AccessLogValve accessLogValve = new Log4j2AccessLogValve(); // 访问日志消息内容使用Tomcat原生占位符定义即可 accessLogValve.setPattern("%h %l %u %t \"%r\" %s %b %Dms %{User-Agent}i %{X-Correlation-Id}i"); factory.addContextValves(accessLogValve); return factory; }
配置完成后所有Tomcat访问日志会直接走Log4j2输出管线,和业务日志格式完全统一,自动处理特殊字符转义,不会出现JSON结构破坏问题。
备选方案:使用Tomcat原生访问日志输出JSON
如果不想引入额外依赖,直接用Tomcat自带的AccessLogValve输出控制台JSON,必须严格使用Tomcat自身的占位符语法,合法配置如下:
server.tomcat.accesslog.enabled=true server.tomcat.accesslog.directory=/dev server.tomcat.accesslog.prefix=stdout server.tomcat.accesslog.suffix= server.tomcat.accesslog.file-date-format= server.tomcat.basedir=. # 核心:使用Tomcat合法占位符,配置项为pattern,不存在console.pattern参数 server.tomcat.accesslog.pattern="{\"time\":\"%t\",\"clientIp\":\"%h\",\"method\":\"%m\",\"uri\":\"%U\",\"query\":\"%q\",\"status\":%s,\"costMs\":%D,\"correlationId\":\"%{X-Correlation-Id}i\",\"source\":\"ACCESS_LOGS\"}%n" server.tomcat.accesslog.encoding=UTF-8
这个方案的缺陷是无法复用Log4j2的消息转义、MDC上下文读取、异常格式化能力,如果请求参数、请求头里包含双引号、换行符等特殊字符,很容易破坏JSON结构,只适合测试环境快速验证使用。
内容的提问来源于stack exchange,提问作者acsh
相关产品推荐
相关产品推荐

