Configure OpenTelemetry Collector to Ingest OTLP and Export to Jaeger, Prometheus, and Loki
Learn how to set up the OpenTelemetry Collector to receive OTLP traces and metrics and forward them to Jaeger, Prometheus, and Loki with proper batching, retry logic, and resource attribution. Follow a step‑by‑step guide, validate the pipeline, and recover from common issues.
05 May 2026, 22:31 UTC

Desired Outcome
Run a single OpenTelemetry Collector instance that:
- Accepts OTLP traces and metrics over gRPC (port 4317) and HTTP (port 4318).
- Exports traces to a Jaeger collector (Thrift Compact on 14268).
- Exposes metrics in a Prometheus‑scrapeable format on 8889.
- Pushes logs to Loki via HTTP on 3100.
- Applies per‑signal batching, memory limits, and enriches data with
service.nameanddeployment.environmentattributes.
Prerequisites
- Linux/macOS/Windows host with Docker 24+ or a native binary of
otelcol‑contrib(v0.112.0 or later). - Network connectivity to Jaeger, Prometheus, and Loki endpoints (or local containers).
- Optional TLS certificates if any backend requires mTLS.
- Environment variables
OTEL_SERVICE_NAMEandOTEL_DEPLOYMENT_ENVIRONMENTset for resource attribution, or define them directly in the config.
Configuration Overview
The Collector configuration is split into three logical parts:
- Receivers – where data enters.
- Processors – transform or buffer data.
- Exporters – push data to downstream systems.
Each signal (traces, metrics, logs) has its own pipeline, allowing independent batching and retry settings.
Step‑by‑Step Setup
- Create
config.yaml
Use the following template. Replace placeholder values if your backends use different ports or require TLS. # config.yaml receivers: otlp: protocols: grpc: endpoint: "0.0.0.0:4317" http: endpoint: "0.0.0.0:4318" processors: memory_limiter: limit_mib: 512 spike_limit_mib: 128 check_interval: 10s batch: timeout: 5s send_batch_size: 1024 send_batch_max_size: 8192 resource: attributes: service.name: "${OTEL_SERVICE_NAME:default-service}" deployment.environment: "${OTEL_DEPLOYMENT_ENVIRONMENT:dev}" exporters: jaeger: endpoint: "jaeger:14268" tls: insecure: true prometheus: endpoint: "0.0.0.0:8889" loki: endpoint: "http://loki:3100/loki/api/v1/push" service: extensions: [health_check] pipelines: traces: receivers: [otlp] processors: [memory_limiter, batch, resource] exporters: [jaeger] metrics: receivers: [otlp] processors: [memory_limiter, batch, resource] exporters: [prometheus] logs: receivers: [otlp] processors: [memory_limiter, batch, resource] exporters: [loki]- Validate the config
Run a dry‑run to catch syntax errors before deployment. otelcol‑contrib --config=config.yaml --dry-run- Run the Collector in Docker
Map the required ports and mount the config file. docker run \\ --name otelcol \\ -p 4317:4317 \\ -p 4318:4318 \\ -p 8889:8889 \\ -p 3100:3100 \\ -p 13133:13133 \\ -v $(pwd)/config.yaml:/etc/otelcol/config.yaml \\ otel/opentelemetry-collector-contrib:0.112.0 \\ --config=/etc/otelcol/config.yaml- Verify that the collector is healthy
The Collector exposes a/health_checkendpoint on port 13133. curl -s -o /dev/null -w "%{http_code}\n" http://localhost:13133 # Expected output: 200
Validation Checks
- Prometheus metrics – Scrape
http://localhost:8889/metricsfrom a Prometheus instance orcurland look for counters such asotelcol_receiver_accepted_spans_totalincreasing. - Jaeger UI – Open
http://localhost:16686(or your Jaeger host) and search for the service name you set. Traces should appear with the correct span kind and attributes. - Loki LogQL – In Grafana or Loki’s API, run:
You should see log lines containing the trace ID.{service_name="${OTEL_SERVICE_NAME}"} |= "test-span" - Collector logs – Inspect Docker logs for any
ERRORorWARNmessages. Example:docker logs otelcol
Recovery Options
- Backends unavailable – The
batchprocessor buffers data in memory. If a backend goes down, the Collector will retry until the buffer reachessend_batch_max_size. To avoid data loss, monitor theotelcol_batcher_queue_sizemetric. - Memory pressure – The
memory_limiterpauses ingestion when memory usage exceedslimit_mib. Logs will show a warning. Increase the limit or adjust the container’s memory quota if you see frequent pauses. - Configuration errors – Use
--dry-runbefore redeploying. If the Collector exits immediately, the logs will contain a JSON error describing the misconfiguration. - Service restart – Restart the Docker container to drain any queued data. The Collector will resume normal operation once the backends are reachable.
Limitations & Next Steps
- The example uses Jaeger’s Thrift Compact exporter, which lacks TLS support in Collector <0.110. If you need mTLS, switch to
otlphttpexporter or upgrade Jaeger. - Prometheus exporter shares the same port as the OTLP HTTP receiver if not separated. In production, bind each to a distinct service or use host networking with care.
- The
resourceprocessor only sets static attributes. For dynamic environments (Kubernetes, ECS), enable thek8s_observerorenvprocessors to auto‑populate fields. - Batch size and timeout are tuned for moderate traffic. For bursty workloads, increase
send_batch_sizeor reducetimeoutto lower latency. - Always run health checks and monitor the Collector’s own metrics to detect backpressure or failures early.
Conclusion
With a single otelcol-contrib instance you can ingest OTLP traces, metrics, and logs, enrich them with resource attributes, and forward them to Jaeger, Prometheus, and Loki. The modular pipeline lets you adjust batching, retries, and memory limits per signal, giving you fine‑grained control over latency and reliability. Follow the steps above, validate each component, and you’ll have a robust observability foundation in minutes.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.