如何阻止Log4j2 JsonTemplateLayout将堆栈跟踪追加到其他JSON字段
问题描述
我正在使用Log4j2的JsonTemplateLayout,配置了JSON模板将堆栈跟踪信息放到stack字段中。但记录异常时,堆栈跟踪除了出现在指定字段外,还会被追加到service、component这类自定义字段里。
使用的JSON模板如下:
{"level": {"$resolver": "level","field": "name"},"message": {"$resolver": "message","stringified": true},"timestamp": {"$resolver": "timestamp","pattern": {"format": "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'","timeZone": "UTC"}},"logger": {"$resolver": "logger","field": "name"},"service": {"$resolver": "pattern","pattern": "${env:FOO_SERVICE}"},"component": {"$resolver": "pattern","pattern": "${env:FOO_COMPONENT}"},"exception": {"exception_class": {"$resolver": "exception","field": "className"},"exception_message": {"$resolver": "exception","field": "message"},"stacktrace": {"$resolver": "exception","field": "stackTrace","stackTrace": {"stringified": true}}},"line_number": {"$resolver": "source","field": "lineNumber"}}
控制台Appender配置:
<Appenders> <Console name="Console" target="SYSTEM_OUT"> <JsonTemplateLayout eventTemplateUri="classpath:log4j2-layout.json"/> </Console> </Appenders>
异常日志示例中,service和component字段被追加了堆栈信息:
{"level":"INFO","message":"Force trigger exception","timestamp":"2022-11-02T20:37:35.270Z","logger":"foo.example.acme.system.connector.dataset.EchoAPI","service":"example1 java.lang.Exception: This is a forced exception\n\tat foo.example.acme.system.connector.dataset.EchoAPI.handle(EchoAPI.java:18) ~[classes/:?]\n\tat foo.example.acme.system.connector.ConnectorApi.handle(ConnectorApi.java:33) ~[classes/:?]\n\tat somesystem.com.connector.undertow.UndertowHandler.handleBody(UndertowHandler.java:131) ~[classes/:?]\n\tat io.undertow.io.AsyncReceiverImpl.receiveFullBytes(AsyncReceiverImpl.java:366) ~[undertow-core-2.2.19.Final.jar:2.2.19.Final]\n\tat somesystem.com.connector.undertow.UndertowHandler.handleRequest(UndertowHandler.java:61) ~[classes/:?]\n\tat io.undertow.server.Connectors.executeRootHandler(Connectors.java:387) ~[undertow-core-2.2.19.Final.jar:2.2.19.Final]\n\tat io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:852) ~[undertow-core-2.2.19.Final.jar:2.2.19.Final]\n\tat org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35) ~[jboss-threads-3.1.0.Final.jar:3.1.0.Final]\n\tat org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:2019) ~[jboss-threads-3.1.0.Final.jar:3.1.0.Final]\n\tat org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1558) ~[jboss-threads-3.1.0.Final.jar:3.1.0.Final]\n\tat org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1423) ~[jboss-threads-3.1.0.Final.jar:3.1.0.Final]\n\tat org.xnio.XnioWorker$WorkerThreadFactory$1$1.run(XnioWorker.java:1282) ~[xnio-api-3.8.7.Final.jar:3.8.7.Final]\n\tat java.lang.Thread.run(Thread.java:832) ~[?:?]\n","component":"example2 java.lang.Exception: This is a forced exception\n\tat foo.example.acme.system.connector.dataset.EchoAPI.handle(EchoAPI.java:18) ~[classes/:?]\n\tat foo.example.acme.system.connector.ConnectorApi.handle(ConnectorApi.java:33) ~[classes/:?]\n\tat somesystem.com.connector.undertow.UndertowHandler.handleBody(UndertowHandler.java:131) ~[classes/:?]\n\tat io.undertow.io.AsyncReceiverImpl.receiveFullBytes(AsyncReceiverImpl.java:366) ~[undertow-core-2.2.19.Final.jar:2.2.19.Final]\n\tat somesystem.com.connector.undertow.UndertowHandler.handleRequest(UndertowHandler.java:61) ~[classes/:?]\n\tat io.undertow.server.Connectors.executeRootHandler(Connectors.java:387) ~[undertow-core-2.2.19.Final.jar:2.2.19.Final]\n\tat io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:852) ~[undertow-core-2.2.19.Final.jar:2.2.19.Final]\n\tat org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35) ~[jboss-threads-3.1.0.Final.jar:3.1.0.Final]\n\tat org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:2019) ~[jboss-threads-3.1.0.Final.jar:3.1.0.Final]\n\tat org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1558) ~[jboss-threads-3.1.0.Final.jar:3.1.0.Final]\n\tat org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1423) ~[jboss-threads-3.1.0.Final.jar:3.1.0.Final]\n\tat org.xnio.XnioWorker$WorkerThreadFactory$1$1.run(XnioWorker.java:1282) ~[xnio-api-3.8.7.Final.jar:3.8.7.Final]\n\tat java.lang.Thread.run(Thread.java:832) ~[?:?]\n","exception":{"exception_class":"java.lang.Exception","exception_message":"This is a forced exception","stacktrace":"java.lang.Exception: This is a forced exception\n\tat foo.example.acme.system.connector.dataset.EchoAPI.handle(EchoAPI.java:18)\n\tat foo.example.acme.system.connector.ConnectorApi.handle(ConnectorApi.java:33)\n\tat somesystem.com.connector.undertow.UndertowHandler.handleBody(UndertowHandler.java:131)\n\tat io.undertow.io.AsyncReceiverImpl.receiveFullBytes(AsyncReceiverImpl.java:366)\n\tat somesystem.com.connector.undertow.UndertowHandler.handleRequest(UndertowHandler.java:61)\n\tat io.undertow.server.Connectors.executeRootHandler(Connectors.java:387)\n\tat io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:852)\n\tat org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)\n\tat org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:2019)\n\tat org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1558)\n\tat org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1423)\n\tat org.xnio.XnioWorker$WorkerThreadFactory$1$1.run(XnioWorker.java:1282)\n\tat java.base/java.lang.Thread.run(Thread.java:832)\n"}}
试过将stringified设为false、把自定义字段改成嵌套形式都无效,当前使用Log4j2 2.19.0版本,也试过更早的版本。
解决方案
这个问题的根源是PatternResolver默认会自动追加异常堆栈信息:当使用pattern解析器时,如果当前日志事件携带异常,它会自动把堆栈跟踪追加到解析结果之后。
要解决这个问题,只需在service和component的pattern解析器配置中添加"exception": "none"参数,明确禁用自动追加异常的行为。
修改后的JSON模板如下:
{ "level": {"$resolver": "level","field": "name"}, "message": {"$resolver": "message","stringified": true}, "timestamp": {"$resolver": "timestamp","pattern": {"format": "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'","timeZone": "UTC"}}, "logger": {"$resolver": "logger","field": "name"}, "service": {"$resolver": "pattern","pattern": "${env:FOO_SERVICE}", "exception": "none"}, "component": {"$resolver": "pattern","pattern": "${env:FOO_COMPONENT}", "exception": "none"}, "exception": { "exception_class": {"$resolver": "exception","field": "className"}, "exception_message": {"$resolver": "exception","field": "message"}, "stacktrace": {"$resolver": "exception","field": "stackTrace","stackTrace": {"stringified": true}} }, "line_number": {"$resolver": "source","field": "lineNumber"} }
参数说明:
"exception": "none":告诉PatternResolver只返回pattern解析后的原始值,不再自动追加异常堆栈信息。
修改后,service和component字段就只会显示环境变量的原始值,不会再被追加异常堆栈内容。
内容的提问来源于stack exchange,提问作者Shogan
相关产品推荐
相关产品推荐

