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

Onboarding OpenTelemetry Tracing to Jujing OBSERVE in 10 Minutes

A copy-paste onboarding guide: install the OpenTelemetry SDK, point the exporter at Jujing's collector, configure sampling, and verify traces — with Java and Go config examples and common pitfalls.

Prerequisites

Before starting, confirm three things. First, network reachability: your service must be able to reach Jujing OBSERVE's collector endpoint — otel-collector.jjhub.cn:4317 for gRPC and 4318 for HTTP — from wherever it runs, whether that's a VM, a container, or Kubernetes. Second, a tenant access token, generated in the console under Access Management → Data Ingestion; it's what authenticates your telemetry. Third, use the latest stable SDK for your language; the OTLP exporter has moved fast, and older versions carry bugs around retries and batching. The examples below cover Java (Spring Boot) and Go, the two most common stacks, but the steps are identical elsewhere — only package names and initialization differ.

Step 1: Add the OpenTelemetry SDK

For Java, the least invasive path is the OpenTelemetry Java Agent: add the dependency-free JAR and change only your launch command, with no code changes required.

java -javaagent:opentelemetry-javaagent.jar   -Dotel.service.name=order-api   -Dotel.exporter.otlp.endpoint=http://otel-collector.jjhub.cn:4318   -Dotel.metrics.exporter=none   -jar order-api.jar

The agent auto-instruments your web framework, HTTP client, and database drivers, so you get spans for incoming requests, outgoing calls, and SQL statements without touching a line of code. If you need custom spans later — say, to wrap a slow batch job — add manual instrumentation on top. For Go, initialize a TracerProvider with the official SDK:

import (
    "go.opentelemetry.io/otel"
    "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
    "go.opentelemetry.io/otel/sdk/trace"
)

exp, _ := otlptracehttp.New(context.Background(),
    otlptracehttp.WithEndpoint("otel-collector.jjhub.cn:4318"),
    otlptracehttp.WithInsecure())
tp := trace.NewTracerProvider(trace.WithBatcher(exp))
otel.SetTracerProvider(tp)

The batcher accumulates spans and flushes them on an interval, which is far more efficient than sending every span individually. Make sure you also shut the provider down on exit (defer a Shutdown), or the last batch can be lost.

Step 2: Configure the export endpoint and auth

The export endpoint is the critical setting — get this one line wrong and nothing shows up. Three points matter. First, match protocol to port: 4317 is gRPC and 4318 is HTTP; don't mix them, and don't append a path like /v1/traces unless your collector explicitly requires it. Second, authentication: Jujing requires the access token in a request header. For the Java Agent use -Dotel.exporter.otlp.headers=Authorization=Bearer <token>; for Go use otlptracehttp.WithHeaders(map[string]string{"Authorization": "Bearer <token>"}). A missing token usually fails silently — the SDK retries, then drops — which is why "no data" is the symptom you'll see. Third, always set service.name; it's the unique identifier used in the console. Multiple replicas share one name and are told apart by host.name or an instance ID, so set those attributes too.

Step 3: Sampling strategy and verification

Collecting every trace in production is both unnecessary and expensive, so combine head-based and tail-based sampling. Use traceidratio at 10–20% by default, and force-keep error and slow requests. The Java Agent takes -Dotel.traces.sampler=traceidratio -Dotel.traces.sampler.arg=0.1; in Go, wrap the sampler with trace.ParentBased(trace.TraceIDRatioBased(0.1)). ParentBased is important: child spans inherit the parent's decision, so a sampled trace keeps all its spans and an unsampled one drops them consistently — you never get half a trace. For tail-based decisions (keep everything that turned out slow or failed), you'll want a tail-sampling processor in the collector rather than the SDK; that's a later step, but worth knowing it exists.

After wiring it up, send one test request, wait about 30 seconds for batching and flushing, then filter by service.name on the Tracing page. A full span waterfall with per-span duration and error markers means you're in. If you see nothing, check in order: the token (is it present and valid?), the endpoint (protocol/port mismatch, or a stray path?), and network reachability (can the container actually reach 4318?). The collector's receive logs will tell you quickly whether data is arriving at all — start there.

Two more things worth doing early. First, propagate trace IDs into your logs: configure your logging framework to emit the current traceId and spanId on each line, so you can jump from a slow span straight to its logs and back. Second, set a simple availability alert on span count per service — a sudden drop to zero is usually the first sign that an agent failed to start or a token got rotated. Both take minutes to set up and pay off the first time you debug a real incident.