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.
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.
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.
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.
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.
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.
memory_limiter first. Under a traffic burst the Collector will OOM before the backend does if you skip it.https in production. The token in the Authorization header must never cross the public internet in cleartext.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.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.