Sleuth输出TraceId

一、环境搭建

1.1包配置

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-sleuth</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zipkin</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

1.2日志配置

<?xml version="1.0" encoding="UTF-8"?>
<configuration scanPeriod="60 seconds" debug="false">
    <!-- https://docs.spring.io/spring-boot/docs/current/reference/html/howto-logging.html -->

    <property name="CONSOLE_LOG_PATTERN"
              value="[%d{yyyy-MM-dd HH:mm:ss.SSS} %highlight(%-5level) %X{X-B3-TraceId} %X{traceId} %yellow(%X{X-B3-TraceId}),%green(%X{X-B3-SpanId}),%blue(%X{X-B3-ParentSpanId}) %yellow(%thread) %green(%logger) %msg%n"/>

    <include resource="org/springframework/boot/logging/logback/defaults.xml"/>

    <!--<include resource="org/springframework/boot/logging/logback/base.xml"/>-->
    <include resource="org/springframework/boot/logging/logback/console-appender.xml"/>
    
    <root level="INFO">
        <appender-ref ref="CONSOLE"/>
    </root>

</configuration>

二、实现分析

2.1 sleuth日志插件

org.springframework.cloud.sleuth.log.Slf4jCurrentTraceContext#newScope

  1. 获取父span设置的信息
    2)将当前span的信息设置到MDC中,如果当前span为空,需要从MDC中移除。
    3)当span close时,将MDC设置为父级span信息。
@Override public Scope newScope(@Nullable TraceContext currentSpan) {
        final String previousTraceId = MDC.get("traceId");
        final String previousParentId = MDC.get("parentId");
        final String previousSpanId = MDC.get("spanId");
        final String spanExportable = MDC.get("spanExportable");
        final String legacyPreviousTraceId = MDC.get(LEGACY_TRACE_ID_NAME);
        final String legacyPreviousParentId = MDC.get(LEGACY_PARENT_ID_NAME);
        final String legacyPreviousSpanId = MDC.get(LEGACY_SPAN_ID_NAME);
        final String legacySpanExportable = MDC.get(LEGACY_EXPORTABLE_NAME);

        if (currentSpan != null) {
            String traceIdString = currentSpan.traceIdString();
            MDC.put("traceId", traceIdString);
            MDC.put(LEGACY_TRACE_ID_NAME, traceIdString);
            String parentId = currentSpan.parentId() != null ?
                    HexCodec.toLowerHex(currentSpan.parentId()) :
                    null;
            replace("parentId", parentId);
            replace(LEGACY_PARENT_ID_NAME, parentId);
            String spanId = HexCodec.toLowerHex(currentSpan.spanId());
            MDC.put("spanId", spanId);
            MDC.put(LEGACY_SPAN_ID_NAME, spanId);

2.2 Logback获取MDC信息

Logback对象层级关系:Logger -> Appender -> Encoder -> PatternLayout,Layout中head定义了pattern的convert。

ch.qos.logback.core.OutputStreamAppender#subAppend

subAppend调用prepareForDeferredProcessing设置MDC。

    public void prepareForDeferredProcessing() {
        this.getFormattedMessage();
        this.getThreadName();
        // fixes http://jira.qos.ch/browse/LBCLASSIC-104
        this.getMDCPropertyMap();
    }

2.3 MDCConvert

%X{X-B3-TraceId}被定义为MDCConverter,它从MDC中获取信息。

 @Override
    public String convert(ILoggingEvent event) {
        Map<String, String> mdcPropertyMap = event.getMDCPropertyMap();

        if (mdcPropertyMap == null) {
            return defaultValue;
        }

        if (key == null) {
            return outputMDCForAllKeys(mdcPropertyMap);
        } else {

            String value = mdcPropertyMap.get(key);
            if (value != null) {
                return value;
            } else {
                return defaultValue;
            }
        }
    }
image.png
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • why: 1,微服务架构微服务增多,一个客户端请求形成一个复杂的分布式服务调用链路,如果任何一个服务延迟过高或...
    xiaoyang08阅读 3,941评论 0 5
  • 在应用程序中添加日志记录总的来说基于三个目的:监视代码中变量的变化情况,周期性的记录到文件中供其他应用进行统计分析...
    时待吾阅读 5,125评论 0 6
  • 在应用程序中添加日志记录总的来说基于三个目的:监视代码中变量的变化情况,周期性的记录到文件中供其他应用进行统计分析...
    时待吾阅读 5,188评论 1 13
  • 一、内容回顾 1、积极主动可以构建人生的语言。 2、分身术第一法则——口吐莲花 3、当你不...
    小玉来啦阅读 874评论 7 3
  • 0718(D3),亲爱的师师,今天我要表杨你 1.早晨5:30准时起床,运动,然后做营养早餐,早早去上班,开启元气...
    师师成长记阅读 272评论 0 0

友情链接更多精彩内容