Home DevOps Docker Observability with OpenTelemetry: Replace Your Scattered Monitoring Stack
Advanced 3 min · July 11, 2026

Docker Observability with OpenTelemetry: Replace Your Scattered Monitoring Stack

OpenTelemetry for Docker observability — OTel Collector 0.156.0+, OTel eBPF Instrumentation (OBI) for zero-code tracing, Collector-to-Prometheus with prometheusremotewrite, OTel vs Prometheus decision guide, structured logging, and trace propagation across containers..

N
Naren Founder & Principal Engineer

20+ years shipping production infrastructure and CI/CD at scale. Lessons pulled from things that broke in production.

Follow
Production
production tested
July 11, 2026
last updated
1,787
articles · all by Naren
Before you start⏱ 30 min
  • Docker and Docker Compose basics
  • Understanding of metrics, logs, and traces (observability signals)
  • Basic familiarity with Prometheus and Grafana
  • OpenTelemetry concepts (traces, spans, metrics, logs)
 ● Production Incident 🔎 Debug Guide
Quick Answer

Deploy the OTel Collector in Docker: docker run -v $(pwd)/otel-config.yaml:/etc/otel/config.yaml otel/opentelemetry-collector-contrib:0.156.0. Configure receivers (OTLP, Prometheus, filelog), processors (batch, filter, attributes), and exporters (prometheusremotewrite, debug). For zero-code tracing, run the OTel eBPF Instrumentation agent: docker run --privileged --pid=host -v /sys/kernel/debug:/sys/kernel/debug ghcr.io/otel-ebpf/instrumentation:latest. This automatically instruments all HTTP/gRPC traffic without changing application code. Connect the eBPF agent to the OTel Collector via OTLP to see distributed traces across your Docker compose services.

✦ Definition~90s read
What is Docker Observability with OpenTelemetry?

OpenTelemetry (OTel) is the CNCF-graduated observability framework that provides a single, vendor-agnostic standard for collecting traces, metrics, and logs from distributed systems. For Docker environments, the OTel Collector acts as a centralized pipeline that receives telemetry from containers, processes it (filtering, sampling, enrichment), and exports it to any backend (Prometheus, Jaeger, Datadog, New Relic, etc.).

Imagine your application is a busy restaurant kitchen with multiple stations (containers).

The OTel eBPF Instrumentation (OBI) project extends this to zero-code instrumentation — automatically generating traces for HTTP/gRPC calls, database queries, and messaging without modifying application code. By 2026, OTel has become the default observability layer for cloud-native applications, replacing fragmented stacks of Prometheus + Jaeger + EFK with a single configurable pipeline.

The OTel Collector 0.156.0+ includes the prometheusremotewrite exporter, bridging OTel metrics to Prometheus-compatible storage for long-term retention and alerting.

Plain-English First

Imagine your application is a busy restaurant kitchen with multiple stations (containers). Before OpenTelemetry, each station shouted its status in its own language — one used Prometheus for metrics, another used Jaeger for traces, a third used a custom log format. The head chef (you) had three different notebooks to understand what was happening. OpenTelemetry is like giving everyone the same notepad and pen: the OTel Collector is the head waiter who collects all notepads, checks for consistency, and delivers them to the right places. The eBPF Instrumentation is like installing cameras that automatically record every order and delivery without any chef having to write anything down.

⚙ Browser compatibility
Latest versions — ✓ supported
ChromeFirefoxSafariEdge

Your microservices are running in Docker containers. You have Prometheus scraping metrics, Jaeger for traces, and the ELK stack for logs — three separate systems, each with its own configuration, storage, and alerting. A slow database query shows up as a high P99 latency in Prometheus, but connecting that to the specific trace in Jaeger and the error log in Kibana requires manual correlation. This fragmented approach is the legacy of the 2010s observability landscape.

