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

Onboarding with OpenTelemetry Collector: Logs, Metrics and Traces in One Config

Use OpenTelemetry Collector as a unified ingestion gateway to send logs, metrics and traces to Observe in one shot. Includes a full collector.yaml, app-side changes, verification steps and common pitfalls.

Why use a Collector instead of sending straight from the app

If every application reports directly to the backend, every configuration change means touching every app. A team running Java, Go and Python side by side ends up maintaining SDK configuration in three places, with three sets of credentials, and the cost grows with every new service. OpenTelemetry Collector is a standalone gateway that inverts this: it accepts OTLP data from all languages over gRPC or HTTP, applies filtering, redaction, batching and rate-limiting in one place, then forwards everything to the backend. Applications only need to know one address — the Collector.

There is a second benefit that matters in practice. When you want to change the backend endpoint, rotate the token, or add a redaction rule for sensitive fields, you change the Collector once instead of redeploying every service. In a fast-moving team, that is the difference between a five-minute change and a week of rollout tickets.

Before you start, gather three things: an Observe account with an ingestion token (create it under Service Management), network reachability from the Collector host to the backend over HTTPS, and at least one application already instrumented with the OpenTelemetry SDKs. If you are starting from zero instrumentation, add the SDK to a single service first and get traces flowing end to end before rolling out to the rest — it makes the onboarding loop much faster than instrumenting everything at once.

Step 1: Download and start the Collector

curl -LO https://github.com/open-telemetry/opentelemetry-collector-releases/releases/download/v0.100.0/otelcol-contrib_0.100.0_linux_amd64.tar.gz
tar xzf otelcol-contrib_0.100.0_linux_amd64.tar.gz
./otelcol-contrib --config collector.yaml

In production, run it under systemd or a container supervisor so it restarts automatically when it crashes.

Step 2: Configure collector.yaml

receivers:
  otlp:
    protocols:
      grpc:
        endpoint: 0.0.0.0:4317
      http:
        endpoint: 0.0.0.0:4318

processors:
  memory_limiter:
    check_interval: 1s
    limit_mib: 512
  batch:
    timeout: 5s
    send_batch_size: 1024

exporters:
  otlphttp:
    endpoint: https://ob.jjhub.cn/otlp
    headers:
      Authorization: "Bearer <your-ingestion-token>"

service:
  pipelines:
    traces:
      receivers: [otlp]
      processors: [memory_limiter, batch]
      exporters: [otlphttp]
    metrics:
      receivers: [otlp]
      processors: [memory_limiter, batch]
      exporters: [otlphttp]
    logs:
      receivers: [otlp]
      processors: [memory_limiter, batch]
      exporters: [otlphttp]

The three pipelines handle traces, metrics and logs separately but share a single exporter, so one file covers all three signal types. The memory_limiter protects the Collector from OOM under bursts, and batch groups small spans into larger requests to cut network overhead.

Step 3: Change one address on the app side

Whatever the language, point the OTLP exporter at the Collector's 4317 (gRPC) or 4318 (HTTP) and you are connected. In Go:

import "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"

exporter, _ := otlptracegrpc.New(ctx,
    otlptracegrpc.WithEndpoint("collector:4317"),
    otlptracegrpc.WithInsecure())

Java and Python work the same way — swap the endpoint to the Collector address. The backend URL and token now live in exactly one place: the Collector config. Rotating a credential or moving the backend no longer requires redeploying every service.

Step 4: Verify all three signal types arrive

Open the Traces, Metrics and Logs pages in the Observe console and confirm all three appear for the same service. Then test the correlation that matters most: find a log line carrying a trace id and click it — it should open the matching trace. If it does not, the logs are not correlated; go back to the application and check that span context is being injected into log output.

Run a quick three-point check: send one request and confirm a new trace appears within seconds; confirm the service name is the one you configured, not a default; and confirm timestamps look right with no timezone shift.

Common pitfalls

  • Out of memory: add memory_limiter first. Under a traffic burst the Collector will OOM before the backend does if you skip it.
  • Plaintext transport: use https in production. The token in the Authorization header must never cross the public internet in cleartext.
  • Missing batch: batch only takes effect when listed inside a pipeline. Omit it and every span or log line triggers its own network call, hurting both latency and throughput.
  • Timezone mismatch: keep the app, the Collector and the backend on the same timezone, or all timestamps will be shifted by a fixed offset.
  • gRPC vs HTTP confusion: make sure the exporter protocol (gRPC 4317 / HTTP 4318) matches the receiver you configured on the Collector.

Once this is working, the Collector becomes the single place to add redaction rules for secrets, PII filters and sampling decisions before any data reaches storage.