Skip to main content

Filter K3s Logs by Level

Reduce log volume and storage costs by filtering to only ERROR and WARN level logs.

Prerequisites and collection scope

Install kubectl on the edge node and configure a kubeconfig with permission to list pods and read pods/log in production. Replace production and app=web-app below with your namespace and workload label. The command follows the matching pods available when it starts, with at most 10 concurrent log streams; it does not discover new pods continuously. For fleet-wide collection across pod churn, use a Kubernetes log collector. Restarting this command can replay log lines; design downstream storage for duplicates.

These are pipeline configuration fragments. Put input, pipeline, and output under config in a job with name and type: pipeline, as shown in the quickstart.

Pipeline

input:
subprocess:
name: kubectl
args:
- logs
- --all-containers=true
- --follow
- --namespace=production
- --selector=app=web-app
- --max-log-requests=10
codec: lines
restart_on_exit: true

pipeline:
processors:
- mapping: |
# Parse JSON logs if possible
root = content().string().parse_json().catch({
"message": content().string(),
"level": "info"
})
root.timestamp = now()
root.node_id = env("NODE_ID")

# Only keep ERROR and WARN logs
- mapping: |
root = if ["error", "warn", "warning", "fatal"].contains(this.level.or("").lowercase()) { this } else { deleted() }

output:
aws_s3:
bucket: edge-k3s-errors
path: 'errors/${! env("NODE_ID") }/${! timestamp_unix() }-${! uuid_v4() }.jsonl'
batching:
count: 100
period: 1m
processors:
- archive:
format: lines

What This Does

  • Parses JSON logs: Attempts to extract level field from JSON-formatted logs
  • Filters by level: Only passes through records whose level equals "error", "warn", "warning", or "fatal", ignoring case
  • Drops other logs: INFO and DEBUG logs are discarded
  • Smaller batches: 100 logs since error volume is much lower

Volume Reduction

Reduction depends on your log mix. If 2% of records have one of the selected levels, this filter retains 2% and discards 98% of records. This is illustrative, not a measured byte or storage-cost saving. Review the discarded levels before using this for production diagnostics.

Handling Non-JSON Logs

The parse_json().catch() pattern handles both JSON and plain text logs:

JSON log (parsed):

{"level": "ERROR", "message": "Database connection failed"}

Plain text log (fallback):

[2024-11-09] ERROR: Database connection failed

For plain text logs, the default level is "info", so they are discarded even when their message includes an error keyword. Add a parser for your text format before filtering if you need to retain those errors.

Level Matching

The filter compares the lowercase level field against error, warn, warning, and fatal. It does not search the message text. deleted() explicitly discards every other record.

Next Steps