OpenTelemetry changes this by unifying all three signals — traces, metrics, and logs — into a single data model and pipeline. The OTel Collector becomes the single point of configuration, processing, and routing. You define receivers (where data comes from), processors (what to do with it — sample, filter, enrich, batch), and exporters (where to send it). The same Collector instance can forward traces to Jaeger, metrics to Prometheus via prometheusremotewrite, and logs to any OTLP-compatible backend.

The latest evolution: OTel eBPF Instrumentation (OBI), which uses eBPF to automatically instrument network calls, database queries, and messaging without any code changes. This is game-changing for legacy applications that cannot be modified to add OTel SDKs. The eBPF agent attaches to network syscalls and reconstructs HTTP/gRPC spans, then exports them via OTLP to the Collector.

By the end of this guide, you'll have a complete OTel observability stack running in Docker — Collector, eBPF instrumentation, Prometheus storage, and trace/visualization — configured end-to-end with examples you can adapt to any application stack.

OTel Collector Architecture: Receivers, Processors, and Exporters

The OTel Collector is a pipeline — data flows from receivers through processors to exporters. Understanding this pipeline is the key to configuring OTel for any Docker environment.

Receivers are the data entry points. otlp receiver accepts OTel Protocol (gRPC on 4317, HTTP on 4318). prometheus receiver scrapes Prometheus endpoints. filelog receiver tails log files. hostmetrics receiver collects host-level metrics (CPU, memory, disk, network). Each receiver produces one or more of the three signals: traces, metrics, or logs.

Processors transform the data. batch aggregates for efficient export. filter drops data based on conditions. attributes adds or modifies attributes. memory_limiter prevents OOM by dropping data when memory exceeds threshold. tail_sampling implements trace sampling. transform applies OTTL for complex transformations.

Exporters are the data destinations. otlp exports to another Collector or backend. prometheusremotewrite exports metrics to Prometheus-compatible storage. jaeger exports traces to Jaeger. debug prints to stdout.

Define pipelines under service.pipelines. A typical traces pipeline: receivers: [otlp] → processors: [batch, memory_limiter] → exporters: [otlp, debug].

otel-collector-config.yamlYAML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# io.thecodeforge — DevOps tutorial

