`

输出日志中加入traceId 进行链路追踪

 
阅读更多

环境 springboot 项目

 

定义一个filter

 

 

import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.stereotype.Component;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.IOException;
import java.util.UUID;

@Component
@Slf4j
public class LogTraceFilter implements Filter {
    private final String TRACE_ID = "TRACE_ID";
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        try{
            String traceId = UUID.randomUUID().toString().replace("-", "");
            MDC.put(TRACE_ID, traceId);
            filterChain.doFilter(servletRequest, servletResponse);
        }catch (Exception e){
            log.error("添加traceId出错,错误信息:",e);
        }finally {
            MDC.remove(TRACE_ID);
        }
    }
    @Override
    public void destroy() {

    }
}

 

 

 

log4j2 日志输出中加入traceId

 

<?xml version="1.0" encoding="UTF-8"?>
<!--Configuration后面的status,这个用于设置log4j2自身内部的信息输出,可以不设置,当设置成trace时,你会看到log4j2内部各种详细输出-->
<!--monitorInterval:Log4j能够自动检测修改配置 文件和重新配置本身,设置间隔秒数-->
<configuration monitorInterval="5" >
    <!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->

    <!--变量配置-->
    <Properties>
        <!-- 格式化输出:%date表示日期,%thread表示线程名,%X{TRACE_ID}这个是链路追踪的traceId, %-5level:级别从左显示5个字符宽度 %msg:日志消息,%n是换行符-->
        <!-- %logger{36} 表示 Logger 名字最长36个字符 -->
        <property name="LOG_PATTERN" value="%date{HH:mm:ss.SSS} 【%thread】 【%X{TRACE_ID}】 %-5level 【%logger{36}】 - %msg%n"/>
        <!-- 定义日志存储的路径 -->
        <property name="FILE_PATH" value="E:\\logs\\test"/>
        <property name="FILE_NAME" value="springboot-test"/>
    </Properties>

    <appenders>

        <console name="Console" target="SYSTEM_OUT">
            <!--输出日志的格式-->
            <PatternLayout pattern="${LOG_PATTERN}"/>
            <!--控制台只输出level及其以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
            <ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
        </console>

        <!--文件会打印出所有信息,这个log每次运行程序会自动清空,由append属性决定,适合临时测试用-->
        <File name="Filelog" fileName="${FILE_PATH}/test.log" append="false">
            <PatternLayout pattern="${LOG_PATTERN}"/>
        </File>

        <!-- 这个会打印出所有的info及以下级别的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档-->
        <RollingFile name="RollingFileInfo" fileName="${FILE_PATH}/info.log"
                     filePattern="${FILE_PATH}/${FILE_NAME}-INFO-%d{yyyy-MM-dd}_%i.log.gz">
            <!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
            <ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
            <PatternLayout pattern="${LOG_PATTERN}"/>
            <Policies>
                <!--interval属性用来指定多久滚动一次,默认是1 hour-->
                <TimeBasedTriggeringPolicy interval="1"/>
                <SizeBasedTriggeringPolicy size="10MB"/>
            </Policies>
            <!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹下7个文件开始覆盖-->
            <DefaultRolloverStrategy max="15"/>
        </RollingFile>

        <!-- 这个会打印出所有的warn及以下级别的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档-->
        <RollingFile name="RollingFileWarn" fileName="${FILE_PATH}/warn.log"
                     filePattern="${FILE_PATH}/${FILE_NAME}-WARN-%d{yyyy-MM-dd}_%i.log.gz">
            <!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
            <ThresholdFilter level="warn" onMatch="ACCEPT" onMismatch="DENY"/>
            <PatternLayout pattern="${LOG_PATTERN}"/>
            <Policies>
                <!--interval属性用来指定多久滚动一次,默认是1 hour-->
                <TimeBasedTriggeringPolicy interval="1"/>
                <SizeBasedTriggeringPolicy size="10MB"/>
            </Policies>
            <!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹下7个文件开始覆盖-->
            <DefaultRolloverStrategy max="15"/>
        </RollingFile>

        <!-- 这个会打印出所有的error及以下级别的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档-->
        <RollingFile name="RollingFileError" fileName="${FILE_PATH}/error.log"
                     filePattern="${FILE_PATH}/${FILE_NAME}-ERROR-%d{yyyy-MM-dd}_%i.log.gz">
            <!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
            <ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/>
            <PatternLayout pattern="${LOG_PATTERN}"/>
            <Policies>
                <!--interval属性用来指定多久滚动一次,默认是1 hour-->
                <TimeBasedTriggeringPolicy interval="1"/>
                <SizeBasedTriggeringPolicy size="10MB"/>
            </Policies>
            <!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹下7个文件开始覆盖-->
            <DefaultRolloverStrategy max="15"/>
        </RollingFile>

    </appenders>

    <!--Logger节点用来单独指定日志的形式,比如要为指定包下的class指定不同的日志级别等。-->
    <!--然后定义loggers,只有定义了logger并引入的appender,appender才会生效-->
    <loggers>

        <!--过滤掉spring和mybatis的一些无用的DEBUG信息-->
        <logger name="org.mybatis" level="info" additivity="false">
            <AppenderRef ref="Console"/>
        </logger>
        <!--监控系统信息-->
        <!--若是additivity设为false,则 子Logger 只会在自己的appender里输出,而不会在 父Logger 的appender里输出。-->
        <Logger name="org.springframework" level="info" additivity="false">
            <AppenderRef ref="Console"/>
        </Logger>

        <root level="info">
            <appender-ref ref="Console"/>
            <appender-ref ref="Filelog"/>
            <appender-ref ref="RollingFileInfo"/>
            <appender-ref ref="RollingFileWarn"/>
            <appender-ref ref="RollingFileError"/>
        </root>
    </loggers>

</configuration>

 

 

 

请求后看日志

 

18:00:12.730 【http-nio-8080-exec-1】 【d9c6d00bafbb4aefb2502ae97a766f32】 INFO  【com.example.springboottest.test.TestController】 - controller request come in http-nio-8080-exec-1
18:00:12.730 【http-nio-8080-exec-1】 【d9c6d00bafbb4aefb2502ae97a766f32】 INFO  【com.example.springboottest.test.service.impl.TestServiceImpl】 - service request come in http-nio-8080-exec-1
18:00:12.731 【http-nio-8080-exec-1】 【d9c6d00bafbb4aefb2502ae97a766f32】 INFO  【com.example.springboottest.test.service.impl.TestServiceImpl】 - service inner request come in http-nio-8080-exec-1

 

 

输出格式改为JSON 格式

 

可以看到,上边输出的日志格式 非JSON 格式,如果想使用日志输出的格式为 JOSN格式应该怎么办呢?

可以看到上边的log4j2.xml的配置文件 使用的是 PatternLayout ,我们可以改用下边的格式

 

<JsonLayout compact="true" locationInfo="true" complete="false" eventEol="true" pattern="${LOG_PATTERN}" />

 

输出结果

{"instant":{"epochSecond":1601169916,"nanoOfSecond":590000000},"thread":"http-nio-8080-exec-2","level":"INFO","loggerName":"com.example.springboottest.test.TestController","message":"controller request come in http-nio-8080-exec-2","endOfBatch":false,"loggerFqcn":"org.apache.logging.slf4j.Log4jLogger","threadId":159,"threadPriority":5,"source":{"method":"sayHello","file":"TestController.java","line":27,"class":"com.example.springboottest.test.TestController"}}
{"instant":{"epochSecond":1601169916,"nanoOfSecond":591000000},"thread":"http-nio-8080-exec-2","level":"INFO","loggerName":"com.example.springboottest.test.service.impl.TestServiceImpl","message":"service request come in http-nio-8080-exec-2","endOfBatch":false,"loggerFqcn":"org.apache.logging.slf4j.Log4jLogger","threadId":159,"threadPriority":5,"source":{"method":"doTestService","file":"TestServiceImpl.java","line":14,"class":"com.example.springboottest.test.service.impl.TestServiceImpl"}}
{"instant":{"epochSecond":1601169916,"nanoOfSecond":592000000},"thread":"http-nio-8080-exec-2","level":"INFO","loggerName":"com.example.springboottest.test.service.impl.TestServiceImpl","message":"service inner request come in http-nio-8080-exec-2","endOfBatch":false,"loggerFqcn":"org.apache.logging.slf4j.Log4jLogger","threadId":159,"threadPriority":5,"source":{"method":"doTestServiceInner","file":"TestServiceImpl.java","line":20,"class":"com.example.springboottest.test.service.impl.TestServiceImpl"}}

 

可以看到,输出的格式是JSON格式了,但是我们自己定义的 TRACEID 并没有输出。

我们可以修改为如下结果,添加我们自定义的字段

<JsonLayout compact="true" locationInfo="true" complete="false" eventEol="true" pattern="${LOG_PATTERN}">
                <KeyValuePair key="TRACE_ID" value="${ctx:TRACE_ID}"/>
            </JsonLayout>

 

 输出结果,可以看到,已经有了 TRACEID 字段了

 

 

{"instant":{"epochSecond":1601170158,"nanoOfSecond":492000000},"thread":"http-nio-8080-exec-2","level":"INFO","loggerName":"com.example.springboottest.test.TestController","message":"controller request come in http-nio-8080-exec-2","endOfBatch":false,"loggerFqcn":"org.apache.logging.slf4j.Log4jLogger","threadId":158,"threadPriority":5,"source":{"method":"sayHello","file":"TestController.java","line":27,"class":"com.example.springboottest.test.TestController"},"TRACE_ID":"130999f8b5154eecb41e56eca76260b2"}
{"instant":{"epochSecond":1601170158,"nanoOfSecond":493000000},"thread":"http-nio-8080-exec-2","level":"INFO","loggerName":"com.example.springboottest.test.service.impl.TestServiceImpl","message":"service request come in http-nio-8080-exec-2","endOfBatch":false,"loggerFqcn":"org.apache.logging.slf4j.Log4jLogger","threadId":158,"threadPriority":5,"source":{"method":"doTestService","file":"TestServiceImpl.java","line":14,"class":"com.example.springboottest.test.service.impl.TestServiceImpl"},"TRACE_ID":"130999f8b5154eecb41e56eca76260b2"}
{"instant":{"epochSecond":1601170158,"nanoOfSecond":494000000},"thread":"http-nio-8080-exec-2","level":"INFO","loggerName":"com.example.springboottest.test.service.impl.TestServiceImpl","message":"service inner request come in http-nio-8080-exec-2","endOfBatch":false,"loggerFqcn":"org.apache.logging.slf4j.Log4jLogger","threadId":158,"threadPriority":5,"source":{"method":"doTestServiceInner","file":"TestServiceImpl.java","line":20,"class":"com.example.springboottest.test.service.impl.TestServiceImpl"},"TRACE_ID":"130999f8b5154eecb41e56eca76260b2"}

 

 

分享到:
评论

相关推荐

    SpringBoot使用TraceId日志链路追踪

    SpringBoot集成log4j实现TraceId日志链路追踪,无需引入组件,主要解决业务调用链场景,很长,调了各种各样的方法,看日志的时候,各个接口的日志穿插,查看不方便。为了解决这个痛点,就使用了TraceId,根据TraceId...

    异构系统链路追踪——滴滴 trace 实践.pdf

    - **业务id和traceid关联**:通过将业务ID与trace ID相关联,可以在大量追踪数据中快速定位到特定业务相关的调用链路。 - **根span具有业务代表性**:确定根span作为整个业务流程的代表,方便后续分析。 - **可下...

    微服务日志链路追踪-log-trace-spring-boot.zip

    Sleuth自动插入跟踪ID(Trace ID)和跨度ID(Span ID)到每个微服务请求中,这些ID可以在日志中查看,用于连接不同服务的调用链路。 Zipkin是一个流行的分布式追踪系统,它可以收集并可视化Sleuth产生的跟踪数据。...

    dubbo traceid

    本篇文章将详细讲解如何在不修改Dubbo源码的前提下,实现Trace ID的穿透,以便在微服务环境中实现全局唯一的ID来追踪服务调用链路,并统一处理日志。 首先,理解`Trace ID`的概念。Trace ID是一个全局唯一的标识符...

    SpringBoot+AOP+TraceID.pdf

    在本文档中,还讲解了如何使用 MDC(Mapped Diagnostic Context)和 TraceID 来实现日志链(Log Chain)。MDC 是一种机制,用于在多个日志记录之间传递信息。TraceID 是一个唯一的标识符,用于标识一条日志记录。...

    微服务架构之链路追踪.pdf

    微服务架构中链路追踪的实现是分布式系统监控与故障排查的重要技术,其主要目的是为了能够跟踪微服务之间的调用链路,以便监控服务的健康状态,诊断问题发生的环节,并提供性能分析的依据。从给定的文件内容中,我们...

    基于SpringBoot自动装配实现的对于OpenFeign扩展请求传递traceId,分布式服务日志查询串联标记

    引用步骤: 1.基于SpringBoot自动装配,引用jar包即可,坐标如下:...3.日志配置中添加traceId引用,如下: [%date{yyyy-MM-dd HH:mm:ss.SSS}] [%X{traceId}] [%thread] %-5level %logger{80} %line - %msg%n&lt;/Pattern&gt;

    视频-分布式链路追踪skywalking.txt

    下面将对SkyWalking的概念、分布式链路追踪的基本原理及其与SkyWalking的关系进行详细介绍。 ### SkyWalking简介 SkyWalking是一款开源的应用性能监控(APM)工具,它可以自动发现、可视化并诊断分布式系统的问题...

    阿里云SkyWalking链路追踪服务.pdf

    阿里云SkyWalking链路追踪服务是一种分布式链路追踪解决方案,旨在帮助开发者快速定位和解决分布式系统中的性能瓶颈问题。该服务基于OpenTracing规范,支持多种编程语言和框架,包括Java、.NET、Python、Go等。 ...

    Go微服务框架go-kratos学习05:分布式链路追踪 OpenTelemetry 使用.doc

    分布式链路追踪是微服务架构中的一种监控和定位技术,旨在跟踪微服务中请求链路的执行过程。随着微服务架构的流行,分布式链路追踪也蓬勃发展起来,出现了许多有名的产品,如 Jaeger、Pinpoint、Zipkin、Skywalking ...

    SOFARPC链路追踪剖析1

    而有了链路追踪,可以通过全局唯一的TraceId来追踪一个请求的完整调用链,并通过Span来表示每个系统的调用阶段,包括Start、Client Send、Server Recv、Server Send、Client Recv和End等。 SOFARPC作为公共通讯框架...

    Skywalking链路追踪自身耗时和总耗时算法分析

    其中,Trace是整个追踪链路的入口,TraceSegment是追踪链路中的一个或多个Span的组合,而Span则是追踪链路中的一个基本单元。一个Span可能有零个、一个或多个children Span。 自身耗时和总耗时的计算方法 在...

    3. SpringCloudSleuth链路追踪概述1

    Spring Cloud Sleuth的实现原理是基于Dapper的思想,将应用程序中的每个请求都作为一个Span,Span之间的关系通过ID和父ID来建立,然后将这些Span组装成一个Trace,最后将Trace输出到日志中,以便后续的分析和追踪。...

    从头分析一则traceId穿透问题(附解决方案).docx

    接下来,我们将重点关注如何在Spring Cloud Sleuth与Logback整合后,确保线程池中输出的日志包含trace ID。 #### 解决日志中缺失trace ID的问题 在Spring Cloud Sleuth与Logback整合的场景下,有时会遇到线程池中...

    统一监控平台方案(日志监控、方法监控、调用链路监控)

    - **Zipkin**:支持链路追踪,一条链路由多个span组成,通过trace ID关联起来。 - **Pinpoint**:专注于方法级别的监控,包括Pinpoint-Collector、Pinpoint-Agent、HBaseStorage和Pinpoint-Web等组件,实现从数据...

    毕业设计基于SpringCloud微服务分布式链路追踪项目源码.zip

    traceId :记录整个服务链路的 ID,由首次请求方创建(这里使用zst-service-demo01创建),整个服务链路中唯一 spanId :记录当前服务块的 ID,由当前服务方创建。 parentId :记录上一个请求服务的 spanId 安装教程...

    链路追踪(Tracing)其实很简单——单链路诊断1

    * 核心接口埋点:通过在接口执行前后插桩埋点,记录的基础链路追踪信息,包括 TraceId、RpcId(SpanId)、时间、状态、IP、接口名称等。 * 自动关联数据:在调用生命周期内,可以自动记录的关联信息,包括 SQL、请求...

    8-8+分布式链路追踪在字节跳动的实践.pdf

    字节跳动的链路追踪系统在实际应用中,能够帮助团队快速响应告警,通过Trace关联错误日志,定位问题根源。例如,当服务失败率上升时,可以通过查看Trace来追踪错误链路,从而高效地解决故障。 综上,字节跳动通过...

    详解spring cloud分布式日志链路跟踪

    它会在日志中添加一些特有的标签,如traceId和spanId等,这些标签能够标识出整个链路的流程,以及每个服务调用的耗时和状态。一旦有服务调用失败,通过这些标识就能快速定位到是哪个服务出现了问题。 在Spring ...

Global site tag (gtag.js) - Google Analytics