← Back to blog
Guide 4 min read 炬鲸团队

Onboarding Guide: Send OpenTelemetry Traces to Torchwhale OBSERVE in 10 Minutes

A complete onboarding guide from zero to first trace: deploy the OpenTelemetry Collector, configure SDK export, instrument key paths, and verify in the UI, with Java code samples and the two pitfalls that trip most teams.

Send OpenTelemetry Traces to Torchwhale OBSERVE in 10 Minutes

This guide walks you through getting your first trace into the platform: deploy the Collector, configure the SDK, instrument your code, and see the first call chain in the UI. We use Java Spring Boot as the example, but the steps are identical for other languages.

Step 1: deploy the OpenTelemetry Collector

Pick a machine that can reach the platform and run the Collector with Docker:

# otel-collector-config.yaml
receivers:
  otlp:
    protocols:
      grpc: { endpoint: 0.0.0.0:4317 }
      http: { endpoint: 0.0.0.0:4318 }
exporters:
  otlp:
    endpoint: "ob.jjhub.cn:4317"
    headers:
      authorization: "Bearer <your-access-token>"
service:
  pipelines:
    traces:
      receivers: [otlp]
      exporters: [otlp]

Generate the access token under "Access Management → OpenTelemetry", then confirm the Collector starts without errors in its logs before moving on. If your internal network cannot reach the platform directly, insert another Collector in the middle as a forwarder — the config stays the same, you only change the endpoint.

A quick sanity check is to confirm the Collector can reach the platform before you touch any application code. This isolates the network path from the app, so when traces do not appear later you know which half of the pipeline to debug.

Step 2: add the SDK and set export options

Add the dependency to pom.xml:

<dependency>
  <groupId>io.opentelemetry</groupId>
  <artifactId>opentelemetry-sdk</artifactId>
</dependency>

Point the SDK at your Collector with environment variables — no code changes are needed for export:

OTEL_EXPORTER_OTLP_ENDPOINT=http://<collector-host>:4318
OTEL_SERVICE_NAME=order-svc

Setting OTEL_SERVICE_NAME explicitly matters: it becomes the identity of the service in every trace, and inconsistent names across deployments are the most common reason traces appear broken. The SDK batches and exports traces asynchronously, so a few seconds of delay before a trace appears in the UI is normal.

Step 3: instrument the paths that matter

Auto-instrumentation covers HTTP, databases, and message queues out of the box. Add manual spans around the business methods that matter most:

Span span = tracer.spanBuilder("checkout")
    .setAttribute("order_id", orderId)
    .startSpan();
try (Scope scope = span.makeCurrent()) {
    // business logic
} finally {
    span.end();
}

Name spans after the operation, not the class, so the trace reads like a story rather than a stack trace. Attach the business identifiers you will actually search for later — an order ID, a user ID, a tenant — as span attributes now, not after the incident. Alternatively, attach the OpenTelemetry Java agent with -javaagent:opentelemetry-javaagent.jar, which auto-instruments most frameworks without source changes; you only need manual spans for your own business logic.

Step 4: verify in the platform

Make a request, then open "Tracing → Search" and filter by service. You should see the full call tree, each span's duration, and its attributes. If the trace is correlated with logs, clicking a span jumps straight to the matching log lines.

Next step: correlate logs with traces

Once traces are flowing, the highest-value follow-up is linking them to logs. Inject the current trace_id into your log lines — most logging libraries do this through MDC or structured logging — and the platform links each span to its logs automatically. From then on, a slow request is one click away from the exact log lines that explain it. If you run several services, keep a single shared Collector: one instance can serve a whole cluster and gives you one place to manage sampling and export credentials. On Kubernetes, prefer the OpenTelemetry Operator or a Collector sidecar so each pod exports to a local Collector instead of reaching across the network directly.

Troubleshooting when nothing shows up

If the platform stays empty, check in this order: confirm the Collector can reach the platform, confirm the app can reach the Collector, and confirm the token is correct and not expired. Nine times out of ten, the problem is a network route or a stale token, not the code.

Two pitfalls worth avoiding up front: inconsistent service names break the trace, so standardize on OTEL_SERVICE_NAME; and a sampling rate that is too high floods storage, so start at 10% and raise it only when you need the detail.