Http请求:添加traceId

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

目录

一、traceId作用

二、MDC实现方案

三、ThreadContext实现方案

总结


一、traceId作用

当请求执行的过程中,会产生各种log日志,我们希望能通过一个ID,贯穿整个请求的链条,将完整的日志打印出来,便于进行日志分析,traceId就是起这样一种作用,将traceId输出到每一行日志中,即可实现我们需要的功能。

二、MDC实现方案

MDC 全称是 Mapped Diagnostic Context,是 Spring 框架中的一个类,它可以MDC 全称是 Mapped Diagnostic Context,是 Spring 框架中的一个类,它可以粗略的理解成是一个线程安全的存放诊断日志的容器。 MDC 可以将一些上下文信息(如用户 ID、请求 IP 等)添加到日志中,方便后续的日志分析和排查问题

话不多说,上代码

@Slf4j
@WebFilter(filterName = "httpTraceFilter", urlPatterns = "/*")
public class HttpTraceFilter extends OncePerRequestFilter implements Ordered {

    private static final String TRACE_ID = "traceId";
 

    @Override
    public int getOrder() {
        return Ordered.LOWEST_PRECEDENCE - 10;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
                                    FilterChain filterChain) throws ServletException, IOException {
        // 初始化traceId值
        String traceIdValue = StringUtils.isEmpty(MDC.get(TRACE_ID)) ? IdUtil.fastSimpleUUID() : MDC.get(TRACE_ID);
        // 设置traceId值
        MDC.put(TRACE_ID, traceIdValue);

        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        try {
            filterChain.doFilter(request, responseNew);
            // 重置traceId值
            MDC.put(TRACE_ID, traceIdValue);
        } finally {
            stopWatch.stop();
            // 线程结束,移除线程变量
            MDC.remove(TRACE_ID);
        }
    }
}   

三、ThreadContext实现方案

org.apache.logging.log4j.ThreadContext 是 Apache Log4j 2.x 中的一个类,用于在多线程环境中管理和传递上下文信息,类似于 Mapped Diagnostic Context (MDC) 的概念

代码如下(示例):

import org.apache.logging.log4j.ThreadContext;
@Slf4j
@WebFilter(filterName = "httpTraceFilter", urlPatterns = "/*")
public class HttpTraceFilter extends OncePerRequestFilter implements Ordered {

    private static final String TRACE_ID = "traceId";
    
    @Override
    public int getOrder() {
        return Ordered.LOWEST_PRECEDENCE - 10;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
                                    FilterChain filterChain) throws ServletException, IOException {
 
        // 获取初始的traceId值
        String traceIdValue = StringUtils.isEmpty(ThreadContext.get(TRACE_ID)) ? IdUtil.fastSimpleUUID() : ThreadContext.get(TRACE_ID);
        // 设置traceId
        ThreadContext.put(TRACE_ID, traceIdValue);

        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        try {
            filterChain.doFilter(request, responseNew);
            // 如果有后续操作,务必要重置traceId,否则会丢失
            ThreadContext.put(TRACE_ID, traceIdValue);
        } finally {
            stopWatch.stop();
            // 执行完后,清除线程变量
            ThreadContext.remove(TRACE_ID);
        }
    }
}

logback xml文件traceId配置实例: 

<springProperty scope="context" name="log.filePattern" source="hcf.log.file-pattern" defaultValue="%d{yyyy-MM-dd HH:mm:ss.SSS}|%level|%thread|%X{clientIp}|%X{traceId}|%X{rpcId}|%c.%M[%L]|%msg%n"/>
	<springProperty scope="context" name="log.consolePattern" source="hcf.log.console-pattern" defaultValue="%red(%d{yyyy-MM-dd HH:mm:ss.SSS})|%highlight(%level)|%green(%thread)|%X{clientIp}|%X{traceId}|%X{rpcId}|%boldMagenta(%c.%M[%L])|%cyan(%msg%n)"/>

<!--控制台输出-->
	<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
		<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
			<charset>UTF-8</charset>
			<pattern>${log.consolePattern}</pattern>
		</encoder>
	</appender>

<!-- 日志文件 -->
	<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
		<!--
			按照时间与文件大小两个维度进行分割文件,%d{yyyy-MM-dd}代表按天分割,%d{yyyy-MM-dd-HH}代表按小时分割
			maxHistory最大保留文件时间数,按天分割代表几天,小时分割则代表几个小时
			maxFileSize单文件最大容量,超过则增加%i的值
			totalSizeCap总计文件容量
		-->
		<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
			<FileNamePattern>${log.path}/${log.system}/${log.appName}/${log.appName}.%d{yyyy-MM-dd}.%i.log</FileNamePattern>
			<maxHistory>15</maxHistory>
			<maxFileSize>500MB</maxFileSize>
			<totalSizeCap>20GB</totalSizeCap>
		</rollingPolicy>
		<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
			<pattern>${log.filePattern}</pattern>
			<charset>UTF-8</charset>
		</encoder>
	</appender>

 


总结

实际使用中,用MDC的方案,发现生产上有部分日志没有traceId,有部分日志traceId错乱,A线程的traceId在B线程日志中输出了,如果遇到此类情况但又排查不出来原因,可以切换为第二种方案。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值