Java 应用通过 OpenTelemetry API 实现手动埋点( 五 )

上面代码中我们首先通过 openTelemetry.getTracer(OrderController.class.getName()) 方法来初始化 Tracer,然后通过 tracer.spanBuilder("getAllOrders").startSpan() 方法来创建一个新的 Span,接着通过 span.makeCurrent() 方法将 Span 注入到上下文中,然后就可以在 try 代码块中执行我们的业务逻辑了,这里我们添加了两个属性,如果出现了异常则会记录异常信息,最后在 finally 代码块中结束 Span 。
我们还需要修改 Dockerfile 中的启动命令,代码如下所示:
# ......# CMD ["mvn", "-Pdev", "spring-boot:run"]CMD ["mvn", "spring-boot:run"]因为现在我们不需要使用 java agent 了,所以去掉 -Pdev 参数(该 profile 中定义了 java agent 启动参数),然后重新构建镜像,重新启动容器,当我们访问订单列表后就可以看到 Jaeger UI 中多了一个 getAllOrders 的 span 了 。

Java 应用通过 OpenTelemetry API 实现手动埋点

文章插图
很明显我们可以看到现在的 span 非常简单,没有和前端 frontend 服务的 span 关联起来 。
由于前端 frontend 在请求后端接口的时候我们已经注入了 W3CTraceContext,所以我们只需要在 Java 应用中通过 propagation api 来获取到 span context,然后将其作为父级 span,这样就可以将前端的 span 和后端的 span 关联起来了 。
这里我们可以添加一个拦截器来使用 propagation 接口解析 span context,代码如下所示:
// src/main/java/com/youdianzhishi/orderservice/interceptor/OpenTelemetryInterceptor.javapackage com.youdianzhishi.orderservice.interceptor;// ......@Componentpublic class OpenTelemetryInterceptor implements HandlerInterceptor {    @Autowired    private OpenTelemetry openTelemetry;    @Override    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {        TextMapGetter<HttpServletRequest> getter = new TextMapGetter<>() {            @Override            public Iterable<String> keys(HttpServletRequest carrier) {                return Collections.list(carrier.getHeaderNames());            }            @Override            public String get(HttpServletRequest carrier, String key) {                return carrier.getHeader(key);            }        };        // 提取传入的Trace Context        Context extractedContext = openTelemetry.getPropagators().getTextMapPropagator()                                       .extract(Context.current(), request, getter);        StringBuilder sb = new StringBuilder();        sb.append(request.getMethod()).append(" ").append(request.getRequestURI());        Span span = tracer.spanBuilder(sb.toString()).setParent(extractedContext)                    .startSpan();        // 将解析出来的SpanContext存储在请求属性中,以便后续使用        request.setAttribute("currentSpan", span);        return true;    }}上面代码中我们首先通过 openTelemetry.getPropagators().getTextMapPropagator() 方法来获取到 TextMapPropagator


推荐阅读