Validated Minimal OpenTelemetry Collector Configs SREs Can Run Locally
Validated Minimal OpenTelemetry Collector Configs SREs Can Run Locally

Structure your OpenTelemetry Collector config as modular YAML: define receivers, processors, and exporters independently, then wire them together under service.pipelines. Before anything touches production traffic, run otelcol validate against the assembled file and confirm a local OTLP receiver accepts test data. If any port faces the public internet, put a TLS listener and an authenticator extension in front of it; everything else binds to localhost by default.
TL;DR:
- Using multiple configuration sources merges into a single setup, but missing component references can cause startup errors that validation catches early.
- The pipelines can specify the same receiver in multiple stages, but each instance processes data independently without shared state or counters.
- Exposing receivers to the public requires TLS and authentication extensions, which should be declared globally and referenced to keep credentials secure.
- Processor order matters: start with memory limiting, then filtering, transforming, and batching to prevent backpressure and ensure correct processing.
- Running
otelcol validatebefore deployment helps catch structural errors or missing references that could cause incidents or silent data loss.
Table of Contents
- Where OpenTelemetry Collector Config Files Live and How They’re Structured
- Receivers, Processors, and Exporters: Copy-Paste YAML Patterns
- Extensions and Connectors: Auth, Telemetry, and Cross-Pipeline Wiring
- How Do Service.Pipelines Wire Everything Together?
- Operational Security: Binding, TLS, and Secrets Handling
- Minimal Config You Can Validate and Run Right Now
- Agent vs. Gateway: Choosing a Deployment Pattern
- Processor Ordering and Avoiding Pipeline Backpressure
- Internal Telemetry, Config Providers, and Override Behavior
- Where to Go Deeper on Collector Configuration
- Sources
- FAQ
Where OpenTelemetry Collector Config Files Live and How They’re Structured
There’s no single required file path for Collector configuration. You pass one or more sources to --config, and each can be a local file, an environment variable, a raw YAML string, or an HTTP/HTTPS endpoint. This flexibility is what lets teams keep a base config in version control while injecting environment-specific overrides at deploy time, using the config provider system built into the otelcol binary.
When you pass multiple --config sources, the Collector merges them into a single in-memory configuration before startup. Merging is convenient for splitting concerns (a shared receivers file, a per-environment exporters file), but it’s also where quiet failures creep in. If one file references a processor another file was supposed to define and that second file gets left out of the merge, you get a missing-component error at startup rather than at review time.
Every component in the config is identified by a type[/name] key. batch/traces and batch/metrics are two distinct instances of the same processor type, and each key must be unique within its section. Before writing YAML, decide what belongs where:
- Receivers: how telemetry enters the Collector (OTLP, Prometheus scrape, etc.)
- Processors: what happens to data in flight (filtering, batching, enrichment)
- Exporters: where processed data goes next
- Connectors: bridges that link the output of one pipeline to the input of another
- Extensions: cross-cutting capabilities like authentication and health checks
Receivers, Processors, and Exporters: Copy-Paste YAML Patterns
Every pipeline starts with a receiver. The OTLP receiver is the default entry point for most setups because it accepts data over both gRPC and HTTP:
receivers:
otlp:
protocols:
grpc:
endpoint: localhost:4317
http:
endpoint: localhost:4318
Those ports (4317 for gRPC, 4318 for HTTP) are the ones you’ll hit with a local test client before trusting anything downstream.
From there, four processors cover most real-world needs, and the order below is deliberate:
memory_limiterrejects data before the Collector runs out of memory. Set it first, always.filteror the OTTL-based transform processors drop or reshape telemetry early, before you spend CPU cycles processing data you don’t want.transformapplies OTTL statements for renaming attributes, redacting fields, or restructuring spans and logs.cumulativetodeltaconverts cumulative metric points to deltas, useful when your backend expects delta semantics.
For exporters, OTLP and OTLP-HTTP exporters cover most backend integrations, and the Prometheus exporter is common for pull-based metrics scraping. TLS certificates, custom headers, and auth extensions all get configured inside the exporter block itself. One thing to watch: not every receiver or exporter supports every signal type. Wiring a metrics-only exporter into a traces pipeline throws ErrSignalNotSupported at startup, not at runtime, so the failure at least shows up before it costs you an incident.
Extensions and Connectors: Auth, Telemetry, and Cross-Pipeline Wiring
Extensions add capabilities that don’t belong inside any single pipeline, like health checks, authentication, or profiling. You declare them in a top-level extensions block, then explicitly enable them in service.extensions, exactly like enabling receivers or exporters in a pipeline.
A common pattern is an OIDC authenticator protecting an OTLP receiver:
extensions:
oidc:
issuer_url: https://auth.example.com
audience: otel-collector
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
auth:
authenticator: oidc
service:
extensions: [oidc]
Connectors solve a different problem: joining pipelines. A connector acts as an exporter for one pipeline and a receiver for another, which is how patterns like routing traces into a separate tail-sampling pipeline or forwarding a subset of logs into a metrics pipeline get built without duplicating receivers.
- Extensions handle cross-cutting concerns (auth, health, zPages).
- Connectors handle cross-pipeline data flow.
- Both get referenced by key elsewhere in the config, just like any other component.
How Do Service.Pipelines Wire Everything Together?
The service.pipelines block is where receivers, processors, and exporters actually become a pipeline. Each pipeline type (traces, metrics, logs) takes arrays of component keys:
service:
pipelines:
traces:
receivers: [otlp]
processors: [memory_limiter, batch]
exporters: [otlp/backend]
metrics:
receivers: [otlp]
processors: [memory_limiter, cumulativetodelta, batch]
exporters: [prometheus]
Notice otlp appears in both pipelines. That’s a fan-out: one receiver instance ingests data once, then hands matching signals to every pipeline that lists it. You’re not running two separate OTLP listeners.
- List a component key in a pipeline to enable it; components defined but never referenced in
service.pipelinessit dormant. - Processor keys can repeat across pipelines, but each reference creates its own independent processor instance (confirmed in the Collector’s own processor documentation), so there’s no shared counter or shared memory across pipelines even when the YAML key looks identical.
- Pipeline processing is synchronous. A processor that blocks or an exporter that can’t keep up will backpressure the receiver feeding it, which can stall ingestion for every pipeline sharing that receiver.
Operational Security: Binding, TLS, and Secrets Handling
Default every receiver endpoint to localhost unless there’s a specific reason to expose it beyond the host. Binding to 0.0.0.0 without a compensating control is one of the most common Collector misconfigurations, and it’s the first thing worth auditing in any existing deployment. If a workload genuinely needs a Collector reachable across the network, pair the 0.0.0.0 bind with network-level access controls and a TLS listener, following the Collector’s own configuration security guidance.
Authentication should live in an authenticator extension, not in a bearer token pasted into a receiver’s YAML. The oidc and basicauth extensions get declared once and referenced from any receiver or exporter’s auth block, which keeps credentials out of the pipeline definitions themselves. If your organization needs a custom authenticator, note that it has to be compiled into the same binary or added through a custom distribution built with the OpenTelemetry Collector Builder.
For tokens, API keys, and certificates, use environment variable substitution or an external secrets provider rather than checking values into the YAML file. The env and http(s) config providers exist partly for this reason: they let a secrets manager or CI pipeline inject values at deploy time instead of baking them into a committed file.
Pro Tip: Run otelcol validate against every config change in CI, before it merges, not after it deploys. A config that fails validation in staging costs you five minutes; the same failure in production costs you an incident and a missing telemetry window during the exact outage you needed visibility into.
Validating at startup also closes off a class of misconfiguration exposure. A collector that fails to load malformed authentication settings, rather than silently falling back to an open listener, is a collector that fails safe.

