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

Onboarding with OpenTelemetry in 5 Minutes: From Collector to Full Tracing

A step-by-step walkthrough for sending traces, metrics, and logs to OBSERVE through the OpenTelemetry Collector, including collector config, Java auto-instrumentation flags, sampling setup, and verification—full traces with no code changes.

Prerequisites

You need an OBSERVE tenant, its gateway address, and an access token. This guide assumes Linux + Docker and Java / Go microservices. Onboarding has three steps: deploy a Collector as the single ingestion point, send data from your services, then verify the trace.

Deploy the Collector

Run one OpenTelemetry Collector that receives traces / metrics / logs from every service and forwards them to OBSERVE. Start it with docker-compose:

otel-collector:
  image: otel/opentelemetry-collector-contrib:0.102.0
  volumes:
    - ./otel-collector-config.yaml:/etc/otelcol/config.yaml
  ports:
    - "4317:4317"   # OTLP gRPC
    - "4318:4318"   # OTLP HTTP
    - "8889:8889"   # Prometheus scrape

The config's key parts are the exporter and the pipelines:

receivers:
  otlp:
    protocols: { grpc: {}, http: {} }
  prometheus:
    config:
      scrape_configs:
        - job_name: 'otel-collector'
          scrape_interval: 15s
          static_configs: [{ targets: ['localhost:8888'] }]
exporters:
  otlp/jjhub:
    endpoint: "obs-gateway.jjhub.cn:4317"
    headers: { authorization: "Bearer <TOKEN>" }
service:
  pipelines:
    traces:  { receivers: [otlp], exporters: [otlp/jjhub] }
    metrics: { receivers: [otlp, prometheus], exporters: [otlp/jjhub] }
    logs:    { receivers: [otlp], exporters: [otlp/jjhub] }

Instrument your services

The fastest path with no code changes is auto-instrumentation. For Java, add the javaagent at startup:

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

For Go, instrument manually with otelhttp and otelgrpc, or use eBPF agentless collection on legacy systems you can't instrument (see the v2.6.0 release notes). In all cases set service.name to a globally unique value—otherwise traces and metrics from different services get mixed together.

Sampling setup

Collecting 100% of everything isn't realistic in production: under load, both the Collector and storage get saturated. By default, add a tail_sampling or probabilistic_sampling processor in the Collector and keep only slow and failed requests:

processors:
  probabilistic_sampler:
    sampling_percentage: 10
  tail_sampling:
    policies:
      - name: slow
        type: latency
        latency: { threshold_ms: 500 }
      - name: errors
        type: status_code
        status_code: { status_codes: [ERROR] }

Slow requests and errors are kept at 100%, normal requests are sampled at 10%—you keep the full traces you need for troubleshooting while controlling storage cost. Tune the sampling policy gradually: run full collection for a day to see the volume, then tighten.

The Collector is also your single place to attach batching and retries, so a brief network blip between your services and OBSERVE doesn't silently drop data. Add a batch processor and a retry-on-failure queue on the exporter:

processors:
  batch:
    send_batch_size: 512
    timeout: 1s
exporters:
  otlp/jjhub:
    retry_on_failure:
      enabled: true
      initial_interval: 2s
      max_elapsed_time: 60s

For a Go service, instrument an HTTP handler in a few lines using the otelhttp wrapper:

import (
    "net/http"
    "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
)

http.Handle("/api/order", otelhttp.NewHandler(orderHandler, "place-order"))

The wrapper starts a span per request, records status and latency, and propagates the trace context to downstream calls automatically—no manual span plumbing in your handlers.

Verify the trace

  1. Trigger a real business request.
  2. In OBSERVE's Tracing view, filter by service.name and you should see a complete trace with per-span latency, status codes, and error details.
  3. Open the Metrics view and confirm metrics are flowing, with names prefixed by otel..
  4. In Logs, search by traceId to confirm logs are correlated with spans—clicking a log should jump back to its span.

Common problems

  • No data: run curl -v http://localhost:4318 to check the port, then read the collector logs for export errors—usually a wrong token or endpoint.
  • Broken traces: make sure every service uses the same propagator (W3C tracecontext by default); don't mix in b3.
  • Misaligned timelines: standardize on UTC or configure one local timezone everywhere—mismatched zones between collector and UI break the trace timeline.
  • Missing resource attributes: tag every service with resource attributes like deployment.environment and service.version so you can filter by environment instead of cramming everything into production.

Finally, pin the javaagent and Collector image versions instead of using latest. Auto-instrumentation and Collector releases move fast, and a silent upgrade can change sampling behavior or drop a field you depend on. Version-pinning is cheap insurance for an observability pipeline that has to be boringly reliable. After your first trace shows up, export it and walk it span by span against the code—if any hop is missing, that's almost always a missing propagator or an un-instrumented HTTP client, both easy to fix now and painful to find later.