Collect Logs and Infrastructure Metrics with Receivers
Use filelog, hostmetrics, kubeletstats, and prometheus receivers, and derive metrics from traces.
Applications that use an OpenTelemetry SDK push their own telemetry, but much of what you need to observe doesn’t: log files, host resources, the kubelet, and services that already expose Prometheus metrics. The Collector pulls these in through receivers. This guide shows the most useful ones, all as configuration. Component option names change between releases, so check each receiver’s README for the version you run. All of these are in the contrib and Kubernetes distributions.
Log files with filelog
The filelog receiver tails files and turns lines into log records.
receivers:
filelog:
include:
- /var/log/myapp/*.log
exclude:
- /var/log/myapp/*.gz
start_at: end # or "beginning" to read existing content
include_file_path: true
operators:
- type: json_parser
timestamp:
parse_from: attributes.time
layout: '%Y-%m-%dT%H:%M:%S.%LZ'
severity:
parse_from: attributes.level
Operators form a small parsing pipeline that runs on each entry. Common ones are json_parser, regex_parser, move, add, remove, and recombine (to join multi-line stack traces back into one record). A multi-line example:
operators:
- type: recombine
combine_field: body
is_first_entry: body matches "^\\d{4}-\\d{2}-\\d{2}"
source_identifier: attributes["log.file.path"]
To survive restarts without re-reading or skipping data, give the receiver a storage extension:
extensions:
file_storage:
directory: /var/lib/otelcol/storage
receivers:
filelog:
include: [/var/log/myapp/*.log]
storage: file_storage
service:
extensions: [file_storage]
On Kubernetes, container logs live under /var/log/pods/*/*/*.log. The Helm chart’s logsCollection preset configures this receiver, mounts the host path, and parses the container runtime format for you, so prefer it over writing the receiver by hand.
Host metrics with hostmetrics
On a VM or a node, the hostmetrics receiver reads CPU, memory, disk, filesystem, and network figures from the operating system:
receivers:
hostmetrics:
collection_interval: 30s
scrapers:
cpu:
memory:
load:
disk:
filesystem:
exclude_mount_points:
mount_points: [/dev/*, /proc/*, /sys/*, /run/*]
match_type: regexp
network:
paging:
Run it in an agent on each host. In a container, it reports the container’s view unless you mount the host’s filesystem and set root_path, so check the receiver README before relying on it there. Add the resourcedetection processor to label metrics with host, cloud, or Kubernetes details:
processors:
resourcedetection:
detectors: [env, system]
timeout: 5s
override: false
Kubernetes metrics
Node and pod resource usage comes from the kubelet through kubeletstats, run as a DaemonSet:
receivers:
kubeletstats:
collection_interval: 30s
auth_type: serviceAccount
endpoint: ${env:K8S_NODE_NAME}:10250
insecure_skip_verify: true
metric_groups: [node, pod, container]
Pass the node name through the downward API:
env:
- name: K8S_NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
insecure_skip_verify is common because kubelet certificates are often self-signed; use proper CA configuration where you can. The service account needs permission to read nodes/stats, which the Helm preset grants.
Cluster-level state (deployment replicas, pod phase, node conditions) comes from the k8s_cluster receiver, and Kubernetes events from k8sobjects. Run both once per cluster, in a single-replica Deployment, or you will collect duplicates. Both are available as Helm presets (clusterMetrics and kubernetesEvents).
Scrape Prometheus endpoints
The prometheus receiver accepts a standard Prometheus scrape configuration, so existing targets move over without rewriting them:
receivers:
prometheus:
config:
scrape_configs:
- job_name: node-exporter
scrape_interval: 30s
static_configs:
- targets: ["node-exporter:9100"]
- job_name: kubernetes-pods
kubernetes_sd_configs:
- role: pod
relabel_configs:
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
action: keep
regex: "true"
Two gotchas: in a Collector config, write a literal dollar sign in a Prometheus regex or replacement as $$, because the Collector otherwise tries to expand it as a variable; and if you run several replicas that all scrape the same targets, you’ll get duplicates. The OpenTelemetry Operator’s Target Allocator exists to shard targets across Collector replicas, as does running one scraper replica.
Use many receivers, one pipeline
Receivers feed pipelines of the same signal type:
service:
pipelines:
metrics:
receivers: [otlp, hostmetrics, kubeletstats, prometheus]
processors: [memory_limiter, resourcedetection, batch]
exporters: [otlphttp/prometheus]
logs:
receivers: [otlp, filelog]
processors: [memory_limiter, batch]
exporters: [otlphttp/loki]
You can also split into several pipelines per signal (metrics/infra, metrics/apps) to apply different processors to each source.
Metrics from traces with the spanmetrics connector
If your services emit traces but not request metrics, the spanmetrics connector derives request counts, error counts, and latency histograms from spans. A connector is an exporter in one pipeline and a receiver in another:
connectors:
spanmetrics:
histogram:
explicit:
buckets: [10ms, 50ms, 100ms, 250ms, 500ms, 1s, 2.5s, 5s]
dimensions:
- name: http.request.method
- name: http.response.status_code
service:
pipelines:
traces:
receivers: [otlp]
processors: [memory_limiter, batch]
exporters: [otlp/tempo, spanmetrics]
metrics/spanmetrics:
receivers: [spanmetrics]
processors: [batch]
exporters: [otlphttp/prometheus]
Every dimension multiplies the number of time series, so add only attributes with a small, bounded set of values. Never use user IDs or URLs with identifiers. Put the connector before any sampling so that the numbers reflect all traffic (see the sampling guide).
Verify
Add the debug exporter with verbosity: detailed to a copy of the pipeline and run the Collector in the foreground. You should see log records with the parsed severity, or metric names such as system.cpu.time, k8s.pod.cpu.usage, or traces.span.metrics.calls (the naming can differ by version). If nothing appears, check file permissions for filelog, the node name variable for kubeletstats, and that every receiver is listed in a pipeline.
Popular Guides
-
OpenTelemetry Explained: SDKs, OTLP, and the Collector Understand the moving parts and the three places configuration lives before you write any YAML. -
The Collector Configuration Model: Components, Pipelines, and Providers Learn the rules of the Collector's YAML: naming, pipelines, connectors, merging files, and environment variables. -
Configure SDKs with OTEL_* Environment Variables Set the service name, exporters, sampling, and limits for any language using standard variables. -
Instrument Apps Without Code Changes: Java, Python, and Node.js Attach OpenTelemetry agents with environment variables and command-line flags only. -
Make the Collector Production-Ready: Memory Limits, Batching, and Retries Configure processors, queues, and persistent storage so telemetry survives overload and outages. -
Deploy the Collector on Kubernetes with Helm Install the official chart, use presets for logs and metrics, and override the config through values files. -
Troubleshoot the Collector and SDKs A systematic checklist for when telemetry doesn't arrive: debug exporter, health checks, internal metrics, and common mistakes.