GuidesOpenTelemetry Collector
OpenTelemetry Collector setup and configuration
The short answer: run the otel/opentelemetry-collector-contrib image with a config.yaml that has an otlp receiver, the memory_limiter and batch processors, and an otlphttp exporter pointed at your backend. Then point your applications at the Collector on port 4317 (gRPC) or 4318 (HTTP). This guide explains each part, gives a configuration you can copy, and shows how to check that data is flowing.
OpenTelemetry and OTLP in one minute
OpenTelemetry is an open standard and a set of libraries for producing traces, metrics and logs. You instrument your code once, with an SDK for your language, and you can send the data to any backend that accepts it.
OTLP (the OpenTelemetry Protocol) is the wire format. It runs over gRPC, usually on port 4317, or over HTTP, usually on port 4318, with paths /v1/traces, /v1/metrics and /v1/logs. Most observability backends accept OTLP directly.
SDK direct export or a Collector?
You have two choices. An SDK can export straight to your backend, or it can export to a Collector that you run, which then forwards the data.
| SDK direct export | Through a Collector | |
|---|---|---|
| Setup | Set a few environment variables | Run and maintain one more component |
| Credentials | Every service holds the backend token | Only the Collector holds it |
| Processing | Limited to what the SDK offers | Filter, redact, enrich and sample centrally |
| Retries and buffering | Inside each application process | Moved out of the application |
| Changing backend | Redeploy every service | Change one file |
Direct export is fine for a few services. A Collector pays off when you have many services, several languages, or rules you want to apply in one place.
How the Collector is built
The Collector is a single binary configured by one YAML file. The file has four main sections.
- Receivers take data in. The
otlpreceiver accepts OTLP from SDKs. Others scrape Prometheus endpoints, read log files or collect host metrics. - Processors change data in transit: batching, memory protection, adding or removing attributes, filtering and sampling.
- Exporters send data out, for example
otlphttporotlp(gRPC) to a backend, ordebugto the Collector's own log. - Pipelines, under
service, connect them. Each pipeline handles one signal (traces, metrics or logs) and lists its receivers, processors in order, and exporters.
A component does nothing until a pipeline uses it. Defining an exporter and forgetting to add it to a pipeline is a common reason why no data arrives.
There are two distributions. The core image contains a small set of components. The contrib image adds many more receivers, processors and exporters, and is what most teams use.
A working config.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: 400
spike_limit_mib: 100
batch:
send_batch_size: 1000
send_batch_max_size: 2000
timeout: 5s
exporters:
otlphttp/backend:
endpoint: https://otlp.example.com
headers:
Authorization: "Bearer ${env:BACKEND_TOKEN}"
debug:
verbosity: basic
extensions:
health_check:
endpoint: 0.0.0.0:13133
service:
extensions: [health_check]
pipelines:
traces:
receivers: [otlp]
processors: [memory_limiter, batch]
exporters: [otlphttp/backend]
metrics:
receivers: [otlp]
processors: [memory_limiter, batch]
exporters: [otlphttp/backend]
logs:
receivers: [otlp]
processors: [memory_limiter, batch]
exporters: [otlphttp/backend]
Points worth knowing:
- Listen on 0.0.0.0 in containers. Recent Collector versions default the receiver to
localhost, which other containers cannot reach. - Put
memory_limiterfirst. It refuses data when the Collector nears its memory limit, so the process slows down instead of being killed. Setlimit_mibbelow the container's memory limit. - Put
batchafter it. Sending fewer, larger requests uses less CPU and network.send_batch_max_sizecaps the size of each request, which matters when your backend limits request size. - Keep secrets out of the file.
${env:BACKEND_TOKEN}reads the token from an environment variable when the Collector starts. - The
otlphttpexporter adds the paths itself. Give it the base URL; it sends to/v1/traces,/v1/metricsand/v1/logs, gzip-compressed by default. - The
/backendsuffix is a name.type/namelets you define two exporters of the same type, for example to send to two places during a migration.
Run it with Docker
docker run -d --name otelcol \
-p 4317:4317 -p 4318:4318 -p 13133:13133 \
-e BACKEND_TOKEN=your-token \
-v "$(pwd)/config.yaml:/etc/otelcol-contrib/config.yaml:ro" \
otel/opentelemetry-collector-contrib:<version>
Pin a specific version tag rather than latest, so an upgrade happens when you choose. The contrib image reads its configuration from /etc/otelcol-contrib/config.yaml. Check that it started:
docker logs otelcol
curl -s http://localhost:13133/
The log should end with a line saying that everything is ready, and the health check should answer. On Kubernetes, the same image and file usually run as a DaemonSet (one Collector per node, close to the applications) or a Deployment (a central gateway). Many teams use both: node Collectors forward to a central one that holds the credentials.
Point your applications at the Collector
OpenTelemetry SDKs read a standard set of environment variables, so you rarely need code changes.
export OTEL_SERVICE_NAME=checkout-api
export OTEL_EXPORTER_OTLP_ENDPOINT=http://otelcol:4318
export OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
export OTEL_RESOURCE_ATTRIBUTES=deployment.environment=production,service.version=1.4.2
export OTEL_TRACES_SAMPLER=parentbased_traceidratio
export OTEL_TRACES_SAMPLER_ARG=0.25
| Variable | What it does |
|---|---|
OTEL_SERVICE_NAME | Names the service. Set it for every service; without it, data shows up as unknown_service. |
OTEL_EXPORTER_OTLP_ENDPOINT | Where to send. For HTTP, the SDK adds /v1/traces and the other paths. |
OTEL_EXPORTER_OTLP_PROTOCOL | grpc or http/protobuf. Defaults differ between SDKs, so set it. |
OTEL_EXPORTER_OTLP_HEADERS | Extra headers as key=value pairs. Needed when exporting directly to a backend; usually not needed towards your own Collector. |
OTEL_RESOURCE_ATTRIBUTES | Attributes added to everything the service sends, such as environment and version. |
OTEL_TRACES_SAMPLER and _ARG | Which sampler to use and its setting, for example a ratio of 0.25. |
Sampling basics
Busy services produce more traces than anyone reads. Sampling keeps a share of them.
- Head sampling decides when a trace starts.
parentbased_traceidratiowith0.25keeps about a quarter of new traces, and child services follow the parent's decision, so traces stay complete. It is cheap but blind: it cannot know in advance which requests will fail. - Tail sampling decides after the trace has finished, in the Collector, with the
tail_samplingprocessor in the contrib image. You can keep every trace with an error or a slow span and a small share of the rest. It needs all spans of a trace to reach the same Collector instance, and it holds traces in memory while it waits.
Start with no sampling while volumes are small. Add head sampling when cost or volume makes it necessary, and tail sampling when you need to keep every error.
Troubleshooting
When nothing arrives, find where the data stops. Add the debug exporter to a pipeline next to your real exporter:
traces:
receivers: [otlp]
processors: [memory_limiter, batch]
exporters: [otlphttp/backend, debug]
With verbosity: detailed it prints every span to the Collector's log. If spans appear there, the applications and receiver are fine and the problem is the export. If they do not, look at the application side.
- Connection refused — wrong port, the receiver is listening on
localhost, or the port is not published from the container. - Protocol mismatch — an SDK sending gRPC to port 4318, or HTTP to 4317.
- 401 or 403 from the backend — missing or wrong token, or the environment variable was not passed to the container.
- 413 or a size error — lower
send_batch_max_size. - Refused data and memory warnings — the memory limiter is working; give the Collector more memory or run more instances.
- Invalid configuration — the Collector exits at start-up and logs the line it could not parse. YAML indentation is the usual cause.
Remove the debug exporter, or set it back to basic, once you are done; detailed output is large.
Send OpenTelemetry data to Televane
Televane accepts traces, metrics and logs over OTLP, so the Collector setup above works with one change to the exporter. First, in the portal open Administration › API keys and create a token with the ingest scope. It starts with obs_ and is shown once, so put it in your secret store.
exporters:
otlphttp/televane:
endpoint: https://ingest.televane.com
headers:
Authorization: "Bearer ${env:TELEVANE_TOKEN}"
service:
pipelines:
traces: { receivers: [otlp], processors: [memory_limiter, batch], exporters: [otlphttp/televane] }
metrics: { receivers: [otlp], processors: [memory_limiter, batch], exporters: [otlphttp/televane] }
logs: { receivers: [otlp], processors: [memory_limiter, batch], exporters: [otlphttp/televane] }
For gRPC, use ingest.televane.com:443 with TLS. To skip the Collector, set OTEL_EXPORTER_OTLP_ENDPOINT=https://ingest.televane.com and OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer obs_YOUR_TOKEN" in each service.
A few limits to plan for. Each request may be up to 1 MiB compressed (8 MiB uncompressed) and 5,000 spans or log records, so keep send_batch_max_size below 5,000. Exponential histograms are not supported yet; use explicit-bucket histograms. Passwords, tokens, keys, card numbers and SQL literals in attributes and log bodies are masked before storage.
Traces then appear on the APM pages with throughput, error rate and p95 latency per service, a span waterfall linked to the logs of the same request, and a service map. Your own metrics can be charted on dashboards. Pricing is by the data you send, with no per-host fees, and the Free plan includes 50 GB a month (see pricing). The full reference is in Send OpenTelemetry data, and you can create an account to try it.
Frequently asked questions
Do I need the OpenTelemetry Collector?
No. SDKs can export directly to any backend that accepts OTLP. A Collector helps when you have many services, want to keep credentials out of applications, or need central filtering, redaction or tail sampling.
Which ports does the OpenTelemetry Collector use?
By convention, 4317 for OTLP over gRPC and 4318 for OTLP over HTTP. The health check extension commonly uses 13133.
Should I use the core or contrib Collector image?
Most teams use contrib, because it includes components such as tail sampling, file log collection and host metrics. You can build a smaller custom distribution later with only the components you use.
What order should Collector processors go in?
Put memory_limiter first so it can refuse data early, then processors that filter, change or sample data, and batch near the end so it batches what will actually be exported.