如何阻止componentRecorder线程日志写入Log4j2的application.log
问题:屏蔽来自特定线程名的Log4j2日志
我在项目中配置了Log4j2,配置内容如下:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="ERROR"> <Properties> <Property name="log-path">${sys:root}/logs</Property> </Properties> <Appenders> <RollingRandomAccessFile name="APPLICATION" filePattern="${log-path}/application.log.%d{yyyy-MM-dd-HH}" > <PatternLayout> <pattern>%d{dd MMM yyyy HH:mm:ss,SSS} %highlight{[%p]} %X{RequestId} (%t) %c: %m%n</pattern> </PatternLayout> </RollingRandomAccessFile> <RollingRandomAccessFile name="REQUESTLOG" filePattern="${log-path}/access.log.%d{yyyy-MM-dd-HH}" > <PatternLayout> <pattern>%m%n</pattern> </PatternLayout> </RollingRandomAccessFile> </Appenders> <Loggers> <Root level="INFO"> <AppenderRef ref="APPLICATION"/> </Root> <Logger name="AccessLogger" level="INFO" additivity="false"> <AppenderRef ref="REQUESTLOG"/> </Logger> <!-- Suppressing excessive logs from dependency packages --> <Logger name="com.dependency1" level="OFF"/> <Logger name="com.component" level="OFF"/> </Loggers> </Configuration>
项目MyProject调用dependency-1,后者再调用dependency-2。dependency-2中有如下代码:
for (int i = 0; i < records; i++) { Thread t = new Thread(r); t.setDaemon(true); t.setName("componentRecorder-" + t.getName()); t.start(); }
目前application.log中出现了该线程输出的日志:
(componentRecorder-Thread-21) componentLogger: A21TJRUUN4KGV 01016862e1798c145f8a127b53634d3ea788392b8123c4b7f5fd04369e3ebc8c7c75 01015c1148bd32f255852a618717bd606e93b5bd4a172fde2b1995de7babe6b2c6fe 010140600f6b1f1dd9327f1bf19b23c4c2e39efa4077338ca32deca1fbd41c6d4a66
从日志中的(componentRecorder-Thread-21) componentLogger:可以判断这些日志来自上述线程。由于这类日志没有明确关联的类或包名,我不清楚如何屏蔽,需要阻止所有来自componentRecorder开头的线程的日志写入application.log,且dependency-2使用SLF4J输出日志。
解决方案
方法1:使用Log4j2正则过滤器(推荐)
直接在APPLICATION Appender中添加RegexFilter,针对线程名前缀进行过滤,拒绝符合条件的日志写入:
<RollingRandomAccessFile name="APPLICATION" filePattern="${log-path}/application.log.%d{yyyy-MM-dd-HH}" > <PatternLayout> <pattern>%d{dd MMM yyyy HH:mm:ss,SSS} %highlight{[%p]} %X{RequestId} (%t) %c: %m%n</pattern> </PatternLayout> <Filters> <!-- 拒绝线程名以componentRecorder开头的日志 --> <RegexFilter regex="componentRecorder-.*" onMatch="DENY" onMismatch="NEUTRAL"/> </Filters> </RollingRandomAccessFile>
该过滤器会检查日志的线程名字段,匹配componentRecorder-前缀的日志会被直接拒绝,不会写入APPLICATION日志文件。
方法2:通过Logger名称屏蔽
从日志中的componentLogger可以推测,dependency-2使用的Logger实例名称为componentLogger,直接添加对应的Logger配置即可屏蔽:
<Loggers> <!-- 原有配置 --> <Root level="INFO"> <AppenderRef ref="APPLICATION"/> </Root> <Logger name="AccessLogger" level="INFO" additivity="false"> <AppenderRef ref="REQUESTLOG"/> </Logger> <!-- 新增:屏蔽componentLogger的所有日志 --> <Logger name="componentLogger" level="OFF" additivity="false"/> <Logger name="com.dependency1" level="OFF"/> <Logger name="com.component" level="OFF"/> </Loggers>
如果这个Logger名称准确,设置级别为OFF就能完全屏蔽它的所有输出。
方法3:线程上下文标记过滤(需修改业务代码)
如果前两种方法不生效,可以通过给线程设置上下文标记,再在过滤器中识别标记来过滤:
- 在调用dependency-2的业务代码中添加线程上下文标记:
// 给当前线程设置标记,子线程会继承该上下文 ThreadContext.put("componentRecorderThread", "true"); try { // 调用dependency-2的代码逻辑 } finally { // 清理标记,避免污染其他线程 ThreadContext.remove("componentRecorderThread"); }
- 修改Log4j2的APPLICATION Appender配置:
<RollingRandomAccessFile name="APPLICATION" filePattern="${log-path}/application.log.%d{yyyy-MM-dd-HH}" > <PatternLayout> <pattern>%d{dd MMM yyyy HH:mm:ss,SSS} %highlight{[%p]} %X{RequestId} (%t) %c: %m%n</pattern> </PatternLayout> <Filters> <ThreadContextMapFilter> <KeyValuePair key="componentRecorderThread" value="true"/> </ThreadContextMapFilter> <ThresholdFilter level="INFO" onMatch="ACCEPT" onMismatch="NEUTRAL"/> </Filters> </RollingRandomAccessFile>
这种方法需要改动业务代码,适合前两种方案无法生效的场景。
内容的提问来源于stack exchange,提问作者Jeya Kumar
相关产品推荐
相关产品推荐

