The problem showed up on every engagement
Observability keeps turning into five separate integrations, wired by hand, per service. Correlation IDs get invented per-team and propagate inconsistently across HTTP, Kafka, and async boundaries. Sensitive fields — passwords, tokens, PANs, SSNs — leak into logs because masking isn't standardized. Traces stop dead at the Kafka broker, so a consumer's work is invisible to the producer's request. Slow queries get discovered in production instead of code review, because nobody's timing them. And every service reinvents its own dashboards, its own metric names, its own exception counters.
None of this is exotic. It's the same plumbing, rebuilt slightly differently, on every Spring Boot service we touched — usually after an incident forced the question rather than before.
The fix: one dependency, a few properties
Rather than write a bespoke observability layer for the next client, we assembled the pieces that were already battle-tested — OpenTelemetry, Micrometer, and Spring Kafka's own Observation support — and filled only the gaps they leave. The result is TraceFlow, a Spring Boot starter: add traceflow-spring-boot-starter, set an application name and an OTLP endpoint, and correlation IDs, structured JSON logs, and HTTP/JDBC/Kafka metrics are already active. No instrumentation code required.
Hexagonal by design
The module is layered so nothing depends sideways: traceflow-api holds the annotations, events, and SPI ports with zero Spring dependency; traceflow-core handles correlation-id and context propagation; a set of feature modules — tracing, metrics, logging, business, security, kafka, jdbc, web, health — each do exactly one job; autoconfigure binds properties and wires every module conditionally on classpath and flag; and spring-boot-starter is the single dependency an application actually adds. Every feature module depends only on the core, never on a sibling, so cross-module wiring lives in exactly one place and each module stays independently testable.
Twelve integration points, one starter
- Distributed tracing — OpenTelemetry spans across HTTP, JDBC, and Kafka, exported via OTLP.
- Metrics — Micrometer and Prometheus, with p50/p95/p99 histograms on every timed call.
- Structured logging — fixed-schema JSON carrying service, trace, span, and correlation id.
- Correlation IDs — auto-generated and propagated across HTTP, Kafka, and async boundaries.
- Business metrics — a single
@BusinessMetric("loan.approved")annotation produces a counter and a domain event. - Sensitive-data masking — passwords, tokens, PANs, SSNs, and JWTs masked in logs by default.
- Health, exception, HTTP, database, Kafka, and security monitoring — the checks Actuator doesn't ship, on by default.
It runs on standard, unglamorous infrastructure: Java 21, Spring Boot 3.5, OpenTelemetry, Micrometer, Prometheus, Grafana, Loki, Tempo, Spring Kafka, HikariCP, Logback, Testcontainers, and JUnit 5 — a single docker compose up stands up Grafana, Prometheus, Loki, and Tempo locally with nine dashboards pre-provisioned.
Proof, not a promise
An ApplicationContextRunner integration test that loads every auto-configuration class together caught two real bugs unit tests missed: the traceflow.enabled master switch wasn't cascading to feature flags, and a Spring Security-backed current-user resolver was silently losing to its own no-op default because of bean-registration order. Both are fixed and now regression-tested — part of a suite of 130+ tests holding an 80% line-coverage gate across all 13 modules.
The dependency that pays for itself is the one you stop rebuilding for the sixth service.
What we'd tell a team starting this today
- Assemble already-proven observability primitives (OpenTelemetry, Micrometer) instead of writing your own — the gaps worth filling are narrower than they look.
- Keep feature modules dependent only on a shared core, never on each other, so the module set stays independently testable as it grows.
- Write the integration test that boots every auto-configuration together before you trust unit tests alone — that's where the real wiring bugs hide.
Standardizing observability before an agent goes near a production system is exactly the groundwork we cover in monitoring and fail-safes for agentic systems, or talk to us about the plumbing your own services keep rebuilding.