Minimal Config You Can Validate and Run Right Now
A minimal, runnable config for local testing needs just an OTLP receiver, a memory limiter, and a debug exporter that prints received data to stdout:
receivers:
otlp:
protocols:
grpc:
endpoint: localhost:4317
processors:
memory_limiter:
check_interval: 1s
limit_mib: 512
exporters:
debug:
verbosity: detailed
service:
pipelines:
traces:
receivers: [otlp]
processors: [memory_limiter]
exporters: [debug]
To confirm this file is well-formed before running it:
- Run
otelcol validate --config=config.yamlto catch structural errors and missing component references. - Run
otelcol print-config --mode=redacted --config=config.yamlto see the fully merged configuration with secrets masked, exactly as documented for the otelcol binary. - Start the Collector in Docker with the ports exposed:
docker run -p 4317:4317 -v $(pwd)/config.yaml:/etc/otelcol/config.yaml otel/opentelemetry-collector --config=/etc/otelcol/config.yaml. - Send a test span with an SDK, or curl the OTLP HTTP endpoint directly, and check the Collector’s stdout for the detailed debug output confirming the span arrived.
If nothing shows up in the logs, check the receiver’s bound port first. A silent failure here is almost always a port mismatch or a firewall rule, not a pipeline bug.
Agent vs. Gateway: Choosing a Deployment Pattern
Running a Collector as an agent (one per host or sidecar per pod) keeps network hops short and local enrichment cheap, but it multiplies the number of instances you have to configure and update. A gateway deployment centralizes processing behind a fleet of Collectors, which simplifies TLS termination, sampling policy, and backend credentials into one place. Most production setups end up hybrid: lightweight agents forwarding to a gateway tier.
Gateways commonly use the loadbalancing exporter to keep related spans together across multiple gateway instances, which matters when tail-based sampling needs to see a full trace to make a keep/drop decision. The gateway deployment pattern documentation covers this exporter’s resolver and routing options in depth:
exporters:
loadbalancing:
routing_key: traceID
resolver:
dns:
hostname: otel-gateway.internal
protocol:
otlp:
tls:
insecure: false
- Use
resolver.staticfor a fixed list of backend hosts, orresolver.dnswhen backends scale dynamically. - Set
routing_key: traceIDfor tail sampling correctness, orrouting_key: servicewhen you need per-service aggregation instead. - Watch
otelcol_loadbalancer_num_backendsand exporter latency metrics to confirm the resolver is finding all healthy backends. Routing by trace ID preserves aggregation accuracy across clustered backends, which static round-robin load balancing does not guarantee.
Processor Ordering and Avoiding Pipeline Backpressure
Ordering inside a pipeline’s processor array isn’t cosmetic; it changes both cost and correctness. The recommended sequence is memory_limiter first, then filtering or sampling, then enrichment processors like resourcedetection or Kubernetes attribute processors, then batch right before the exporter.
memory_limiterfirst protects the Collector from OOM crashes before any expensive transform runs.- Filter and sample early so you’re not spending CPU enriching telemetry you’re about to drop.
- Enrich after filtering, before batching, since enrichment processors add attributes that batching then groups efficiently for export.
- Same processor key in different pipelines creates fully independent instances with no shared state between them, as the Collector’s processor documentation states directly, so tuning
batch/tracesnever accidentally affectsbatch/metrics. - Mitigate backpressure with batch processors sized to your exporter’s throughput, or use a connector to decouple a slow pipeline stage from the receivers feeding it, since synchronous pipeline processing means one saturated exporter can stall ingestion upstream.
Internal Telemetry, Config Providers, and Override Behavior
The Collector can expose its own health and performance data, which is often the first place to look when a pipeline seems to be dropping data silently.
- Enable internal logs and metrics through
service.telemetry, and turn on zPages for live in-process debugging when a pipeline behaves unexpectedly. - Config providers (
env,yaml,file,http,https) can be mixed in a single--configinvocation, letting a base file live in git while an environment-specific override comes from a URL or an environment variable at deploy time. - Use
--setflags to override specific keys in the merged config without editing the file, and runprint-configafterward to confirm the override actually landed where you expected in the final in-memory configuration.
Where to Go Deeper on Collector Configuration
Start with the official Collector configuration reference for provider and merge-behavior details, the gateway deployment guide for scaling patterns, and the security best practices page for hardening checklists. The processor README on GitHub documents instance semantics distribution by distribution.
Once your Collector config is validated and shipping clean telemetry, the next challenge is usually correlating what it emits with the rest of your infrastructure signal, Kubernetes events, CI/CD deploys, and security findings, without hand-stitching dashboards across five tools. That’s the gap Opsphere’s platform is built for: it reads the operational context your Collector pipelines produce alongside AWS, Kubernetes, and observability data through more than 300 read-only integrations, so an SRE investigating an incident isn’t jumping between four consoles to find a root cause. Platform engineering teams already running validated Collector configs can see how this fits their stack on the platform engineering use case page, and pricing for the Developer, Team, and Enterprise plans is listed on the Opsphere pricing page.
Sources
- Gateway deployment pattern | OpenTelemetry
- Configuration | OpenTelemetry Collector
- processor/README.md — OpenTelemetry Collector (GitHub)
FAQ
Do I Need an OTel Collector?
Not always. If you have a single service and a backend that accepts SDK exports directly, you can skip it. Most production setups still add one because it centralizes batching, retry logic, sampling, and backend credential management instead of duplicating that logic in every service’s SDK config.
What Does an OpenTelemetry Collector Do?
It receives telemetry data (traces, metrics, logs) from applications and infrastructure, processes it through configurable pipelines like filtering, batching, and enrichment, and exports it to one or more observability backends. It sits between your instrumented services and whatever platform stores and analyzes that data.
Is an OTel Collector Push or Pull?
It supports both, depending on the receiver. The OTLP receiver is push-based (applications send data to it over gRPC or HTTP), while receivers like the Prometheus receiver pull metrics by scraping endpoints on a schedule you define in the receiver’s config.
What’s the Difference Between the Collector and an OpenTelemetry Exporter?
An exporter is a component, either inside an SDK or inside the Collector, that sends telemetry data to a specific destination. The Collector is the standalone service that hosts receivers, processors, and exporters together, giving you a processing layer that a bare SDK exporter alone doesn’t provide.
How Do I Fix a Missing-Component Error at Startup?
That error almost always means a component referenced in service.pipelines or an auth block isn’t defined in the merged configuration, often because a merged file was left out of the --config arguments. Run otelcol print-config --mode=redacted to see the final merged config and confirm every referenced key actually exists in it.
Recommended
This article is provided for general informational purposes only and does not constitute professional, legal, security, or compliance advice. Please evaluate recommendations against your organization’s specific environment and requirements.
