问题描述
在开发中,使用okhttp起websocket,打印日志中无法打印traceId和spanId,导致生产问题无法排查
OkHttpClient client = new OkHttpClient.Builder().build();
client.newWebSocket(request, new WebSocketListener() {
// do something
}
解决方法
经过多次尝试后,使用了一种比较简单的方法解决了。
整体思路是,使用okhttp自带的interceptor,自定义自己的拦截器,在拦截器中放入traceId等信息。
- 首先是项目启动类
@Configuration
public class OpenTracingConfig {
@Value("${spring.application.name}")
private String serviceName;
@Value("${jager.host}")
private String jagerHost;
@Bean
public io.opentracing.Tracer tracer() {
JaegerTracer.Builder builder = new JaegerTracer.Builder(serviceName);
builder.withReporter(new RemoteReporter.Builder().withSender(new UdpSender(jagerHost, 6831, 65000)).build());
builder.withSampler(new ProbabilisticSampler(1.0));
builder.withScopeManager(new WrappedThreadLocalScopeManager());
return builder.build();
}
class WrappedThreadLocalScopeManager extends ThreadLocalScopeManager {
@Override
public Scope activate(Span span, boolean finishOnClose) {
if (span != null) {
String traceContext = span.context().toString();
if (traceContext != null) {
String[] traceInfo = traceContext.split(":");
if (traceInfo.length == 4) {
// 在打印日志中加入traceId spanId parentSpanId
MDC.put("X-B3-TraceId", traceInfo[0]);
MDC.put("X-B3-SpanId", traceInfo[1]);
MDC.put("X-B3-ParentSpanId", traceInfo[2]);
}
}
}
return super.activate(span, finishOnClose);
}
}
}
- 在外部获取traceId等信息,在拦截器中手动放入信息
public class OkHttpTraceInterceptor implements Interceptor {
/**
* traceId
*/
private final String traceId;
/**
* spanId
*/
private final String spanId;
/**
* parentSpanId
*/
private final String parentSpanId;
public OkHttpTraceInterceptor(String traceId, String spanId, String parentSpanId) {
this.traceId = traceId;
this.spanId = spanId;
this.parentSpanId = parentSpanId;
}
@Override
public Response intercept(Chain chain) throws IOException {
// 这边有尝试过注入tracer,或者外部获取tracer传入到拦截器,都无法获取到traceId,
// 所以无奈只能外部获取具体值,传入拦截器,希望知道的大佬指点下是为什么
// JaegerTracer tracer= SpringContextHolder.getBean("tracer");
// SpanContext context = tracer.activeSpan().context(); // 这里的activeSpan()获取到的是null
//手动放入traceid spanid parentspanid
MDC.put("X-B3-TraceId", traceId);
MDC.put("X-B3-SpanId", spanId);
MDC.put("X-B3-ParentSpanId", parentSpanId);
return chain.proceed(chain.request());
}
}
- 构建okhttp传入拦截器参数
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(new OkHttpTraceInterceptor(MDC.get("X-B3-TraceId"), MDC.get("X-B3-SpanId"), MDC.get("X-B3-ParentSpanId")))
.build();
本次解决只是为了解决问题而解决,并没有了解opentracing的原理,例如为什么在OkHttpTraceInterceptor拦截器中获取tracer的activeSpan(),始终是空,或者在OkHttpTraceInterceptor拦截器中直接用MDC.get(“X-B3-TraceId”)也是空,希望明白的大佬能指点一下!