Wire a Spring Boot app into OBSERVE tracing with zero code changes using the Java Agent, including JVM flags, Logback MDC correlation with trace_id, and common pitfalls.
otel.example.com:4317)No business code changes are required — this is done through the Java Agent's automatic instrumentation. The Agent weaves instrumentation in at class-load time and covers HTTP clients, database drivers, message queues, Spring MVC, and other common components out of the box. That's the point of choosing the Agent path over manual SDK integration: you get spans across frameworks without touching a single source file.
Grab opentelemetry-javaagent.jar from the official OpenTelemetry releases page and place it in a fixed directory on the app machine, such as /opt/otel/. Pin the version; don't chase the latest release in production. Before upgrading, run a round in staging to confirm the propagation format stays compatible downstream. The Agent jar is self-contained, so there is nothing to install — you just reference its path.
Add the following to the JVM startup arguments:
java -javaagent:/opt/otel/opentelemetry-javaagent.jar -Dotel.service.name=order-service -Dotel.exporter.otlp.endpoint=http://otel.example.com:4317 -Dotel.traces.exporter=otlp -Dotel.metrics.exporter=otlp -Dotel.logs.exporter=otlp -Dotel.propagators=tracecontext,baggage -jar app.jar
What each flag does:
otel.service.name: the name you'll see in OBSERVE; it must be globally unique and should match the service name in your registry;otel.exporter.otlp.endpoint: the OBSERVE collection gateway;otel.propagators: the propagation format, tracecontext is fine by default and is what carries context across services.In production, fold these flags into a shared startup script or the environment block of your Kubernetes Deployment. That keeps service names and sampling rates consistent instead of letting each service drift on its own — inconsistent names are the quickest way to make trace queries useless across a fleet.
The link between traces and logs lives in your log output. With Logback, inject the MDC fields into the pattern in logback.xml:
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} %-5level [%X{trace_id}] [%X{span_id}] %logger{36} - %msg%n</pattern>
</encoder>
</appender>
The Agent injects trace_id and span_id into the MDC automatically, so those two fields show up in every log line and OBSERVE can correlate them with traces once collected. If your logs already use JSON output, add those two fields to the JSON too — otherwise the correlation breaks silently and you'll wonder why "jump to logs" returns nothing.
Send a request, then search the trace query page in OBSERVE with service.name = order-service. If you see Spans, it's working. Open any Span and you should find the logs it produced; conversely, clicking a trace_id in the log view takes you back to the full call chain.
It's worth running a short load test afterward to confirm Span volume, sampling ratio, and error rate all match expectations — otherwise it's easy to end up "looks connected, but a lot of data is silently dropped."
-Dotel.traces.sampler=parentbased_traceidratio with -Dotel.traces.sampler.arg=0.1 to sample 10% and avoid blowing up storage;traceparent header;OTEL_BSP_* batch settings so the export queue doesn't pile up without bound.Once traces flow, the natural next step is adding business attributes. Drop order_id or user_id into Spans as custom attributes so you can search traces by business key rather than by service name alone. That's what turns tracing from a debugging tool into something support can actually use during an incident.
Once data is flowing, here's what changes day to day. A support ticket says "order 102345 timed out." Instead of asking which service to look at, you paste the order ID into the trace search, open the single trace that spans gateway → accounting → risk, and the flame graph highlights that risk-control's database call took 2.8 seconds. You click that Span, the log panel shows the exact SQL and that the connection pool was exhausted, and you hand the fix to the right team. That path — business key to trace to span to log — is the whole reason we emphasized the MDC correlation step earlier. Skip it, and traces are just a pretty picture with no way to act on them.