logsCollection preset wires up the filelog receiver; the kubernetesAttributes preset enriches each record with the pod, namespace, node, and container it came from. A small transform infers severity from the message body, the same way the Docker path does.
Use this for workloads that don’t instrument themselves. A service using an OpenTelemetry SDK
should send records straight to OTLP; collecting both paths stores every event
twice. See Choose what to collect.
Prerequisites
- A running Rootprint instance and the host it serves on — you’ll substitute it for
<your-rootprint>. - A Kubernetes cluster with
kubectlandhelmconfigured against it. The DaemonSet schedules on every node whose pods you want collected. - An ingest API key scoped to your target index. In Settings → API keys, click Create ingest key, give it a name, and pick the index (
otel-logs-v0_9here; see Indexes for its schema). See API keys.
1
Add the OpenTelemetry Helm repo
2
Create values.yaml
Save this as
values.yaml. Replace <your-rootprint> with your Rootprint host and
<your-ingest-token> with the API key you copied above.processorsandexcludeare replaced, not merged. List every entry you want, including the preset-injectedmemory_limiter,k8s_attributesandbatch.- Override the receiver as
filelog, notfile_log. Afile_logblock is ignored; Helm prints a[DEPRECATION]notice for it. otlp_httprequires Collector 0.158.0 or newer. Older images name itotlphttp.
3
Install the chart
exclude above covers both. Otherwise the DaemonSet tails Rootprint and its Quickwit
backend, and their logs feed back into the index.4
Send a test log line
Run a throwaway pod that prints one line and exits. The Collector on that pod’s node tails it and
ships it with the pod’s metadata attached.Clean up afterwards with
kubectl delete pod rootprint-smoke-test.5
Verify in Rootprint
Open Search, pick
otel-logs-v0_9 from the index selector, and query for
hello from rootprint. Allow up to a minute for the batch to flush and Quickwit to commit.
resource_attributes.k8s.pod.name reads rootprint-smoke-test.What you get in Rootprint
Thek8s.* keys are OTLP resource attributes, so query them under resource_attributes:
Severity inference
Thetransform matches two pattern families against the body:
error,fatal,panic, orexception(word-boundary) →severityText: ERROR(severity number 17).warn/warning,deprecated, orretry→severityText: WARN(13).- Everything else →
severityText: INFO(9).
DEBUG is not inferred. Emit debug records through an OpenTelemetry SDK that sets severityNumber itself.
Choose what to collect
logsCollection tails every pod on the node. Exclude what you don’t want before pointing it at a busy cluster.
Workloads that already send OTLP
Exclude the namespaces whose services report over OTLP:filter processor after k8s_attributes and drop on resource_attributes.
Collect selectively instead
To have workloads opt in, use annotation-based discovery and drop thefilelog block:
io.opentelemetry.discovery.logs.<container>/enabled) and per-pod filelog settings via io.opentelemetry.discovery.logs/config are documented upstream.
Multi-line logs
The preset’scontainer operator rejoins lines split by the container runtime, not multi-line output from the application. A stack trace or a pretty-printed object arrives as one record per line.
Add a recombine operator, restating the container parser because operators is replaced wholesale:
is_first_entry marks a record boundary — above, any line not starting with whitespace, which covers indented stack frames. Use a timestamp or level prefix instead if that fits your output better. source_identifier defaults to attributes["log.file.path"], so lines from different containers never merge.
Cluster events (optional)
The steps above collect pod logs. To also capture cluster-level events — scheduling, image pulls, OOMKills — deploy a second Collector as a single-replicaDeployment (not a DaemonSet, to avoid duplicate events) with the kubernetesEvents preset:
rootprint-otel-events) so it doesn’t collide with the DaemonSet.
To keep a single workload instead, enable presets.kubernetesObjects alongside kubernetesEvents on the DaemonSet: it adds a leader election lease so only one pod watches, and also ingests the cluster’s object inventory on a schedule.
Troubleshooting
helm installfails with[ERROR] 'image.repository' must be set: add theimage.repositoryblock from the values above.- DaemonSet pod stays
Pendingwithdidn't have free ports: another Collector holds the default hostPorts. Disable them as shown above. - No pods in the DaemonSet: nodes may carry taints the Collector doesn’t tolerate. Add the matching
tolerations, or checkkubectl describe daemonset -n rootprint. - Records arrive as single lines of a larger message: application-level multi-line output. See Multi-line logs.
- Every event appears twice: a workload is both exporting OTLP and printing to stdout. Compare
attributes.log.file.path:*againstNOT attributes.log.file.path:*to see the split, then exclude that namespace. 401from Rootprint: theAuthorizationheader is missing or the token is wrong.403from Rootprint: the ingest API key is invalid, unknown, or revoked. Create a new one in Settings → API keys. A key scoped to a different index does not return403— it writes there silently, so check the key’s index if records land somewhere unexpected.413from Rootprint: the batch is too large. Addsend_batch_max_sizeto thebatchprocessor.415from Rootprint: theContent-Typeis notapplication/x-protobuf. The Collector sets this automatically; check for a proxy stripping headers.- Logs arrive without
k8s.*attributes: thekubernetesAttributespreset needs RBAC to read pod metadata. The chart creates theClusterRoleautomatically — if you disabled RBAC creation, grantget/list/watchonpodsandnamespaces.
Related
- Send logs from Docker: container logs on a single Linux host.
- Send logs with the OpenTelemetry Collector: the same Collector tailing files on a host.
- OTLP reference: endpoint URL, response codes, body limits.
- Indexes: the
otel-logs-v0_9schema.

