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

Get Your First Trace in 5 Minutes with OpenTelemetry

A copy-paste path from deploying the OpenTelemetry Collector to instrumenting your app and exporting to Jujing OBSERVE. Includes Java/Go snippets, verification steps, common errors, and a checklist — follow it and you get your first trace.

Before you start

Pin down three things first: what language your app is written in, where it runs, and the Jujing OBSERVE endpoint. OBSERVE supports both OTLP/HTTP and OTLP/gRPC, and there are official SDKs for Java, Go, Python, and Node.js. This guide uses a Java app with OTLP/gRPC; other languages only swap the dependency and the init code.

Step 1: Deploy the Collector

Don't point your app straight at the backend. Put an OpenTelemetry Collector in between — it handles receiving, batching, retrying, and exporting, so your app only talks to a local Collector.

receivers:
  otlp:
    protocols:
      grpc:
        endpoint: 0.0.0.0:4317
      http:
        endpoint: 0.0.0.0:4318
exporters:
  otlphttp:
    endpoint: https://ob.jjhub.cn/otlp/v1
    headers:
      Authorization: Bearer ${OBSERVE_TOKEN}
service:
  pipelines:
    traces:
      receivers: [otlp]
      exporters: [otlphttp]

The key detail: the exporter carries the OBSERVE token, so the app never knows the backend address. That decoupling means switching backends later only touches the Collector, never the app.

Step 2: Instrument the app

For Java, use the OpenTelemetry Agent for zero-code injection — one JVM flag at startup:

java -javaagent:opentelemetry-javaagent.jar \
  -Dotel.exporter.otlp.endpoint=http://localhost:4317 \
  -Dotel.service.name=order-service \
  -Dotel.traces.exporter=otlp \
  -jar app.jar

Go needs the SDK wired in by hand; the three core lines are:

exp, _ := otlptracegrpc.New(ctx,
    otlptracegrpc.WithEndpoint("localhost:4317"),
    otlptracegrpc.WithInsecure())

Python and Node.js are the same shape: install the matching SDK, point it at the same OTLP endpoint, and set service.name.

Step 3: Verify the trace

Send one real request, wait 30 seconds, then filter by service.name on the OBSERVE trace page. If you see the request, you are done. If not, troubleshoot in this order:

  1. Check the Collector log for Exporting lines. If absent, the app never reached the Collector — check the port and network.
  2. If exporting happens but the backend shows nothing, check whether the token expired or the endpoint is wrong.
  3. If the trace exists but has few spans, the SDK probably didn't propagate upstream context — check whether the HTTP client uses a propagation-aware interceptor.

Common pitfalls

  • Time zones. Span timestamps are UTC; the UI renders in the browser's zone. Don't hand-adjust offsets in your queries.
  • Sampling. Default head-based sampling at 100% balloons traffic. In production, use tail-based sampling or sample by error rate.
  • Inconsistent service.name. Every instance of a service must share one service.name, or traces get split and you never see a complete call chain.
  • Version mixing. Keep the SDK and Collector on the same major version; protocol incompatibilities do surface across versions.

Recommendations

Get it working in staging before production. Run at a low sampling rate for a week, confirm span volume, storage growth, and query latency all look sane, then raise it gradually. When it comes to instrumentation, working beats exhaustive — one real trace is worth more than a pile of empty spans.