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
levelfield 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
- Multiple Destinations: Send filtered logs to multiple systems
- Best Practices: Learn about efficient filtering strategies
- Mapping Processor: Component reference