log4j2 常见配置并支持logId

1、常见配置及解释

<?xml version="1.0" encoding="UTF-8"?>
<!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
<!--Configuration后面的status,这个用于设置log4j2自身内部的信息输出,可以不设置,当设置成trace时,你会看到log4j2内部各种详细输出-->
<!--monitorInterval:Log4j能够自动检测修改配置 文件和重新配置本身,设置间隔秒数-->
<configuration status="INFO" monitorInterval="30">
    <!--先定义所有的appender-->
    <appenders>
        <!--这个输出控制台的配置-->
        <console name="Console" target="SYSTEM_OUT">
            <!--输出日志的格式-->
            <PatternLayout pattern="[ %p ] [%-d{yyyy-MM-dd HH:mm:ss}] [ LOGID:%X{logid} ] [%l] %m%n"/>
        </console>

        <!--文件会打印出所有信息,这个log每次运行程序会自动清空,由append属性决定,这个也挺有用的,适合临时测试用-->
        <File name="Test" fileName="log/test.log" append="false">
            <PatternLayout pattern="[ %p ] %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] [%l] %m%n"/>
        </File>

        <RollingFile name="RollingFileInfo" fileName="log/log.log" filePattern="log/log.log.%d{yyyy-MM-dd}">
            <!-- 只接受level=INFO以上的日志 -->
            <ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
            <PatternLayout pattern="[ %p ] [%-d{yyyy-MM-dd HH:mm:ss}] [ LOGID:%X{logid} ] [%l] %m%n"/>
            <Policies>
                <TimeBasedTriggeringPolicy modulate="true" interval="1"/>
                <SizeBasedTriggeringPolicy/>
            </Policies>
        </RollingFile>

        <RollingFile name="RollingFileError" fileName="log/error.log" filePattern="log/error.log.%d{yyyy-MM-dd}">
            <!-- 只接受level=WARN以上的日志 -->
            <Filters>
            <ThresholdFilter level="warn" onMatch="ACCEPT" onMismatch="DENY" />
            </Filters>
            <PatternLayout pattern="[ %p ] %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] [%l] %m%n"/>
            <Policies>
                <TimeBasedTriggeringPolicy modulate="true" interval="1"/>
                <SizeBasedTriggeringPolicy/>
            </Policies>
        </RollingFile>

    </appenders>

    <!--然后定义logger,只有定义了logger并引入的appender,appender才会生效-->
    <loggers>
        <!--过滤掉spring和mybatis的一些无用的DEBUG信息-->
        <logger name="org.springframework" level="INFO"></logger>
        <logger name="org.mybatis" level="INFO"></logger>
        <root level="all">
            <appender-ref ref="Console"/>
            <appender-ref ref="Test"/>
            <appender-ref ref="RollingFileInfo"/>
            <appender-ref ref="RollingFileError"/>
        </root>
    </loggers>
</configuration>

2、Java端配置

运行时指定上述log4j2.xml的配置:

-Dlog4j.configurationFile=./conf/log4j2.xml

3、输出logId或者与log交互

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.ThreadContext;

/**
 * Created by think on 2017/1/22 0022.
 */
public class LogTest {
    private static final Logger logger = LogManager.getLogger(LogTest.class);

    static class test extends Thread {
        @Override
        public void run() {
            long time = System.currentTimeMillis();
            ThreadContext.put("logid", String.valueOf( time));
            logger.info("test thread.");
            ThreadContext.clearAll();
        }
    }

    public static void main(String[] args) {
        long time = System.currentTimeMillis() ;
        ThreadContext.put("logid", String.valueOf(time));
        try {
            logger.trace("trace...");
            logger.debug("debug...");
            logger.info("info...");
            logger.warn("warn...");
            logger.error("error...");
            logger.fatal("fatal...");

            test test1 = new test();
            test test2 = new test();
            test1.start();
            test2.start();

        } catch (Exception e) {
            e.printStackTrace();
        }

        ThreadContext.clearAll();
    }
}

输出:

