Skip to main content
This page ships container logs from a Kubernetes cluster to Rootprint over OTLP. The OpenTelemetry Collector runs as a DaemonSet — one pod per node — tailing every pod’s stdout/stderr off the kubelet. The chart’s 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.

Prerequisites

  • A running Rootprint instance and its base URL — you’ll substitute it for <your-rootprint>.
  • A Kubernetes cluster with kubectl and helm configured 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_9 here; 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 base URL and <your-ingest-token> with the API key you copied above.The service.pipelines.logs.processors list is spelled out on purpose. The chart replaces this array rather than merging it, so the preset-injected processors (memory_limiter, k8sattributes, batch) have to be listed alongside transform — drop one and the chart drops it from the pipeline.
3

Install the chart

Confirm the DaemonSet is running — one pod per node:
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. The record typically arrives within a few seconds. attributes.k8s.pod.name reads rootprint-smoke-test, and k8s.namespace.name, k8s.node.name, and k8s.container.name are populated.

What you get in Rootprint

The kubernetesAttributes preset attaches cluster context to every record:
OTLP attributeValue
k8s.pod.namepod the log came from
k8s.namespace.namepod’s namespace
k8s.node.namenode the pod is scheduled on
k8s.container.namecontainer within the pod
k8s.pod.uidpod UID
severityinferred from the message body

Severity inference

The transform lowercases the body and matches two pattern families:
  • error, fatal, panic, or exception (word-boundary) → severityText: ERROR (severity number 17).
  • warn / warning, deprecated, or retryseverityText: WARN (13).
  • Everything else → severityText: INFO (9).
DEBUG is not inferred — \bdebug\b against arbitrary pod output false-positives constantly. Apps that need debug-level visibility should emit it via an OpenTelemetry SDK that sets severityNumber itself; that record carries through unchanged because the SDK writes to the same endpoint.

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-replica Deployment (not a DaemonSet, to avoid duplicate events) with the kubernetesEvents preset:
Install it under a separate release name (e.g. rootprint-otel-events) so it doesn’t collide with the DaemonSet.

Troubleshooting

  • No pods in the DaemonSet: nodes may carry taints the Collector doesn’t tolerate. Add the matching tolerations to values.yaml, or check kubectl describe daemonset -n rootprint.
  • 401 from Rootprint: the Authorization header is missing or the token is wrong. Check the token value in values.yaml.
  • 403 from Rootprint: the API key exists but is not scoped to otel-logs-v0_9. Create a new key scoped to that index.
  • 413 from Rootprint: the batch is too large. Add send_batch_max_size to the batch processor.
  • 415 from Rootprint: the Content-Type is not application/x-protobuf. The Collector sets this automatically; if you see a 415, check for a proxy stripping headers.
  • Logs arrive without k8s.* attributes: the kubernetesAttributes preset needs RBAC to read pod metadata. The chart creates the ClusterRole automatically — if you disabled RBAC creation, grant get/list/watch on pods and namespaces.