bigywater.tech
Spring · 86

Observation API:一个注解同时得到指标与链路

Observation API 到底是什么?和直接用 MeterRegistry、Tracer 有什么区别?@Observed 能得到什么?标签应该放指标里还是 span 里?采样会不会影响指标?这篇在 Spring Boot 4.0.8 加 Brave 上,用自己收集的 span 逐项验证。

1 次观察 → 指标 + span
GET /work 一次请求产生 http.server.requests 指标和 2 个 span,日志自动带 traceId
3 个 orderId / 0 个标签
高基数标签 orderId 在 span 里有 3 个不同取值,指标标签里一个都没有
10 / 100 / 0
默认采样、probability=1.0、probability=0.0 时 100 个请求保留的 span 数

一次观察两份产出

实测 · 本机执行输出
  GET /work → traceId=6ad6de2363b09c4c3a40e9769a75e650
  日志行(Boot 默认格式里多了关联 id):INFO 47388 --- [demo] [nio-9602-exec-2] [6ad6de2363b09c4c3a40e9769a75e650-3a40e9769a75e650] demo.Main                                : 处理 /work
  收集到的 span 2 个:
    svc-call|trace=…|parent=有|{class=demo.Svc, layer=service, method=call}
    http get /work|trace=…|parent=-|{exception=none, http.url=/work, method=GET, outcome=SUCCESS, status=200, uri=/work}
  指标 http.server.requests?tag=uri:/work:COUNT 1,标签 {'exception': ['none'], 'method': ['GET'], 'error': ['none'], 'outcome': ['SUCCESS'], 'status': ['200']}

HTTP 请求同时得到指标和链路;日志默认格式自动带 traceId 与 spanId。

高低基数标签

实测 · 本机执行输出
  指标 order.process:COUNT 3,标签 {'type': ['a', 'b'], 'error': ['none']}
  span 个数 3,每个 span 的标签:
    order.process|trace=…|parent=有|{orderId=30bb2f59, type=a}
    order.process|trace=…|parent=有|{orderId=607e3226, type=a}
    order.process|trace=…|parent=有|{orderId=bc3483bd, type=b}

低基数标签进指标和 span,高基数标签只进 span。

@Observed

实测 · 本机执行输出
  指标 svc.call:COUNT 2,标签 {'method': ['call'], 'error': ['none'], 'class': ['demo.Svc'], 'layer': ['service']}
  span svc-call 个数 2,第 1 个:svc-call|trace=…|parent=有|{class=demo.Svc, layer=service, method=call}
  全部 span 名字:['http get /actuator/metrics/{requiredMetricName}', 'http get /spans', 'http get /work', 'svc-call']

一个注解得到一个 Timer 指标和一个 span,需要 ObservedAspect Bean。

采样与开关

实测 · 本机执行输出
  management.tracing.sampling.probability 不设(默认):/plain 的 span 10 个;http.server.requests?uri=/plain 的 COUNT 100
  probability=1.0:/plain 的 span 100 个;http.server.requests?uri=/plain 的 COUNT 100
  probability=0.0:/plain 的 span 0 个;http.server.requests?uri=/plain 的 COUNT 100
  probability=1.0 且 management.observations.enable.svc.call=false:/plain 的 span 100 个;http.server.requests?uri=/plain 的 COUNT 100;5 次 /work 之后 svc.call 指标 没有这个指标,svc-call 的 span 0 个,http get /work 的 span 5 个

默认采样率只留 10% 的 span,指标不受影响;按名字关闭观察时指标与 span 一起消失。

分步演示

Observation
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / OpenJDK 21.0.12(Homebrew) / Spring Boot 4.0.8(Spring Framework 7.0.9、Tomcat 11.0.24) / Spring Cloud 2025.1.3;用 javac 编译、java 直接运行,依赖由 Maven 从 Maven Central 解析;数字每次运行会有小幅抖动。被测应用是 spring-boot-starter-actuator、webmvc、aspectj 加 micrometer-tracing-bridge-brave 与 spring-boot-micrometer-tracing-brave 的单个程序,自己注册了一个 Brave 的 SpanHandler 把结束的 span 存进内存再通过接口读出来,没有接 Zipkin 或 OTLP;采样率除第四节外设为 1.0;第四节「默认」的 10 个是 100 个请求实际保留的数,没有分析采样器的种类
    • 没有验证:把 span 真正发到 Zipkin / OTLP / Tempo;OpenTelemetry 桥接(micrometer-tracing-bridge-otel);跨服务的 traceparent 传播(见微服务系列的链路追踪);响应式和异步线程里的上下文传播;ObservationFilter 与 ObservationConvention 的自定义;@Observed 在 private 方法或同类内调用时失效(AOP 通用限制,本篇没有测);观察对吞吐的开销
    京ICP备2026067502号-1京公网安备11010502063487号