[ TRACE ] [2017-02-04 17:10:27] [ LOGID:199427158 ] [logtest.LogTest.main(LogTest.java:37)] trace...
[ DEBUG ] [2017-02-04 17:10:27] [ LOGID:199427158 ] [logtest.LogTest.main(LogTest.java:38)] debug...
[ INFO ] [2017-02-04 17:10:27] [ LOGID:199427158 ] [logtest.LogTest.main(LogTest.java:39)] info...
[ WARN ] [2017-02-04 17:10:27] [ LOGID:199427158 ] [logtest.LogTest.main(LogTest.java:40)] warn...
[ ERROR ] [2017-02-04 17:10:27] [ LOGID:199427158 ] [logtest.LogTest.main(LogTest.java:41)] error...
[ FATAL ] [2017-02-04 17:10:27] [ LOGID:199427158 ] [logtest.LogTest.main(LogTest.java:42)] fatal...
[ INFO ] [2017-02-04 17:11:38] [ LOGID:199498552 ] [logtest.LogTest$test.run(LogTest.java:20)] test thread.
[ INFO ] [2017-02-04 17:11:38] [ LOGID:199498551 ] [logtest.LogTest$test.run(LogTest.java:20)] test thread.

本文代码可参考:https://github.com/hawkingfoo/log-test

