Files
spring-boot-demo/observability/docs/output/03-observed-needs-explicit-bean.txt
T
Claude 03bdf7ee87 Add observability: real OTLP metrics/traces to grafana/otel-lgtm, Docker Compose auto-wiring, and a dual-version (Boot 4.0 vs 4.1) proof of the new OTEL_* env var support
Companion module for the rewritten ankurm.com Prometheus/Grafana monitoring post. Verified
against a real running grafana/otel-lgtm container (not mocked): 8 real requests produce a real
orders_placed_total metric queried back from the bundled Prometheus-compatible API with zero
management.otlp.* properties, auto-wired entirely by Boot's Docker Compose service-connection
detection. Two real findings surfaced along the way and documented rather than smoothed over:
@Observed silently produces no span without an explicit ObservedAspect bean (AspectJ weaving
alone is not sufficient, despite Micrometer Tracing being active), and OTEL_EXPORTER_OTLP_ENDPOINT
already worked on Boot 4.0 via Micrometer's own OtlpConfig fallback -- what's actually new in 4.1
is the rest of the standard OTEL_* surface (verified with OTEL_METRIC_EXPORT_INTERVAL against
identical source compiled on both Boot 4.0.8 and 4.1.1).

Also fixes the root README's module table, which was missing a row for
resilience4j-circuit-breaker (added in a previous commit but never indexed here).
2026-09-18 09:32:34 +00:00

33 lines
1.7 KiB
Plaintext

OrderController#placeOrder is annotated @Observed(name = "place-order", contextualName =
"order-controller#placeOrder"). Before ObservationConfig (an explicit ObservedAspect @Bean)
existed in this repo, spring-boot-starter-opentelemetry, spring-boot-starter-aspectj (AspectJ
weaver on the classpath) and micrometer-tracing were ALL already present and active -- and the
annotation still did nothing. Real trace, fetched straight from Tempo's query API, before the fix:
$ curl -s "http://localhost:3200/api/traces/<trace-id>"
span: http post /orders/{id} | kind: SPAN_KIND_SERVER | parent: (root)
# one span. @Observed's child span never appears.
After adding:
@Configuration(proxyBeanMethods = false)
class ObservationConfig {
@Bean
ObservedAspect observedAspect(ObservationRegistry registry) {
return new ObservedAspect(registry);
}
}
Same annotation, same request, new trace:
$ curl -s "http://localhost:3200/api/traces/<trace-id>"
span: order-controller#placeOrder | kind: SPAN_KIND_INTERNAL | parent: <server-span-id>
span: http post /orders/{id} | kind: SPAN_KIND_SERVER | parent: (root)
# two spans. The @Observed child span now nests correctly under the HTTP server span.
Spring Boot's autoconfiguration wires an ObservationRegistry bean for you the moment Micrometer
Tracing is on the classpath -- it does NOT also register an ObservedAspect. AspectJ weaving
being present is necessary but not sufficient; without the aspect bean there is nothing for the
weaver to apply. This is easy to miss because the app starts cleanly, the HTTP server span still
shows up, and nothing logs a warning -- the method-level span is just silently absent.