OpenTelemetry笔记(4)-Span上下文传播

背景

当 2 个进程之间进行交互时,span 传递的上下文就会中断,需要有一种机制,在 RPC 期间,保持链路跟踪

思路

在 RPC 调用时,将必要的 Span 上下文数据作为附带信息传递给对方进程,在对方接收时识别附带的信息,并进行解码恢复 Span 上下文环境

TextMapPropagator

  • TextMapPropagator 定义了 2 个方法
    • inject 方法用于将当前上文环境数据注入到远程上下文环境中
    • extract 方法用于在接收端数据时恢复上下文环境
  • TextMapSetter 用于对目标对象设置传播字段属性值
  • TextMapGetter 用于对目标对象获取传播字段属性值

接口定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public interface TextMapPropagator {

Collection<String> fields();


<C> void inject(Context context, @Nullable C carrier, TextMapSetter<C> setter);


<C> Context extract(Context context, @Nullable C carrier, TextMapGetter<C> getter);
}

public interface TextMapSetter<C> {

void set(@Nullable C carrier, String key, String value);
}


public interface TextMapGetter<C> {


Iterable<String> keys(C carrier);

@Nullable
String get(@Nullable C carrier, String key);
}

接口实现示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class DemoPropagator implements TextMapPropagator {
private static final String FIELD = "X-demo-field";
private static final ContextKey<Long> PROPAGATION_START_KEY =
ContextKey.named("propagation.start");

@Override
public List<String> fields() {
return Collections.singletonList(FIELD);
}

@Override
public <C> void inject(Context context, C carrier, TextMapSetter<C> setter) {
Long propagationStart = context.get(PROPAGATION_START_KEY);
if (propagationStart == null) {
propagationStart = System.currentTimeMillis();
}
setter.set(carrier, FIELD, String.valueOf(propagationStart));
}

@Override
public <C> Context extract(Context context, C carrier, TextMapGetter<C> getter) {
String propagationStart = getter.get(carrier, FIELD);
if (propagationStart != null) {
return context.with(PROPAGATION_START_KEY, Long.valueOf(propagationStart));
} else {
return context;
}
}
}

ContextPropagators

Span 上下文传播,其是 TextMapPropagator 的一个容器,用于注册 TextMapPropagator

1
2
3
4
public interface ContextPropagators {

TextMapPropagator getTextMapPropagator();
}