LinkMesh

Search docs, blog and changelog

ENDE

Snippets · Sources

Collect Kubernetes events as logs

Kubernetes events explain most "why is this pod not running" questions, and the API server deletes them after an hour. The k8s_events receiver watches them and turns each into a log record, so they stay searchable next to the pod's own logs.

Signals
Logs
Category
CollectionKubernetes
Source
Kubernetes API (events)
Components
batchmemory_limiterotlphttp
Destination
OTLP/HTTP endpoint

OpenTelemetry Collector

OpenTelemetry Collector YAML
receivers:
  k8s_events:
    auth_type: serviceAccount
    # Empty means every namespace.
    namespaces: []

processors:
  memory_limiter:
    check_interval: 1s
    limit_percentage: 80
    spike_limit_percentage: 25
  batch:
    timeout: 5s

exporters:
  otlphttp:
    endpoint: https://your-backend:4318

service:
  pipelines:
    logs:
      receivers: [k8s_events]
      processors: [memory_limiter, batch]
      exporters: [otlphttp]

The collector needs this to run in a cluster: a ServiceAccount, the RBAC it uses and the workload. Create the config first with kubectl -n observability create configmap k8s-events --from-file=config.yaml.

Kubernetes manifest
apiVersion: v1
kind: ServiceAccount
metadata:
  name: k8s-events
  namespace: observability
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: k8s-events
rules:
  - apiGroups: [""]
    resources: [events, namespaces]
    verbs: [get, list, watch]
  - apiGroups: [events.k8s.io]
    resources: [events]
    verbs: [get, list, watch]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: k8s-events
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: k8s-events
subjects:
  - kind: ServiceAccount
    name: k8s-events
    namespace: observability
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: k8s-events
  namespace: observability
spec:
  replicas: 1
  strategy:
    type: Recreate
  selector:
    matchLabels:
      app: k8s-events
  template:
    metadata:
      labels:
        app: k8s-events
    spec:
      serviceAccountName: k8s-events
      containers:
        - name: otelcol
          image: otel/opentelemetry-collector-contrib:0.161.0
          args: ["--config=/conf/config.yaml"]
          env:
            - name: K8S_NODE_NAME
              valueFrom:
                fieldRef:
                  fieldPath: spec.nodeName
          volumeMounts:
            - name: config
              mountPath: /conf
      volumes:
        - name: config
          configMap:
            name: k8s-events

LinkMesh

Library › Sources › Kubernetes Events

Auth Type
serviceAccount
Field Selector
type=Warning

What LinkMesh then pushes to the collector, under receivers:

Pushed to the collector
k8sobjects/input_src_00000501:
  auth_type: serviceAccount
  objects:
    - field_selector: type=Warning
      mode: watch
      name: events

The same, as an API call (see automation recipes):

API call
curl -X POST "$LINKMESH/sources" \
  -H "Authorization: Bearer $LMSAT" \
  -H "Content-Type: application/json" \
  -d '{
  "defaultConfig": {
    "auth_type": "serviceAccount",
    "field_selector": "type=Warning"
  },
  "name": "Kubernetes Events",
  "receiverType": "k8s_events"
}'

The rest of the collector config above (k8s_events, memory_limiter, batch, otlphttp) is not part of this template: in LinkMesh those are separate sources, processors and destinations on the route.

Generated from LinkMesh's template catalogue by linkmesh-server snippet-render 1.464.3, not written by hand.

Download config.yamlValidated with otelcol-contrib v0.161.0 on 2026-10-26

Complete config files, each checked with the collector's own validate command (otelcol-contrib v0.161.0). Replace https://your-backend:4318 with your own OTLP endpoint before you run it.

The gotcha

Two replicas ship every event twice. In our test a probe pod produced four events; with one collector replica they arrived once, with two replicas each replica shipped all four - eight records for four events. Keep replicas: 1, and the Recreate strategy, as the manifest does.

Manage this across a fleet

LinkMesh manages collector configuration across a fleet from one self-hosted control plane, so a change like this is made once rather than host by host. The first 25 Collectors are free after a no-card registration in the OpenSight Customer Portal (5 without one).

Doing this in LinkMesh: Install LinkMesh on Kubernetes