对于SpringCloud,开源社区已经实现了OpenTracing/OpenTelemetry, 但是对于Dubbo 或者 公司内部的RPC框架,却还没有Jaeger的实现,如果要使用,需要我们自己实现。
今天我们就以Jaeger 为例, 来聊下如何实现OpenTracing/OpenTelemetry。
转载请注明出处(手动微笑🙂)
OpenTracing-Java
一、OpenTracing/OpenTelemetry 实现思路
二、OpenTracing/OpenTelemetry Java实现实例
以下为OpenTracing的标准实现思路,以Http请求为例;
2.1 客户端标准实现
Span span = tracer.buildSpan("...").start();
try (Scope scope = tracer.scopeManager().activate(span)) {
span.setTag("...", "...");
//... 业务调用逻辑
} catch (Exception e) {
span.log(...);
} finally {
// Optionally finish the Span if the operation it represents
//is logically completed at this point.
span.finish();
}
2.2 服务端实现
/**
* If request is traced then do not start new span.
*/
if (servletRequest.getAttribute(SERVER_SPAN_CONTEXT) != null) {
chain.doFilter(servletRequest, servletResponse);
} else {
SpanContext extractedContext = tracer.extract(Format.Builtin.HTTP_HEADERS,
new HttpServletRequestExtractAdapter(httpRequest));
final Span span = tracer.buildSpan(httpRequest.getMethod())
.asChildOf(extractedContext)
.withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_SERVER)
.start();
httpRequest.setAttribute(SERVER_SPAN_CONTEXT, span.context());
for (ServletFilterSpanDecorator spanDecorator: spanDecorators) {
spanDecorator.onRequest(httpRequest, span);
}
try (Scope scope = tracer.activateSpan(span)) {
chain.doFilter(servletRequest, servletResponse);
if (!httpRequest.isAsyncStarted()) {
for (ServletFilterSpanDecorator spanDecorator : spanDecorators) {
spanDecorator.onResponse(httpRequest, httpResponse, span);
}
}
// catch all exceptions (e.g. RuntimeException, ServletException...)
} catch (Throwable ex) {
for (ServletFilterSpanDecorator spanDecorator : spanDecorators) {
spanDecorator.onError(httpRequest, httpResponse, ex, span);
}
throw ex;
} finally {
if (httpRequest.isAsyncStarted()) {
// what if async is already finished? This would not be called
httpRequest.getAsyncContext()
.addListener(new AsyncListener() {
@Override
public void onComplete(AsyncEvent event) throws IOException {
HttpServletRequest httpRequest = (HttpServletRequest) event.getSuppliedRequest();
HttpServletResponse httpResponse = (HttpServletResponse) event.getSuppliedResponse();
for (ServletFilterSpanDecorator spanDecorator: spanDecorators) {
spanDecorator.onResponse(httpRequest,
httpResponse,
span);
}
span.finish();
}
@Override
public void onTimeout(AsyncEvent event) throws IOException {
HttpServletRequest httpRequest = (HttpServletRequest) event.getSuppliedRequest();
HttpServletResponse httpResponse = (HttpServletResponse) event.getSuppliedResponse();
for (ServletFilterSpanDecorator spanDecorator : spanDecorators) {
spanDecorator.onTimeout(httpRequest,
httpResponse,
event.getAsyncContext().getTimeout(),
span);
}
}
@Override
public void onError(AsyncEvent event) throws IOException {
HttpServletRequest httpRequest = (HttpServletRequest) event.getSuppliedRequest();
HttpServletResponse httpResponse = (HttpServletResponse) event.getSuppliedResponse();
for (ServletFilterSpanDecorator spanDecorator: spanDecorators) {
spanDecorator.onError(httpRequest,
httpResponse,
event.getThrowable(),
span);
}
}
@Override
public void onStartAsync(AsyncEvent event) throws IOException {
}
});
} else {
// If not async, then need to explicitly finish the span associated with the scope.
// This is necessary, as we don't know whether this request is being handled
// asynchronously until after the scope has already been started.
span.finish();
}
}
}