<think>好的,用户之前询问了关于ThreadContext中logId无法移除的问题,现在他们想了解如何在log4j2.xml中配置全链路的logID。我需要根据之前的分析,提供配置方法,确保logID在日志中全程可见,尤其是在异步和多线程环境下。 首先,用户可能是遇到了分布式系统中日志追踪困难的问题,特别是在微服务架构下,一个请求可能经过多个服务,每个服务又有多个线程处理。他们需要一种方法来确保每个请求的日志都有唯一的logID,方便追踪和排查问题。 接下来,我需要回顾之前提到的ThreadContext的使用,以及可能遇到的问题,比如线程复用和未正确清除上下文。现在用户需要的是配置log4j2.xml,使得logID能够自动记录到每条日志中,且在整个调用链中保持一致。 首先,应该考虑如何定义logID。通常,可以在请求入口处生成唯一的logID,比如使用过滤器或拦截器,logID放入ThreadContext中。然后在日志输出格式中包含这个logID。但用户现在特别询问的是log4j2.xml的配置,所以重点应放在如何配置PatternLayout来包含logID,以及如何处理异步日志的问题。 在log4j2中,可以通过%X{logId}来引用ThreadContext中的logID。因此,在PatternLayout中添这个变量是关键。但还需要考虑异步日志的情况,因为默认情况下,异步日志可能不会自动传递ThreadContext,导致logID丢失。需要配置AsyncLogger时指定ContextDataInjector,比如使用ReusableLogEventFactory,确保上下文数据被正确传递。 另外,用户可能需要跨线程传递logID,比如在使用线程池时,子线程需要继承父线程的logID。这时候可能需要配置isThreadContextMapInheritable参数,或者在代码中手动传递设置logID。 还需要考虑Web应用的场景,比如使用Servlet过滤器在请求开始时生成logID在结束时清除。这部分虽然在之前的回答中提到了,但需要结合log4j2.xml的配置,确保过滤器正确设置logID且在日志输出中能够捕获到。 可能的配置步骤包括: 1. 在log4j2.xml的PatternLayout中添%X{logId}。 2. 配置异步日志的ContextDataInjector,确保logID在异步环境下不丢失。 3. 使用过滤器或拦截器生成和清除logID。 4. 处理跨线程时的logID传递问题,可能需要使用InheritableThreadLocal或者手动传递。 同时,需要提醒用户注意线程池中的线程复用问题,确保每次任务执行前都清除旧的logID设置新的。此外,在微服务之间传递logID时,可能需要通过HTTP头或其他方式将logID传递到下游服务,在每个服务的日志配置中同样包含logID。 最后,验证配置是否正确,可以通过生成logID检查日志输出是否包含该ID,以及在不同线程和服务中是否保持一致。还要提供示例配置和代码片段,方便用户参考实现。</think>以下是关于在log4j2.xml中配置全链路logID的详细指南: # Log4j2全链路logID配置方案 ## 一、基础配置原理 $$ \text{日志链路追踪} = \text{ThreadContext存储} + \text{日志模板引用} + \text{上下文传递} $$ ## 二、核心配置步骤 ### 1. 日志模板配置 ```xml <Configuration> <Appenders> <Console name="Console" target="SYSTEM_OUT"> <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} [%t] %-5level %X{logId} %logger{36} - %msg%n"/> </Console> </Appenders> </Configuration> ``` *关键参数说明*: `%X{logId}` 会自动读取ThreadContext中名为"logId"的值 ### 2. 异步日志增强配置 ```xml <AsyncLogger name="com.yourpackage" level="info" includeLocation="true"> <AppenderRef ref="Console"/> <ContextDataInjector> org.apache.logging.log4j.core.impl.ReusableLogEventFactory </ContextDataInjector> </AsyncLogger> ``` ## 三、全链路传递实现 ### 1. HTTP请求入口配置(Servlet过滤器) ```java @WebFilter("/*") public class LogIdFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { try { String logId = UUID.randomUUID().toString(); ThreadContext.put("logId", logId); chain.doFilter(request, response); } finally { ThreadContext.clearAll(); } } } ``` ### 2. RPC调用上下文传递 ```java // 客户端发送前 rpcRequest.addHeader("X-Log-ID", ThreadContext.get("logId")); // 服务端接收时 String logId = rpcRequest.getHeader("X-Log-ID"); ThreadContext.put("logId", logId); ``` ## 四、多线程场景处理 ### 1. 线程池包装器 ```java public class LogAwareExecutor extends ThreadPoolExecutor { public void execute(Runnable task) { Map<String, String> context = ThreadContext.getImmutableContext(); super.execute(() -> { ThreadContext.clearAll(); ThreadContext.putAll(context); try { task.run(); } finally { ThreadContext.clearAll(); } }); } } ``` ### 2. CompletableFuture增强 ```java public static <T> CompletableFuture<T> withLogContext(Supplier<T> supplier) { Map<String, String> context = ThreadContext.getImmutableContext(); return CompletableFuture.supplyAsync(() -> { ThreadContext.putAll(context); try { return supplier.get(); } finally { ThreadContext.clearAll(); } }); } ``` ## 五、高级配置选项 ### 1. 强制继承模式 ```xml <Configuration> <Properties> <Property name="log4j2.isThreadContextMapInheritable">true</Property> </Properties> </Configuration> ``` ### 2. 日志脱敏配置 ```xml <PatternLayout pattern="%d{yyyy-MM-dd} %X{logId:--masked--} %msg%n"/> ``` ## 六、验证与调试 ### 1. 日志采样验证 ```java // 在关键节点添验证日志 logger.info("logId验证标记: {}", ThreadContext.get("logId")); ``` ### 2. 诊断配置 ```bash # 启动时添调试参数 -Dlog4j2.debug=true -Dlog4j2.disableThreadContext=true ``` ## 七、性能优化建议 1. **对象复用配置**: ```xml <Configuration reuseObjects="true"> <LogEventFactory class="org.apache.logging.log4j.core.impl.ReusableLogEventFactory"/> </Configuration> ``` 2. **上下文缓存策略**: ```java // 在应用启动时设置 System.setProperty( "log4j2.threadContextMap", "org.apache.logging.log4j.spi.CopyOnWriteThreadContextMap" ); ``` > **注意事项**: > 1. 当使用`%X{logId}`时如果值为空,日志会显示空白字符,建议添默认值:`%X{logId:-N/A}` > 2. 异步日志与同步日志的上下文传递机制不同,需要特别注意`ReusableLogEventFactory`的配置 > 3. 跨JVM调用时需通过Header传递logId,推荐使用`X-Request-ID`作为标准字段
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值