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

我们知道对于 JAVA 应用可以通过 OpenTelemetry 提供的 Java agent 来实现自动埋点功能,在大多数场景下也完全足够了,但是有时候我们需要更加精细的控制,这时候我们就需要使用手动埋点的方式来实现了 。
使用注解埋点我们可以在 Java 应用通过手动埋点的方式来实现链路追踪,但如果我们不希望进行太多的代码更改,那么可以使用注解的方式来实现,OpenTelemetry 提供了一些注解来帮助我们实现手动埋点,比如 @WithSpan@SpanAttribute
首先我们需要添加依赖库 opentelemetry-instrumentation-annotations
<dependencies>  <dependency>    <groupId>io.opentelemetry.instrumentation</groupId>    <artifactId>opentelemetry-instrumentation-annotations</artifactId>    <version>1.29.0</version>  </dependency></dependencies>开发人员可以使用 @WithSpan 注解来向 OpenTelemetry 自动检测发送信号,每当标记的方法被执行时都应创建一个新的 span 。
比如我们在 Order Service 中的 IndexController 中添加一个 @WithSpan 注解,代码如下所示:
// src/mAIn/java/com/youdianzhishi/orderservice/controller/IndexController.javapackage com.youdianzhishi.orderservice.controller;// ......import io.opentelemetry.instrumentation.annotations.WithSpan;@RestController@RequestMApping("/")public class IndexController {    @GetMapping    @WithSpan    public ResponseEntity<String> home(HttpServletRequest request) {        return new ResponseEntity<>("Hello OpenTelemetry!", HttpStatus.OK);    }}然后我们重建镜像,重新启动容器,当我们访问首页的时候就可以看到 Jaeger UI 中多了一个 IndexController.home 的 span 了 。


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

文章插图
每次应用程序调用有注解的方法时,它都会创建一个表示其持续时间并提供任何抛出异常的 span 。默认情况下,span 名称是 <className>.<methodName>,当然也可以在注解中提供了一个名称作为参数,比如可以使用 @WithSpan("indexSpan") 来指定 span 的名称,这样在 Jaeger UI 中就可以看到 indexSpan 的 span 了 。

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

文章插图
此外当为一个带注解的方法创建一个 span 时,可以通过使用 @SpanAttribute 注解来自动将方法调用的参数值添加为创建 span 的属性 。
比如我们在 IndexController 中添加一个 fetchId 函数,并接收一个 id 参数,我们就可以使用 @SpanAttribute 注解来将接收的 id 参数添加为 indexSpanWithAttr 这个 span 的属性,代码如下所示:
// src/main/java/com/youdianzhishi/orderservice/controller/IndexController.javapackage com.youdianzhishi.orderservice.controller;// ......import io.opentelemetry.instrumentation.annotations.WithSpan;import io.opentelemetry.instrumentation.annotations.SpanAttribute;@RestController@RequestMapping("/")public class IndexController {    @GetMapping    @WithSpan("indexSpan")    public ResponseEntity<String> home(HttpServletRequest request) {        return new ResponseEntity<>("Hello OpenTelemetry!", HttpStatus.OK);    }    @GetMapping("/{id}")    @WithSpan("indexSpanWithAttr")    public ResponseEntity<String> fetchId(@SpanAttribute("id") @PathVariable Long id) {        return new ResponseEntity<>("Hello OpenTelemetry:" + id, HttpStatus.OK);    }}然后我们重建镜像,重新启动容器,当我们访问 http://localhost:8081/123 的时候就可以看到 Jaeger UI 中多了一个 indexSpanWithAttr 的 span 了,并且该 span 的属性中包含了我们传递的 id 参数 。


推荐阅读