OpenTelemetry Collector is a vendor-neutral agent that receives, processes, and exports telemetry data—metrics, traces, and logs. Configuration is YAML-based and declarative; the collector reads one file and runs exactly what you specify, nothing more. Get the config right and you have a flexible observability pipeline. Get it wrong and data either disappears silently or floods your backend.
The Configuration Model
The collector config has four main sections: receivers, processors, exporters, and service. Think of it as a DAG (directed acyclic graph) where data flows from receivers through pipelines to exporters.
Receivers → Processors → Exporters
↓ ↓ ↓
OTLP Batch Jaeger
Prometheus Sampling Datadog
Syslog Attributes Prometheus
The service section wires these together. A pipeline defines which receivers feed into which processors, which then feed into which exporters. You can have multiple pipelines running in parallel—one for traces, another for metrics, a third for logs.
Receivers: Where Data Enters
Receivers listen on ports or read from files. Common ones:
- otlp: gRPC and HTTP endpoints for OpenTelemetry protocol (port 4317 gRPC, 4318 HTTP by default).
- prometheus: Scrapes Prometheus targets. Requires a
configblock withscrape_configs. - syslog: Parses syslog messages (RFC 3164 or RFC 5424).
- jaeger: Accepts Jaeger spans (gRPC, Thrift, HTTP).
- fluentforward: Listens for Fluent Forward protocol.
Example receiver block:
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
prometheus:
config:
scrape_configs:
- job_name: 'my-app'
static_configs:
- targets: ['localhost:8080']
Gotcha: If you don't specify an endpoint, the receiver uses a default (4317 for otlp gRPC). If that port is already bound, startup fails silently in some distributions. Always be explicit about ports.
Processors: Transform and Filter
Processors sit between receivers and exporters. They modify, drop, or batch telemetry. Run them in sequence; order matters.
- batch: Groups telemetry into batches before export (reduces network calls). Essential for production.
- memory_limiter: Prevents memory runaway; drops data if heap exceeds a threshold.
- attributes: Adds, removes, or modifies attributes on spans, metrics, or logs.
- sampling: Drops spans probabilistically or by trace ID (tail-based sampling available).
- resource_detection: Adds resource attributes from environment (AWS, GCP, Kubernetes, etc.).
- span: Renames spans, removes attributes, updates status.
Example processor block:
processors:
batch:
send_batch_size: 1024
timeout: 10s
memory_limiter:
check_interval: 1s
limit_mib: 512
attributes:
actions:
- key: environment
value: production
action: insert
sampling:
sampling_percentage: 10
Trade-off: The batch processor adds latency (up to timeout) to reduce resource use. For high-volume systems, increase send_batch_size to flush faster. For low-volume, increase timeout to batch more efficiently.
Exporters: Where Data Leaves
Exporters send telemetry to backends. Most run over gRPC or HTTP with configurable retry and timeout logic.
- otlp: Sends to any OTLP-compatible backend (Jaeger, Tempo, Datadog, New Relic, etc.).
- prometheus: Exposes metrics on an HTTP endpoint for Prometheus to scrape.
- jaeger: Native Jaeger exporter (gRPC, Thrift, HTTP).
- logging: Writes to stdout (debug only).
- zipkin: Sends to Zipkin.
- splunk: Sends to Splunk HEC.
Example exporter block:
exporters:
otlp:
endpoint: localhost:4317
timeout: 30s
prometheus:
endpoint: 0.0.0.0:8889
logging:
loglevel: debug
Gotcha: The prometheus exporter exposes metrics; it doesn't scrape. Prometheus scrapes the collector's metrics endpoint. Don't confuse this with the prometheus receiver, which scrapes targets.
Service: Wiring Pipelines
The service section defines which receivers, processors, and exporters form a pipeline. Each pipeline is independent.
service:
pipelines:
traces:
receivers: [otlp, jaeger]
processors: [memory_limiter, batch]
exporters: [otlp]
metrics:
receivers: [prometheus]
processors: [batch]
exporters: [prometheus]
logs:
receivers: [syslog]
processors: [attributes]
exporters: [otlp]
This config:
- Accepts traces from OTLP and Jaeger, processes them, exports to OTLP.
- Scrapes Prometheus targets, batches metrics, exposes them.
- Receives syslog, adds attributes, exports as OTLP.
Critical: A receiver, processor, or exporter must be referenced in a pipeline to run. Unused blocks are ignored. If your receiver isn't in the service section, it won't listen.
Minimal Production Example
Here's a realistic setup for a Kubernetes cluster:
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: 1024
resource_detection:
detectors: [k8s, env, system]
batch:
send_batch_size: 512
timeout: 5s
exporters:
otlp:
endpoint: tempo.observability.svc.cluster.local:4317
timeout: 30s
logging:
loglevel: info
service:
pipelines:
traces:
receivers: [otlp]
processors: [memory_limiter, resource_detection, batch]
exporters: [otlp, logging]
This setup:
- Listens on standard OTLP ports.
- Detects Kubernetes resource attributes automatically.
- Limits memory to 1 GB; batches spans for efficiency.
- Exports to Tempo and logs (for debugging).
When This Breaks
Data loss with no error: Exporters have retry logic and a queue. If the backend is unreachable, the queue fills, and old telemetry is dropped. Monitor exporter queue depth and backend latency.
Memory runaway: The memory_limiter processor is a safety valve, not a solution. If you're hitting the limit frequently, either increase it (if you have headroom) or reduce sample rate or batch size.
Duplicate attributes: If you use resource_detection and also add attributes manually, you may end up with conflicting or redundant fields. Check your backend to confirm.
Processor ordering: Sampling before resource_detection means you drop spans before enriching them. Reverse the order if you want all spans enriched equally.
Port conflicts: Receivers bind to ports at startup. If a port is in use, the collector fails. Use netstat or ss to verify ports are free before deploying. If you're running the collector alongside other services on a shared host, the comparison on tinjauhost.biz.id on shared hosting versus VPS trade-offs is worth a read before deciding where to deploy.
One-Line Takeaway
OpenTelemetry Collector config is a declarative pipeline: receivers → processors → exporters, wired in the service section. Get the YAML right, and you have a reusable observability backbone; get it wrong, and telemetry vanishes or your backend drowns in noise. For teams also thinking about how their instrumentation choices affect end-user experience, this guide on ecommerce platform conversion rates by tier illustrates how backend performance and observability gaps can surface in real business metrics.