Wire Spring Boot 3.x tracing into Jujing in ten minutes using Micrometer Tracing and an OpenTelemetry Collector. Includes dependencies, config, Collector setup, custom spans, and four common pitfalls.
Three things are enough: a Spring Boot 3.x app (3.2+ ships Micrometer Tracing, which saves half the setup), an OpenTelemetry Collector (run one in Docker to receive and forward traces to Jujing), and your Jujing endpoint and token.
Add two dependencies to Maven:
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-tracing-bridge-otel</artifactId>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-exporter-otlp</artifactId>
</dependency>
Spring Boot 3.2+ auto-configures tracing through the actuator, so you don't instantiate a Tracer by hand or write span-export logic yourself.
spring:
application:
name: order-service
management:
tracing:
sampling:
probability: 1.0
otlp:
tracing:
endpoint: http://localhost:4318/v1/traces
spring.application.name becomes the service.name automatically, which is what you filter by when debugging. probability: 1.0 means 100% sampling — fine locally, but drop it to 0.1–0.3 in production. The endpoint points at the Collector's HTTP port 4318.
otel-collector-config.yaml:
receivers:
otlp:
protocols:
http:
endpoint: 0.0.0.0:4318
exporters:
otlphttp:
endpoint: https://ob.jjhub.cn/v1/traces
headers:
Authorization: Bearer <token>
service:
pipelines:
traces:
receivers: [otlp]
exporters: [otlphttp]
Start it: docker run -v $PWD/otel-collector-config.yaml:/etc/otelcol/config.yaml otel/opentelemetry-collector-contrib
Hit your endpoints a few times, open the Trace list in Jujing, filter by service.name, and you'll see the full call chain. Click a span to inspect its duration, status code, and custom attributes.
Framework instrumentation covers HTTP, databases, and messaging, but business-critical steps need manual spans. Inject the Tracer and wrap key methods like placing an order or deducting inventory:
Span span = tracer.nextSpan().name("place_order").start();
try (var scope = tracer.withSpan(span)) {
span.setTag("txn_id", txnId);
// business logic
} finally {
span.end();
}
In production, offload sampling to the Collector with tail-based sampling: keep every trace slower than 500ms or with errors, sample the rest by ratio. That protects storage without missing the traces that matter.