Log Parsing User Guide
See Log Parsing Architecture for why and when to configure parsing, and Log Parsing Configuration for the full reference for each function. This page walks through the workflow of actually writing and shipping a change, start to finish.
The general workflow
Every change to this pipeline follows the same shape, regardless of which function you’re writing:
-
Collect a representative sample line from the source you’re configuring for — copy it exactly from a real log event rather than retyping it, so you catch the actual spacing, quoting, and delimiters.
-
Choose the right function for the job — see Why configure log parsing if you’re not sure which of Grammar, Transform, or Relabel applies.
-
Build and test the pattern externally before touching Helm values — a dissect debugger or grok debugger, since this pipeline has no built-in live preview (Limitations).
-
Scope it with
conditionsso it only runs against the logs it’s meant for — see Functions and conditions. -
Pick
relabelortransformbased on what it needs to see, not where you place it —relabelalways runs before Grammar/JSON auto-parsing,transformalways after, regardless of config-list position; see Relabel, Transform priority order. -
Validate in a lower environment, then deploy with a
logs-parserHelm upgrade — there’s no hot-reload, so this is the only way the change takes effect. -
Confirm the result in the Logs Explorer against logs ingested after the rollout — see Logs Search Syntax.
The rest of this page works through that sequence for four common tasks.
Extracting structured fields from a plain-text source
Say an internal service logs lines like this, and the automatic heuristic lumps the whole thing into one generic facet:
2024-01-16T10:30:00Z ERROR Connection failed
A grok pattern with named captures gets you a ts, level, and msg facet instead:
logs-parser:
kf_parsing_config:
config: |-
- parser:
grok:
args:
- patterns:
- '%{TIMESTAMP_ISO8601:ts} %{LOGLEVEL:level} %{GREEDYDATA:msg}'
conditions:
- matcher: "#source"
value: "my-internal-service"
op: "=="
Test the pattern against a real sample line in a grok debugger first, confirming each named group captures what you expect, before adding the conditions block and deploying. See Grammar: dissect and grok patterns for when to reach for dissect instead — it’s faster and simpler for a fixed-delimiter format.
Promoting a facet to a filterable label
Once a facet is extracted (by Grammar, above, or by JSON auto-parsing), it’s searchable but not a first-class, always-indexed field. If you find yourself filtering or grouping dashboards by a facet often enough that it deserves to be a label, promote it with transform:
logs-parser:
kf_parsing_config:
config: |-
...
- transform:
args:
- action: "facet_to_label_map"
- sourceLabels: "@eventSource"
- targetLabel: "source"
conditions:
- matcher: "#source"
op: "=="
value: "awsLogSource"
Use transform here, not relabel — transform always runs after extraction, so eventSource is already a facet by the time this rule evaluates, regardless of where you place it in the config list; relabel would run too early to see it. See Promote facets sparingly before doing this for every facet you extract.
Tagging every log from one source with a fixed label
To mark every log from a given source with a constant value — an environment, a team, a tier — use relabel’s `replace action with a regex that always matches:
logs-parser:
kf_parsing_config:
config: |-
- relabel:
args:
- action: "replace"
- regex: ".*"
- replacement: "production"
- targetLabel: "env"
conditions:
- matcher: "#source"
value: "my-internal-service"
op: "=="
Without the conditions block, this would tag every log line the pipeline processes with env=production — see Scope every function with conditions.
Dropping noisy log lines you don’t want indexed
A source emitting high-volume, low-value lines — health-check pings, synthetic monitoring noise — can be excluded entirely with the drop action. If the condition depends on a facet your own config extracts (here, path from an earlier Grammar step or JSON auto-parsing), write it as transform, not relabel — relabel always runs before extraction and would never see path, regardless of where you place it in the list:
logs-parser:
kf_parsing_config:
config: |-
- transform:
args:
- action: "drop"
- sourceLabels: "@path"
- regex: "/healthz"
See Relabel, Transform priority order for why the choice between the two keywords matters here. Because drop is irreversible once deployed, test the condition’s regex against real sample lines first, and read Drop and keep are destructive actions before shipping it.
Next steps
-
Log Parsing Configuration — the full configuration reference
-
Log Parsing Best Practices — guidance for writing config that stays precise and cheap to query
-
Log Parsing Troubleshooting — diagnosing a pipeline that isn’t doing what you expect