美文网首页
Sleuth链路添加额外传播字段

Sleuth链路添加额外传播字段

作者: 烂融小菜花 | 来源:发表于2019-11-27 12:01 被阅读0次

    SpringCloud官网中关于Sleuth链路添加额外传播字段的描述如下:

    有时需要传播额外的字段,例如请求 ID 或备用跟踪上下文。例如,如果你在 Cloud Foundry 环境中,可能希望传递请求 ID,如下例所示:

    // when you initialize the builder, define the extra field you want to propagate
    Tracing.newBuilder().propagationFactory(
      ExtraFieldPropagation.newFactory(B3Propagation.FACTORY, "x-vcap-request-id")
    );
    
    // later, you can tag that request ID or use it in log correlation
    requestId = ExtraFieldPropagation.get("x-vcap-request-id");
    

    即在初始化时,添加需要额外传播的字段。在之后需要用到的地方可以通过ExtraFieldPropagation.get("x-vcap-request-id")的方式来获取。

    在具体项目中的用法:

    我们公司的需求是:链路追踪不止可以记录后台微服务的的调用链,也要把前端用户的操作单元给记录下来。
    实现方式:由前端传两个标识参数来记录用户操作的链路,在网关时,获取到传递过来的参数,然后通过Brave的额外传播字段进行链路捆绑,并在客户端(具体的微服务应用)进行配置,将 baggage 值设置为 Slf4j 的 MDC,然后即可在日志中输出该参数信息。

    一.定义额外传播的字段:

    在网关中定义传播的额外字段,经测试,有两种方式可以添加额外的字段

    方式一:

    @Configuration
    @Order(TraceWebServletAutoConfiguration.TRACING_FILTER_ORDER - 2)
    public class SleuthPropagateConfig {
    
        /** 前端操作ID */
        public static final String OPERATION_ID = "X-Operation-ID";
        /** 前端操作名称 如:行政区划/保存 */
        public static final String OPERATION_NAME = "X-Operation-Name";
    
        @Bean
        public SleuthProperties sleuthProperties() {
            SleuthProperties sleuthProperties = new SleuthProperties();
            //会加baggage-前缀
    //      List<String> dkBaggageKeys = new ArrayList<>();
    //      dkBaggageKeys.add(OPERATION_ID);
    //      List<String> baggageKeys = sleuthProperties.getBaggageKeys();
    //      if (CollectionUtils.isEmpty(baggageKeys)) {
    //          sleuthProperties.setBaggageKeys(dkBaggageKeys);
    //          return sleuthProperties;
    //      }
    //      if (!baggageKeys.contains(OPERATION_ID)) {
    //          sleuthProperties.getBaggageKeys().add(OPERATION_ID);
    //      }
    //      if (!baggageKeys.contains(OPERATION_NAME)) {
    //          sleuthProperties.getBaggageKeys().add(OPERATION_NAME);
    //      }
            
            //不会加前缀
            List<String> frontTraceKeys = new ArrayList<>();
            frontTraceKeys.add(OPERATION_ID);
            frontTraceKeys.add(OPERATION_NAME);
            List<String> propagationKeys = sleuthProperties.getPropagationKeys();
            if (CollectionUtils.isEmpty(propagationKeys)) {
                sleuthProperties.setPropagationKeys(frontTraceKeys);
                return sleuthProperties;
            }
            if (!propagationKeys.contains(OPERATION_ID)) {
                sleuthProperties.getPropagationKeys().add(OPERATION_ID);
            }
            if (!propagationKeys.contains(OPERATION_NAME)) {
                sleuthProperties.getPropagationKeys().add(OPERATION_NAME);
            }
            return sleuthProperties;
        }
    }
    

    但是这种方式不是很优雅,本人用的是第二种方式
    方式二:

    @Configuration
    @Order(TraceWebServletAutoConfiguration.TRACING_FILTER_ORDER - 2)
    public class SleuthPropagateConfig {
    
        /** 前端操作ID */
        public static final String OPERATION_ID = "X-Operation-ID";
        /** 前端操作名称 如:行政区划/保存 */
        public static final String OPERATION_NAME = "X-Operation-Name";
    
        /**
         * 定义链路追踪额外传播字段
         * @return
         */
        @Bean
        public Tracing tracing() {
            return Tracing.newBuilder().propagationFactory(
                    ExtraFieldPropagation.newFactoryBuilder(B3Propagation.FACTORY)
                            .addField(OPERATION_NAME)
                            .addField(OPERATION_ID)
                            //.addPrefixedFields("x-baggage-", Arrays.asList(OPERATION_NAME, OPERATION_ID))
                            .build()
            ).build();
        }
    }
    

    二.在网关过滤器中设置传播字段的信息

    @Component
    public class FrontTraceFilter implements GlobalFilter, Ordered {
    
        @Override
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    
            String operationId = exchange.getRequest().getQueryParams().getFirst(SleuthPropagateConfig.OPERATION_ID);
            String operationName = exchange.getRequest().getQueryParams().getFirst(SleuthPropagateConfig.OPERATION_NAME);
    
            if (!StringUtils.isEmpty(operationId)
                    && StringUtils.isEmpty(ExtraFieldPropagation.get(SleuthPropagateConfig.OPERATION_ID))) {
                ExtraFieldPropagation.set(SleuthPropagateConfig.OPERATION_ID, operationId);
            }
            if (!StringUtils.isEmpty(operationName)
                    && StringUtils.isEmpty(ExtraFieldPropagation.get(SleuthPropagateConfig.OPERATION_NAME))) {
                ExtraFieldPropagation.set(SleuthPropagateConfig.OPERATION_NAME, operationName);
            }
    
            return chain.filter(exchange);
        }
    
        @Override
        public int getOrder() {
            return 0;
        }
    }
    

    三.在客户端(微服务应用)添加配置

    在application.yml中添加额外传播字段的相关配置,sleuth2.0后必须配置,否则在客户端获取不到字段信息

    spring:
      application:
        name: demo-feign2
      sleuth:
        sampler:
          #调用链信息采样率
          probability: 1.0
        # 注意, Sleuth2.0.0之后, baggage的 key 必须在这里配置才能生效
    #    baggage-keys:
    #      - X-Operation-ID
    #      - X-Operation-Name
        propagation-keys:
          - X-Operation-ID
          - X-Operation-Name
        log:
          slf4j:
            #自动额外传播字段设置为 Slf4j 的 MDC
            whitelisted-mdc-keys:
            - X-Operation-ID
            - X-Operation-Name
    

    四.在客户端中使用额外的传播字段

    ExtraFieldPropagation.get("key");
    

    五.logback日志配置

    <?xml version="1.0" encoding="UTF-8"?>
    <configuration>
        <springProperty scope="context" name="APP_NAME" source="spring.application.name"/>
        <springProperty scope="context" name="LOG_FILE" source="logging.path"/>
        <springProperty scope="context" name="ServerPort" source="server.port"/>
    
        <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
            <encoder>
                <pattern>%date [%thread] %-5level %logger{80} - %msg%n</pattern>
            </encoder>
        </appender>
    
        <appender name="LOGSTASH" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <file>${LOG_FILE}.json</file>
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <fileNamePattern>${LOG_FILE}/${APP_NAME}.json.%d{yyyy-MM-dd}.gz</fileNamePattern>
                <maxHistory>7</maxHistory>
            </rollingPolicy>
            <encoder charset="UTF-8" class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
                <providers>
                    <timestamp>
                        <timeZone>UTC</timeZone>
                    </timestamp>
                    <pattern>
                        <pattern>
                            {
                            "level": "%level",
                            "service": "${APP_NAME:-}",
                            "traceId": "%X{X-B3-TraceId:-}",
                            "spanId": "%X{X-B3-SpanId:-}",
                            "parentSpanId": "%X{X-B3-ParentSpanId:-}",
                            "exportable": "%X{X-Span-Export:-}",
                            "pid": "${PID:-}",
                            "thread": "%thread",
                            "class": "%logger{40}",
                            "method": "%M",
                            "line": "%L",
                            "message": "%message",
                            "operationId": "%X{X-Operation-ID}"
                            "operationName": "%X{X-Operation-Name}"
                            }
                        </pattern>
                    </pattern>
                </providers>
            </encoder>
        </appender>
    
        <root level="INFO">
            <appender-ref ref="LOGSTASH" />
            <appender-ref ref="STDOUT" />
        </root>
    </configuration>
    

    六.logback日志输出结果

    {"@timestamp":"2019-11-27T04:00:33.233+00:00","level":"INFO","service":"demo-feign2","traceId":"04f1bfb59beb7053","spanId":"c7ba04760057c6f2","parentSpanId":"04f1bfb59beb7053","exportable":"true","pid":"43252","thread":"http-nio-8302-exec-2","class":"com.caihua.demo.feign.web.HiController","method":"sayHi","line":"19","message":"this is feign2 controller, begin to call the feign service","operationId":"123","operationName":"save"}
    {"@timestamp":"2019-11-27T04:00:33.243+00:00","level":"INFO","service":"demo-producer2","traceId":"04f1bfb59beb7053","spanId":"9ece8de790d6ad9e","parentSpanId":"c7ba04760057c6f2","exportable":"true","pid":"7968","thread":"http-nio-8301-exec-4","class":"com.caihua.demo.DemoProducer2Application","method":"home","line":"29","message":"this is producer controller, begin to call producer2 service ","operationId":"123","operationName":"save"}
    {"@timestamp":"2019-11-27T04:00:33.244+00:00","level":"INFO","service":"demo-producer2","traceId":"04f1bfb59beb7053","spanId":"9ece8de790d6ad9e","parentSpanId":"c7ba04760057c6f2","exportable":"true","pid":"7968","thread":"http-nio-8301-exec-4","class":"com.caihua.demo.producer.HiService","method":"sayHi","line":"21","message":"this is producer2 HiService, i will call private method","operationId":"123","operationName":"save"}
    {"@timestamp":"2019-11-27T04:00:33.244+00:00","level":"INFO","service":"demo-producer2","traceId":"04f1bfb59beb7053","spanId":"9ece8de790d6ad9e","parentSpanId":"c7ba04760057c6f2","exportable":"true","pid":"7968","thread":"http-nio-8301-exec-4","class":"com.caihua.demo.producer.HiService","method":"sayHello","line":"28","message":"hello: cai, this is private method","operationId":"123","operationName":"save"}
    
    

    相关文章

      网友评论

          本文标题:Sleuth链路添加额外传播字段

          本文链接:https://www.haomeiwen.com/subject/ayxpwctx.html