外观
Spring Boot接入OpenTelemetry可观测零侵入
来源:语雀原文 | 整理日期:2026-09-22
理论基础:




展示:

启动类:

接口:

配置启动jar

运行提示信息:

Jagger链路效果:

点击计入

搜索traceid进入

prometheus效果

图表:

详细代码
我将使用相同的基准应用程序:一个用 Kotlin 编写的简单 Spring Boot 应用程序。它提供一个端点。
- 端点背后的函数名为
entry() - 它调用另一个名为
intermediate()的函数 - 后者使用
WebClient实例,替换RestTemplate,来调用上面的端点 - 为了避免无限循环,我传递了一个自定义请求头:如果
entry()函数找到它,它转化为以下代码:
javascript
@SpringBootApplication
class Agent1xApplication
@RestController
class MicrometerController {
private val logger = LoggerFactory.getLogger(MicrometerController::class.java)
@GetMapping("/{message}")
fun entry(@PathVariable message: String, @RequestHeader("X-done") done: String?) {
logger.info("entry: $message")
if (done == null) intermediate()
}
fun intermediate() {
logger.info("intermediate")
RestClient.builder()
.baseUrl("http://localhost:8080/done")
.build()
.get()
.header("X-done", "true")
.retrieve()
.toBodilessEntity()
}
}对于每种设置,我将检查两个阶段:启用 OpenTelemetry 的主要阶段,以及创建额外内部跨度的自定义阶段。
Micrometer Tracing
Micrometer Tracing 源于 Micrometer,一个“供应商中立的应用程序可观测性门面”。
Micrometer Tracing 为最流行的跟踪库提供了一个简单的门面,让您可以在没有供应商锁定的情况下对基于 JVM 的应用程序代码进行检测。它旨在为您的跟踪收集活动增加很少或没有开销,同时最大限度地提高跟踪工作的可移植性。 — Micrometer Tracing site
要开始使用 Micrometer Tracing,需要添加一些依赖项:
- Spring Boot Actuator,
org.springframework.boot:spring-boot-starter-actuator - Micrometer Tracing 本身,
io.micrometer:micrometer-tracing - 到目标跟踪后端 API 的“桥梁”。在我的例子中,它是 OpenTelemetry,因此
io.micrometer:micrometer-tracing-bridge-otel - 到后端的具体导出器,
io.opentelemetry:opentelemetry-exporter-otlp
我们不需要 BOM,因为版本已经在 Spring Boot 父级中定义。
但是,我们需要两个运行时配置参数:跟踪应该发送到哪里,以及组件的名称是什么。它们由 MANAGEMENT_OTLP_TRACING_ENDPOINT 和 SPRING_APPLICATION_NAME 变量控制。
javascript
services:
jaeger:
image: jaegertracing/all-in-one:1.55
environment:
- COLLECTOR_OTLP_ENABLED=true
ports:
- "16686:16686"
micrometer-tracing:
build:
dockerfile: Dockerfile-micrometer
environment:
MANAGEMENT_OTLP_TRACING_ENDPOINT: http://jaeger:4318/v1/traces
SPRING_APPLICATION_NAME: micrometer-tracing- 启用 Jaeger 的 OpenTelemetry 收集器
- Jaeger OpenTelemetry gRPC 端点的完整 URL
- 设置 OpenTelemetry 的服务名称
以下是结果:

在没有任何自定义的情况下,Micrometer 在接收和发送 HTTP 请求时会创建跨度。
框架需要将魔法注入到 RestClient 中以进行发送。我们必须让前者实例化后者才能做到这一点:
javascript
@SpringBootApplication
class MicrometerTracingApplication {
@Bean
fun restClient(builder: RestClient.Builder) =
builder.baseUrl("http://localhost:8080/done").build()
}我们可以通过多种方式创建手动跨度,其中一种是通过 OpenTelemetry API 本身。但是,设置需要大量的样板代码。最直接的方法是 Micrometer 的 Observation API。它的主要好处是使用单个 API 来管理 指标 和 跟踪。
以下是更新后的代码:
javascript
class MicrometerController(
private val restClient: RestClient,
private val registry: ObservationRegistry
) {
@GetMapping("/{message}")
fun entry(@PathVariable message: String, @RequestHeader("X-done") done: String?) {
logger.info("entry: $message")
val observation = Observation.start("entry", registry)
if (done == null) intermediate(observation)
observation.stop()
}
fun intermediate(parent: Observation) {
logger.info("intermediate")
val observation = Observation.createNotStarted("intermediate", registry)
.parentObservation(parent)
.start()
restClient.get()
.header("X-done", "true")
.retrieve()
.toBodilessEntity()
observation.stop()
}
}添加的观察调用反映在生成的跟踪中:

OpenTelemetry 代理 v1
Micrometer Tracing 的替代方案是通用的 OpenTelemetry Java Agent。 其主要优势在于它既不影响代码也不影响开发人员; 该代理纯粹是运行时范围内的关注点。
javascript
java -javaagent:opentelemetry-javaagent.jar agent-one-1.0-SNAPSHOT.jar该代理遵守 OpenTelemetry 的环境变量配置:
javascript
services:
agent-1x:
build:
dockerfile: Dockerfile-agent1
environment:
OTEL_EXPORTER_OTLP_ENDPOINT: http://jaeger:4317
OTEL_RESOURCE_ATTRIBUTES: service.name=agent-1x
OTEL_METRICS_EXPORTER: none
OTEL_LOGS_EXPORTER: none
ports:
- "8081:8080"- 设置协议、域名和端口。库附加
/v1/traces - 设置 OpenTelemetry 的服务名称
- 不导出指标或日志
无需更多配置,我们就可以获得以下跟踪:

该代理会自动跟踪接收和发送的请求,以及使用 Spring 相关注释标记的函数。跟踪根据调用堆栈正确地嵌套在彼此内部。要跟踪其他函数,我们需要在代码库中添加一个依赖项,io.opentelemetry.instrumentation:opentelemetry-instrumentation-annotations 。我们现在可以使用 @WithSpan 注释来注释以前未跟踪的函数。
value() 部分控制跟踪的标签,而 kind 则转换为 span.kind 属性。如果将值设置为空字符串(默认值),则它会输出函数的名称。就我而言,默认值就足够了。
javascript
@WithSpan
fun intermediate() {
logger.info("intermediate")
RestClient.builder()
.baseUrl("http://localhost:8080/done")
.build()
.get()
.header("X-done", "true")
.retrieve()
.toBodilessEntity()
}它会生成预期的新的 intermediate() 跟踪:

OpenTelemetry Agent v2
OpenTelemetry 在今年 1 月发布了代理的新主要版本。我用它更新了我的演示;现在只有在应用程序接收和发送请求时才会创建跟踪。

与之前的版本一样,我们可以使用 @WithSpan 注释添加跟踪。唯一的区别是,我们还必须注释 entry()函数。它默认情况下不会被跟踪。
