Sleuth链路添加额外传播字段

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 dkBaggageKeys = new ArrayList<>();
//      dkBaggageKeys.add(OPERATION_ID);
//      List 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 frontTraceKeys = new ArrayList<>();
        frontTraceKeys.add(OPERATION_ID);
        frontTraceKeys.add(OPERATION_NAME);
        List 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 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日志配置



    
    
    

    
        
            %date [%thread] %-5level %logger{80} - %msg%n
        
    

    
        ${LOG_FILE}.json
        
            ${LOG_FILE}/${APP_NAME}.json.%d{yyyy-MM-dd}.gz
            7
        
        
            
                
                    UTC
                
                
                    
                        {
                        "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}"
                        }
                    
                
            
        
    

    
        
        
    

六.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链路添加额外传播字段)