receivers:
  otlp:
    protocols:
      grpc:
        endpoint: 0.0.0.0:4317
      http:
        endpoint: 0.0.0.0:4318

  prometheus:
    config:
      scrape_configs:
        - job_name: 'docker-containers'
          docker_sd_configs:
            - host: unix:///var/run/docker.sock
          relabel_configs:
            - source_labels: [__meta_docker_container_name]
              target_label: container

  hostmetrics:
    collection_interval: 30s
    scrapers:
      cpu: {}
      memory: {}
      disk: {}
      network: {}

  filelog:
    include: [/var/log/containers/*.log]
    operators:
      - type: json_parser
        parse_from: body

processors:
  batch:
    timeout: 2s
    send_batch_max_size: 1000

  memory_limiter:
    check_interval: 5s
    limit_mib: 800

  attributes:
    actions:
      - key: environment
        value: production
        action: upsert

  tail_sampling:
    policies:
      - name: sample-errors
        type: status_code
        config:
          status_code_source: span
          rules:
            - status_code: ERROR
              min_spans: 1

service:
  pipelines:
    traces:
      receivers: [otlp]
      processors: [memory_limiter, batch, tail_sampling]
      exporters: [otlp, debug]
    metrics:
      receivers: [otlp, prometheus, hostmetrics]
      processors: [memory_limiter, batch]
      exporters: [prometheusremotewrite]
    logs:
      receivers: [otlp, filelog]
      processors: [memory_limiter, batch]
      exporters: [otlp, debug]
Interview Gold: Memory Limiter Is Mandatory in Production
Without the memory_limiter processor, the OTel Collector can grow unbounded during traffic spikes, getting OOMKilled by Docker. Always configure it: 80% of the container's memory limit. The Collector will gracefully drop data instead of crashing.
Production Insight
A streaming platform had their Collector OOM every 3 hours during peak traffic. Root cause: batch processor had send_batch_max_size: 100000 (default is 1000). The Collector held 100K spans in memory per batch. Fix: reduce to 1000, add memory_limiter. No more OOMs.
Key Takeaway
OTel Collector is a pipeline: receivers → processors → exporters. Always configure memory_limiter, batch, and appropriate sampling.
docker-opentelemetry THECODEFORGE.IO OpenTelemetry Observability Stack Layers Component hierarchy from instrumentation to visualization Instrumentation OTel SDK | OTel eBPF (OBI) | Auto-instrumentation agents Collection OTel Collector | Receivers | Processors Backend Storage Prometheus (metrics) | Jaeger (traces) | Loki (logs) Visualization & Alerting Grafana dashboards | Alertmanager | Trace analytics THECODEFORGE.IO
thecodeforge.io
Docker Opentelemetry

OTel eBPF Instrumentation (OBI): Zero-Code Tracing for Docker Containers

Traditional OTel instrumentation requires adding SDKs to application code. For legacy applications, vendor-modified frameworks, or polyglot environments, this is impractical. OTel eBPF Instrumentation (OBI) solves this by automatically instrumenting network-level operations from outside the application.

OBI works by attaching eBPF programs to the kernel's network stack. When a container makes an HTTP request, the eBPF program intercepts the syscall, reads the HTTP headers, and reconstructs a span. It captures: method, URL path, status code, latency, and body size. It also propagates trace context via the traceparent header.

OBI supports: HTTP/1.1 and HTTP/2, gRPC, TLS connections (via uprobe attachment to OpenSSL/BoringSSL), MySQL and PostgreSQL queries, Redis commands, and Kafka produce/consume operations.

Running OBI: deploy as a privileged container sharing the host PID namespace and mounting debugfs. Configure with OTEL_EXPORTER_OTLP_ENDPOINT and OTEL_SERVICE_NAME.

docker-compose-obi.yamlYAML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# io.thecodeforge — DevOps tutorial

version: '3.8'
services:
  otel-collector:
    image: otel/opentelemetry-collector-contrib:0.156.0
    command: ["--config=/etc/otel/config.yaml"]
    volumes:
      - ./otel-config.yaml:/etc/otel/config.yaml
    ports:
      - "4317:4317"
      - "4318:4318"

  otel-ebpf:
    image: ghcr.io/otel-ebpf/instrumentation:latest
    privileged: true
    pid: host
    network_mode: host
    volumes:
      - /sys/kernel/debug:/sys/kernel/debug:rw
      - /proc:/var/run/proc:ro
      - /sys/fs/cgroup:/sys/fs/cgroup:ro
    environment:
      OTEL_EXPORTER_OTLP_ENDPOINT: "http://otel-collector:4317"
      OTEL_SERVICE_NAME: "eBPF-auto-instrumentation"

  app:
    image: python:3.11-slim
    command: python -m http.server 8080
    ports:
      - "8080:8080"

  prometheus:
    image: prom/prometheus:latest
    ports:
      - "9090:9090"

  grafana:
    image: grafana/grafana:latest
    ports:
      - "3000:3000"
Production Trap: eBPF Kernel Requirements
OBI requires kernel 5.4+ with BTF support and BPF Type Format enabled. It needs Linux Security Module (LSM) BPF hooks (kernel 5.8+). Run cat /sys/kernel/security/lsm to verify. If the output is 'none' or doesn't include 'bpf', OBI fails silently.
Production Insight
A team at a major bank used OBI to instrument a 15-year-old COBOL-based payment processing system running in Docker. The application couldn't be modified (no source code access). OBI generated complete traces for every payment request without a single code change.
Key Takeaway
OTel eBPF Instrumentation provides zero-code tracing for HTTP/gRPC, database queries, and Redis/Kafka. Runs as privileged container with host PID namespace. Ideal for legacy applications.

Metrics Pipeline: OTel Collector to Prometheus via prometheusremotewrite

The OTel Collector can replace Prometheus server's scraping function entirely. Instead of having Prometheus scrape metrics from each container, the Collector receives metrics via OTLP and exports them using the prometheusremotewrite exporter.

This architecture ('OTel as the metrics pipeline frontend') is the recommended pattern since Collector 0.156.0+. Benefits: single configuration for all metrics, ability to process metrics before storage (filter, aggregate, enrich), and reduced load on Prometheus.

The prometheusremotewrite exporter sends metrics to Prometheus's remote write endpoint (/api/v1/write). Configure with endpoint, namespace, and resource_to_telemetry_conversion. The exporter uses a queue with configurable consumers and retry settings.

For long-term storage, use Prometheus in remote-write-only mode with Thanos or Grafana Mimir as the backend. The Collector sends metrics to the remote-write endpoint, and Thanos/Mimir handles storage and querying.

Metric naming: OTel uses dots (http.server.duration), Prometheus uses underscores (http_server_duration). The Collector automatically converts dots to underscores.

metrics-pipeline.yamlYAML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# io.thecodeforge — DevOps tutorial

receivers:
  otlp:
    protocols:
      grpc:
        endpoint: 0.0.0.0:4317
  prometheus:
    config:
      scrape_configs:
        - job_name: 'node-exporter'
          static_configs:
            - targets: ['node-exporter:9100']

processors:
  batch:
    timeout: 2s
    send_batch_max_size: 10000
  memory_limiter:
    limit_mib: 800
    check_interval: 5s
  attributes:
    actions:
      - key: deployment_environment
        value: production
        action: upsert
  filter:
    metrics:
      include:
        match_type: regexp
        metric_names:
          - "http.server.*"
          - "container.*"
          - "process.*"

exporters:
  prometheusremotewrite:
    endpoint: "http://prometheus:9090/api/v1/write"
    remote_write_queue:
      enabled: true
      num_consumers: 5
      queue_size: 10000
    resource_to_telemetry_conversion:
      enabled: true
    retry_on_failure:
      enabled: true
      initial_interval: 5s
      max_interval: 60s

service:
  pipelines:
    metrics:
      receivers: [otlp, prometheus]
      processors: [memory_limiter, batch, filter, attributes]
      exporters: [prometheusremotewrite]
Senior Shortcut: Use prometheusremotewrite with VictoriaMetrics
VictoriaMetrics is a Prometheus-compatible TSDB that uses significantly less disk and memory than Prometheus. Replace Prometheus: endpoint: http://victoriametrics:8428/api/v1/write. It's 10x more storage-efficient for high-cardinality metric sets.
Production Insight
A SaaS company was spending $4,000/month on Prometheus storage for 500M time series. They switched to OTel Collector → VictoriaMetrics. The Collector filtered out 60% of metrics before they reached storage. The bill dropped to $600/month — no application changes.
Key Takeaway
OTel Collector replaces Prometheus scraping as the metrics pipeline frontend. Use prometheusremotewrite to send processed metrics to Prometheus, VictoriaMetrics, or Mimir.
Scattered Stack vs Unified OTel Approach Compare traditional monitoring with OpenTelemetry integration Scattered Stack Unified OTel Instrumentation Vendor-specific agents per service Single OTel SDK or eBPF zero-code Data Pipeline Multiple exporters, custom shippers OTel Collector with unified pipeline Trace Correlation Manual trace IDs, no propagation Automatic context propagation across con Metrics Pipeline Direct to Prometheus, no enrichment OTel Collector → Prometheus via OTLP Logging Structured logs without trace IDs Logs correlated with traces via OpenTele THECODEFORGE.IO
thecodeforge.io
Docker Opentelemetry

Structured Logging and Trace Correlation with OpenTelemetry

OTel's log signal unifies logs with traces and metrics. The key benefit: log entries can be correlated with traces using trace_id and span_id attributes, enabling clicking from a log line to the trace that generated it.

Structured logging: applications emit logs in JSON format with trace context embedded. Use OTel SDK logging (auto-injecting trace_id/span_id) and export via OTLP to the Collector.

For existing applications that log to files, use the filelog receiver. It tails log files, parses them (JSON, regex), and converts entries to OTel log records.

Log enrichment: use the attributes processor to add service.name, container.id, environment to all log entries.

Trace-log correlation: when the application emits logs with trace_id and span_id, the Collector correlates them. In Grafana, click from a log entry to the trace span.

otel-structured-logging.pyPYTHON
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#!/usr/bin/env python3
import logging
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.exporter.otlp.proto.grpc.log_exporter import OTLPLogExporter
from opentelemetry.sdk._logs import LoggerProvider, LoggingHandler
from opentelemetry.sdk._logs.export import BatchLogProcessor

trace.set_tracer_provider(TracerProvider())
tracer = trace.get_tracer(__name__)

logger_provider = LoggerProvider()
logger_provider.add_log_processor(
    BatchLogProcessor(OTLPLogExporter(endpoint="http://otel-collector:4317", insecure=True))
)

handler = LoggingHandler(level=logging.INFO, logger_provider=logger_provider)
logging.getLogger().addHandler(handler)

with tracer.start_as_current_span("process-order") as span:
    logging.info("Processing order %s", "ORD-12345")
    # Log automatically includes trace_id and span_id
Interview Gold: Logs Are Still Needed for Debugging
Even with perfect tracing, logs are essential for debugging because they contain application-specific context (variable values, business logic state). OTel approach: traces for 'what happened', logs for 'why it happened'. Always correlate via trace_id.
Production Insight
A fintech startup reduced MTTR from 45 minutes to 8 minutes by implementing trace-log correlation. The key: filelog receiver with JSON parsing and structured logs with trace context. One click from trace to log eliminated manual cross-system searching.
Key Takeaway
OTel unifies logs with traces and metrics. Use OTel SDK logging for automatic trace_id injection, or filelog receiver for existing logs. Enable trace-log correlation.

Trace Propagation Across Containers: Making Distributed Tracing Actually Work

Distributed tracing across containers fails when trace context isn't propagated between services. This is the most common OTel implementation issue. If Service A calls Service B and the trace_id doesn't continue, you get two disconnected traces.

Trace context propagation uses the traceparent header (W3C Trace Context). When Service A makes an HTTP request, the OTel SDK injects the traceparent header. Service B's SDK extracts it and continues the trace. Format: 00-<trace_id_32_hex>-<span_id_16_hex>-01.

For SDK-instrumented services: set OTEL_PROPAGATORS=tracecontext,baggage. This enables W3C Trace Context plus baggage.

For eBPF-instrumented services: OBI automatically propagates trace context by capturing the traceparent header from outgoing requests and injecting it into downstream requests.

Common failure: proxies and load balancers strip unknown headers. Ensure your reverse proxy (nginx, Envoy, HAProxy) is configured to pass through the traceparent header.

For non-HTTP protocols (gRPC, messaging), use the OTel propagator for that protocol. gRPC uses binary propagation in metadata. Kafka messages propagate via message headers.

trace-propagation-check.shBASH
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// io.thecodeforge — DevOps tutorial

# Check if traceparent header is being sent
curl -v http://service-b:8080/api/endpoint 2>&1 | grep -i traceparent
# If empty, propagation is broken

# Verify propagator configuration in running container
docker exec <container-id> env | grep OTEL_PROPAGATORS
# Should output: OTEL_PROPAGATORS=tracecontext,baggage

# Check proxy config (nginx example) to ensure header passthrough
# In nginx config:
# underscores_in_headers on;
# proxy_set_header traceparent $http_traceparent;

# Using curl to simulate trace propagation
export TRACEPARENT="00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01"
curl -H "traceparent: $TRACEPARENT" http://service-b:8080/api/endpoint
Production Trap: Proxies Stripping traceparent Header
Some proxies and CDNs strip unknown headers, including traceparent. This is the #1 cause of broken distributed tracing. Configure your reverse proxy to pass through traceparent, tracestate, and baggage headers. nginx: underscores_in_headers on; proxy_pass_request_headers on;.
Production Insight
A team spent two weeks debugging 'missing traces' before discovering their AWS ALB was stripping the traceparent header. The fix: use the OTel AWS Lambda extension which re-injects the header after the ALB removes it. The traces appeared immediately.
Key Takeaway
Trace context propagates via the traceparent header. Set OTEL_PROPAGATORS=tracecontext,baggage on all services. Ensure proxies pass through traceparent. Test with curl to verify propagation.
● Production incidentPOST-MORTEMseverity: high

The 8-Minute P99 Latency Spike Nobody Could Explain

Symptom
Every day at 2:04 PM, P99 latency on the checkout service jumped from 200ms to 12s for exactly 8 minutes, then returned to normal. No deployment, no traffic spike, no error rate increase.
Assumption
Team spent days looking at each silo: Prometheus said CPU/memory were normal. Jaeger couldn't find the slow traces because they were sampling at 5%. ELK showed no error logs. Assumed it was an external dependency (payment gateway) slowing down.
Root cause
A cron job in a separate container ran a daily data export at 2:00 PM, consuming all available I/O bandwidth on the shared data volume. The checkout service's database queries queued behind the export's sequential scan. The 8-minute window was exactly the export duration.
Fix
1) OTel Collector with eBPF instrumentation revealed the blocking span: a PostgreSQL query waiting on 'I/O wait' correlated with the export container's disk write activity. 2) Moved the data export to a separate storage volume with dedicated I/O limits. 3) Added OTel-metric-based alerts for disk I/O pressure per container. 4) Enabled continuous profiling via OTel's profiling signal.
Key lesson
  • Without unified observability, connecting latency symptoms to I/O root causes requires cross-referencing three tools. OTel's single pipeline eliminates this.
  • Per-container CPU/memory metrics miss I/O contention. OTel eBPF Instrumentation captured the actual trace showing the database wait event.
  • eBPF instrumentation discovered the root cause without any code changes — the checkout service was a legacy Java app without OTel SDKs.
Production debug guideSymptom → Root cause → Fix3 entries
Symptom · 01
OTel Collector starts but no data appears in the backend (Prometheus/Jaeger)
Fix
1. Check Collector logs: docker logs <collector-container>. Look for 'Failed to export' or 'receiver is closed'. 2. Verify receiver configuration matches your app's protocol (OTLP gRPC on 4317, OTLP HTTP on 4318). 3. Test with Collector's health check: curl http://localhost:13133. 4. Use the debug exporter to see data in Collector stdout.
Symptom · 02
eBPF instrumentation agent starts but doesn't generate any traces
Fix
1. Verify kernel support: cat /sys/kernel/security/lsm should not be 'none'. 2. Check eBPF agent logs for 'failed to attach BPF program'. 3. Ensure agent runs with --privileged and --pid=host. 4. Test with a known HTTP request: curl http://localhost:8080/api/health. 5. Verify OTLP endpoint in eBPF agent config points to the Collector.
Symptom · 03
prometheusremotewrite exporter fails with '409 Conflict' or 'write failed'
Fix
1. Check if Prometheus remote write endpoint is reachable: curl -I http://prometheus:9090/api/v1/write. 2. Verify WAL disk space: df -h /var/lib/prometheus. 3. Add batch processor and queue settings to the exporter. 4. Check for metric name conflicts: duplicate names cause 409.
FeatureOpenTelemetryPrometheusJaegerELK Stack
TracesNative (OTLP)NoNativeNo
MetricsNative (OTLP)NativeNoNo
LogsNative (OTLP)NoNoNative
Unified pipelineYes (single config)No (separate)No (separate)No (separate)
Zero-code instrumentationYes (eBPF)NoNoNo
Storage integrationAny backendItself + remote writeElasticsearch, S3Elasticsearch
ProcessingReceivers → Processors → ExportersRecording rulesSampling onlyIngest pipelines
Best forUnified observabilityMetrics monitoringDistributed tracingLog management
⚙ Quick Reference
5 commands from this guide
FileCommand / CodePurpose
otel-collector-config.yamlreceivers:OTel Collector Architecture
docker-compose-obi.yamlversion: '3.8'OTel eBPF Instrumentation (OBI)
metrics-pipeline.yamlreceivers:Metrics Pipeline
otel-structured-logging.pyfrom opentelemetry import traceStructured Logging and Trace Correlation with OpenTelemetry
trace-propagation-check.shcurl -v http://service-b:8080/api/endpoint 2>&1 | grep -i traceparentTrace Propagation Across Containers

Key takeaways

1
OTel Collector unifies traces, metrics, and logs into a single pipeline. Receivers → Processors → Exporters architecture is the foundation. Always configure memory_limiter in production.
2
OTel eBPF Instrumentation provides zero-code tracing for HTTP/gRPC, SQL, Redis, and Kafka. Essential for legacy applications that cannot be modified to add SDKs.
3
Use prometheusremotewrite exporter to send OTel metrics to Prometheus, VictoriaMetrics, or Grafana Mimir. The Collector replaces Prometheus scraping as the metrics pipeline frontend.
4
Trace context propagation via traceparent header is the most common failure point. Ensure all services and proxies pass through traceparent. Set OTEL_PROPAGATORS=tracecontext,baggage.
5
Structured JSON logging with trace_id/span_id correlation enables clicking from log entries to traces. Use OTel SDK logging or filelog receiver with JSON parsing.

Common mistakes to avoid

4 patterns
×

Not configuring memory_limiter processor, causing Collector OOM during traffic spikes

×

Forgetting to set OTEL_PROPAGATORS=tracecontext on all services

×

Using Prometheus receiver in Collector to scrape, then also having Prometheus scrape the same targets

×

Not filtering high-cardinality metrics before they reach Prometheus storage

INTERVIEW PREP · PRACTICE MODE

Interview Questions on This Topic

Q01SENIOR
Compare and contrast OpenTelemetry and Prometheus for metrics collection...
Q02SENIOR
How does OTel tail-based sampling work and when would you use it over he...
Q03SENIOR
Explain the OTel Collector pipeline and how you would debug a missing tr...
Q04SENIOR
How would you design an observability architecture for a 200-microservic...
Q01 of 04SENIOR

Compare and contrast OpenTelemetry and Prometheus for metrics collection. When would you use each?

ANSWER
Prometheus is a pull-based monitoring system with integrated storage and alerting. OTel is a unified observability framework supporting traces, metrics, and logs with flexible push/pull receivers. Use Prometheus when you need a self-contained monitoring stack and prefer pull-based scraping. Use OTel when you need to unify multiple signals, push-based architecture, or advanced processing (sampling, filtering, enrichment) before storage. Best practice: OTel Collector for metric pipeline, Prometheus for storage and alerting.
FAQ · 5 QUESTIONS

Frequently Asked Questions

01
Do I still need Prometheus if I use OTel Collector?
02
Can OTel eBPF instrumentation work with TLS-encrypted traffic?
03
What's the difference between OTel Collector and OTel SDK?
04
How do I handle high-cardinality metrics (e.g., per-user or per-request metrics) with OTel?
05
Does OTel support profiling in addition to traces, metrics, and logs?
N
Naren Founder & Principal Engineer

20+ years shipping production infrastructure and CI/CD at scale. Lessons pulled from things that broke in production.

Follow
Verified
production tested
July 11, 2026
last updated
1,787
articles · all by Naren
🔥

That's Docker. Mark it forged?

3 min read · try the examples if you haven't

Previous
Rootless Docker Production Guide
35 / 41 · Docker
Next
Harbor Registry Deep Dive