ObservabilityL · OpenTelemetry CollectorOTelCollector
Receivers
What you'll learn
- Name the receiver kinds the collector ships for logs, metrics, and traces
- Choose the correct receiver for an application, host, file, or Kubernetes source
- Configure the otlp, filelog, journald, hostmetrics, prometheus, and k8sobjects receivers with their production-relevant arguments
- Diagnose a receiver that is running but not accepting data
Prerequisites
Verified against Prometheus 2.55.x · Alertmanager 0.28.x · node_exporter 1.8.x · blackbox_exporter 0.26.x · Grafana 11.x · Loki 3.x · Tempo current · OpenTelemetry Collector 0.110.x · Grafana Alloy current · Docker Engine 28.x · Ubuntu 24.04 LTS · Debian 12 (Bookworm) · RHEL / Rocky / AlmaLinux 9.x · 2026-08-13
An application team ships OTel-instrumented services. The traces
arrive. The metrics arrive. The logs do not, because the
services log to /var/log/app/*.log on the host, not over OTLP.
The team spends two hours debating whether to add a log
forwarder. The answer was in the receiver list all along:
filelog was already available; the configuration simply
omitted it.
This lesson is the receiver surface of the collector: how each receiver gets its data, what arguments are production-relevant, and how to choose the right receiver for the source at hand.
What it is
A receiver is the inbound edge of a collector pipeline. It accepts telemetry from the wire (push protocols) or scrapes it from a local source (pull protocols), converts the source format into pdata, and emits it onto the pipeline. A receiver never exports; an exporter never receives. The boundary is strict.
Wire (push) Local (pull)
+-------------+ +---------------+
| otlp :4317 | | filelog |
| otlp :4318 | | journald |
| jaeger | | prometheus |
| zipkin | | hostmetrics |
| kafka | | k8sobjects |
| otlphttp | | k8s_cluster |
+-------------+ +---------------+
| |
v v
+------+ +------+
| pdata| | pdata|
+------+ +------+
| |
+-----------+--------------+
|
v
Processors ...
The receiver decides the wire format and the parsing work; the
rest of the pipeline sees the same pdata regardless of source.
That uniformity is the property that lets a single loki
exporter ship logs from otlp, filelog, and journald
without any per-source conditional logic.
Why a sysadmin cares
The receiver is the place where data enters the platform. Three failure shapes originate here.
- The receiver that was never declared. The platform team
configured
otlpin the pipeline but the application does not speak OTLP; the team forgot to addfilelogfor the file-based logs. Symptom: the file-based logs never arrive. - The receiver that is declared but bound to the wrong
interface. The
otlpreceiver listens on0.0.0.0but the host firewall blocks the port; the applications connect to a different collector. Symptom: traces from this host do not arrive; the collector self-metrics show zero accepted. - The receiver that scrapes a target it should not. The
prometheusreceiver accidentally scrapes a Kubernetes service that has 50,000 metrics endpoints. Symptom: the collector heap grows;process_runtime_total_alloc_bytesclimbs until the kernel OOM-kills the process.
The receiver choice is the cheapest decision to get right and the most expensive to get wrong. The wrong receiver costs a missed signal; the right receiver costs a line of YAML.
How it works
Wire receivers
Wire receivers accept telemetry from a network endpoint. The collection mode is push; the source initiates the connection.
otlpis the protocol-native receiver for the collector. It accepts OTLP over gRPC (0.0.0.0:4317) and HTTP (0.0.0.0:4318). The OTel SDK in the application initialises a gRPC or HTTP client; the client connects to the receiver; the receiver parses the protobuf or JSON payload into pdata.otlphttpis a separate receiver that accepts OTLP over HTTP/JSON only. Useful when a load balancer in front of the collector terminates TLS and re-encrypts as HTTP.jaegeraccepts the Jaeger Thrift and gRPC protocols on the legacy Jaeger ports (14250,14268,9411). Useful when migrating a fleet off the Jaeger agent. New fleets should export OTLP, not Jaeger.zipkinaccepts the Zipkin v1 JSON and v2 thrift/protobuf formats. Same role asjaegerfor Zipkin-instrumented fleets.kafkaconsumes telemetry from Kafka topics. Used when the fleet already publishes to Kafka and the collector is downstream of the bus.
Local receivers
Local receivers scrape or tail a source on the host. The collection mode is pull; the receiver initiates the read.
filelogtails files from the host filesystem. The closest equivalent to Promtail’s scrape_configs. The receiver tracks file position in a checkpoint store backed by thefile_storageextension; the receiver resumes from the checkpoint after a restart.journaldtails journald entries from the systemd journal. Equivalent tojournalctl -fbut as a streaming receiver. The receiver uses the systemd journal API; it requires the host to be running systemd.hostmetricsscrapes host-level metrics from/proc,/sys, and the cgroup filesystem. CPU, memory, disk, network, load, paging. The receiver is the collector-native replacement fornode_exporterwhen the fleet already runs the collector.prometheusscrapes Prometheus-formatted metrics endpoints. The receiver walks a list of targets declared in the configuration or discovered through aserviceorpodassociation in Kubernetes.k8sobjectswatches the Kubernetes API for object changes and emits each change as a log record. Useful for capturing pod lifecycle events into Loki.
How to configure it
Three receivers for the most common sources, annotated.
# /etc/otelcol/config.yaml
receivers:
# 1. OTLP from OTel-instrumented applications.
# Binds to localhost in agent mode, to a private
# interface in gateway mode. The two protocols (gRPC
# and HTTP) can share the same config block.
otlp:
protocols:
grpc:
endpoint: localhost:4317
max_recv_msg_size_mib: 16
http:
endpoint: localhost:4318
# 2. Tail application log files.
# The include list is a glob; the operators chain parses
# each line into structured fields. Storage is required
# for the checkpoint; the file_storage extension must be
# declared and wired in service.extensions.
filelog:
include:
- /var/log/app/*.log
start_at: end
operators:
- type: regex_parser
regex: '^(?P<ts>\S+) (?P<level>\S+) (?P<msg>.*)$'
- type: move
from: body
to: attributes
# 3. Host metrics. The collector scrapes /proc and /sys
# itself; no separate exporter is needed.
hostmetrics:
collection_interval: 30s
scrapers:
cpu:
metrics:
system.cpu.utilization:
enabled: true
memory: {}
disk: {}
filesystem: {}
network: {}
load: {}
paging: {}
# 4. Prometheus pull. The receiver walks the static list
# of targets; in Kubernetes the service/pod associations
# generate the target list dynamically.
prometheus:
config:
scrape_configs:
- job_name: app
scrape_interval: 30s
static_configs:
- targets: [localhost:9100]
Five arguments that recur in production tuning.
start_atonfilelog—beginningre-reads every file from byte zero on restart;endstarts at the current end of file. The production value isendunless the use case is one-shot log replay.collection_intervalonhostmetrics— the scrape interval. The default is 10 seconds; 30 seconds is enough for host-level metrics and halves the storage cost.scrape_intervalonprometheus— the scrape interval. Match it to the receiver’scollection_intervalfor consistency.max_recv_msg_size_mibonotlp/grpc— the largest protobuf message the receiver accepts. The default is 4 MiB; traces with large span batches need 16 MiB or more.encodingonfilelog— the file encoding (utf-8,utf-16le,gbk, etc.). The default isutf-8; UTF-16 log files are the silent failure shape.
How to validate it
Validation is a parse-check plus a runtime check of the receiver counters.
# CONFIGURATION: parse-check against the schema.
otelcol validate --config=/etc/otelcol/config.yaml
# READ-ONLY: confirm every receiver is accepting data.
curl -s http://localhost:8888/metrics | grep otelcol_receiver_accepted
otelcol_receiver_accepted_log_records{receiver="filelog"} 1872
otelcol_receiver_accepted_log_records{receiver="otlp"} 421
otelcol_receiver_accepted_metric_points{receiver="hostmetrics"} 89
# READ-ONLY: confirm no receiver is refusing data.
curl -s http://localhost:8888/metrics | grep otelcol_receiver_refused
# (empty output = healthy; a non-empty value means the
# memory_limiter is refusing data)
The receiver-side diagnostic follows three steps.
- The process is running.
pidof otelcolreturns a PID; the agent log shows no Start failures. - The receiver is accepting.
otelcol_receiver_accepted_*climbs over time. - The receiver is not refusing.
otelcol_receiver_refused_*is zero or near zero; a non-zero value means thememory_limiteris rejecting the receiver’s batches.
If the receiver is running but receiver_accepted is flat at
zero, the source is not reaching it. Check the bind address,
the firewall, and the source-side configuration in that order.
How it can fail
Six failure modes specific to receivers.
- The filelog receiver that never recovered its position.
The
filelogreceiver was configured withstart_at: beginningand nofile_storageextension. Symptom: after restart, the receiver re-reads every file from byte zero; Loki receives duplicates; the metricotelcol_receiver_accepted_log_recordsshows a step on every restart. - The OTLP receiver that never saw a connection. The
receiver binds to
localhost:4317in agent mode; the application is configured withOTEL_EXPORTER_OTLP_ENDPOINT=http://collector:4317. The application and the collector cannot resolve each other. Symptom:otelcol_receiver_accepted_*is flat at zero; the application log shows connection-refused. - The prometheus receiver that scraped the world. The
receiver was given a target list with 50,000 endpoints. The
collector heap grows; the
memory_limiterbegins refusing. Symptom:otelcol_receiver_refused_metric_pointsclimbs;process_runtime_total_alloc_bytesclimbs; the kernel OOM-kills the process. - The hostmetrics receiver that ran as root. The receiver
needs read access to
/procand/sys. A container image that drops privileges cannot read those paths. Symptom:otelcol_receiver_accepted_metric_pointsis zero; the agent log shows permission-denied. - The journald receiver that read no journal. The receiver
was configured with
units: [sshd]but the host runs sysvinit, not systemd. Symptom:otelcol_receiver_accepted_log_recordsis flat at zero; the agent log shows journal-not-found. - The k8sobjects receiver that watched too much. The
receiver was configured with no
objectsfilter; the collector emits every pod, service, and configmap change as a log record. Symptom: log volume spikes; the Loki cost climbs; the platform team gets a budget alert.
How to troubleshoot it
When a receiver is not behaving, the diagnostic order matters.
- Read the receiver-specific counter. Find the receiver
name in
otelcol_receiver_accepted_*. A flat zero is the signature of “receiver is running, source is not reaching it”. - Confirm the source is reachable. For wire receivers,
ss -tlnpshows whether the listener is bound. For local receivers, the file path or cgroup path must exist and be readable by the collector user. - Check the firewall. A wire receiver on
0.0.0.0is still invisible if the host firewall blocks the port or the network policy in Kubernetes drops the traffic. - Tail the agent log at Start. A receiver that fails to Start logs the reason with a line number and the offending argument. The first error is usually the only one.
- Test with a known input. Send a known OTLP request with
otelcliorcurl; check thatreceiver_accepted_*ticks. If the counter ticks, the receiver is fine; the issue is upstream.
Security implications
Receivers are the most permissive component in the collector. The defaults are local-only; production deployments often relax them in ways that need an audit.
- Bind to localhost in agent mode. The OTLP, Zipkin, and
Jaeger receivers default to
0.0.0.0. In agent mode, change the bind tolocalhost. In gateway mode, restrict the listener with a NetworkPolicy. - Authentication on the wire receivers. The
bearertokenauthandbasicauthextensions provide client-side authentication helpers; the OTLP receiver supports TLS but does not enforce authentication on its own. Add a reverse proxy if mutual TLS is required. - Filesystem access. The
filelog,journald, andhostmetricsreceivers read whatever the collector process can read. Run the process as a dedicated user with read access to the intended paths and no more. - Log content. The
filelogreceiver reads file content verbatim. Sensitive data in the log path (credentials, PII) is captured into pdata and shipped downstream. Theredactionprocessor (orattributeswithaction: delete) strips it before the exporter.
Performance implications
The receiver is the cheapest part of the pipeline. The cost appears at scale.
- OTLP receiver. The gRPC and HTTP servers are goroutine-based; the cost is roughly proportional to the number of concurrent streams. A receiver that accepts thousands of streams holds thousands of goroutines.
filelogreceiver. The receiver tails files; the cost is the cost of reading and parsing. A regex operator with a backtracking pattern can dominate CPU. Use anchored regex.hostmetricsreceiver. The receiver scrapes/procand/syson every collection interval. A 10-second interval is cheap; a 1-second interval can dominate CPU on large hosts.prometheusreceiver. The cost is the cost of scraping each target. A target list with thousands of endpoints is expensive; the cardinality cost is paid downstream.k8sobjectsreceiver. The receiver watches the API server; the cost is the cost of the watch and the per-change emission. Useobjectsfilters aggressively.
Production guidance
- Bind OTLP receivers to localhost in agent mode. In
gateway mode, restrict with NetworkPolicy. The default
0.0.0.0is too permissive for a production host. - Set
start_at: endon filelog receivers. A receiver that starts at the beginning on restart duplicates every line. The right value isendfor steady state;beginningis for one-shot replay. - Declare the
file_storageextension for filelog and journald. Without it, the checkpoint is in-memory and every restart re-reads the file from byte zero. - Filter
k8sobjectsaggressively. Watch only the objects you intend to log. Every watched object becomes a log line on every change. - Match scrape intervals to the metric resolution you need. A 10-second interval on host metrics is overkill; 30 seconds halves the storage cost for almost no loss in dashboard usefulness.
Verification
You should now be able to answer:
- What is the difference between a wire receiver and a local receiver, and which one is push?
- Which receiver should you use for an OTel-instrumented application that exports OTLP?
- Which receiver should you use for a service that writes
logs to
/var/log/app/*.log? - Why does the
filelogreceiver need afile_storageextension in steady state? - What does a flat-zero
otelcol_receiver_accepted_*counter tell you?
Quiz
Knowledge check · 8 questions
Q1. Which receiver is the protocol-native choice for OTel-instrumented applications?
Q2. A service writes structured logs to /var/log/app/*.log. The right receiver is:
Q3. The filelog receiver can resume its position across restarts without the file_storage extension.
Q4. otelcol_receiver_accepted_log_records is flat at zero for the otlp receiver. The first diagnostic step is:
Q5. Name the metric that confirms a receiver is running and accepting data.
Q6. Which of these are wire receivers (push protocol)?
Q7. The right start_at value for the filelog receiver in steady state is:
Q8. The k8sobjects receiver is producing too many log lines. The right action is:
Passing score: 75%. Answers are checked in this browser.