Parser Extensions
Customize OOTB parsers per log source with a small VRL overlay — without forking the base parser.
Parser Extensions
A parser extension is a small VRL overlay attached to a single log source. It runs as an extra Vector transform chained between the OOTB parser's parse step and its output step. Use it to add a field, normalize a value, or drop a noisy event for one tenant or one feed — without forking the OOTB parser and losing upgrades.
When in doubt, extend, don't fork. Extensions let you keep pulling improvements to the OOTB parser while your customization rides on top. Forking — even AI-assisted "rewrite the whole parser" — leaves you on a divergent copy that has to be re-merged every time the base parser ships an update.
What an Extension Is
An extension is a VRL transform that runs after the OOTB parser has already produced the canonical UDM shape (.udm.*, .metadata.*, .ext, .message, .source_type) and before the output flatten step that prepares the event for ClickHouse.
Because the extension sits between _parse and _output, it sees the same .udm.* shape the parser produced — you can set, override, or delete UDM fields directly, and the flatten step still runs uniformly afterward.
Common Use Cases
| Goal | Example |
|---|---|
| Add a tenant field | .udm.team = "soc" |
| Normalize a value | .udm.action = downcase!(.udm.action) |
| Drop noisy events | if .udm.action == "heartbeat" { abort } |
Enrich from .ext | .udm.user = .ext.principal_id ?? .udm.user |
| Mask sensitive content | .message = replace!(.message, r'\d{16}', "[REDACTED]") |
What Extensions Are Not For
- Replacing the OOTB parser. If the base parser is structurally wrong for your logs (different format, different vendor variant), generate a new parser from samples instead — that's still the right tool for the job.
- Cross-source logic. Extensions are per-log-source. Logic that spans sources belongs in detection rules or enrichment.
- Stateful processing. Extensions are stateless transforms — no aggregation, no joins, no lookups against other events.
The Stub Case (No OOTB Parser)
If the log source's parser_vrl is empty and the extension is enabled, the extension is the parser for that source type. The pipeline skips the _parse stage entirely and the extension consumes from the router directly:
The Extension tab makes this explicit — when no OOTB parser exists for the source type, the read-only base pane shows a "your extension will be the parser" hint and you author the full transform there.
Authoring an Extension
Walkthrough
- Open the log source at Feeds → select source → log-source detail page
- Click the
Extensiontab (betweenVRL editorandDeployments) - Write the overlay. The top pane shows the OOTB parser read-only; the bottom pane is your editable VRL. The AI sidebar accepts natural-language edits — it's pinned to "only emit the extension, don't touch the base parser"
- Test with a sample event. The Test button runs
parser_vrl → extension_vrlagainst your sample and shows the final event shape — exactly what would land in ClickHouse - Enable the toggle, Save the draft, then Publish + Deploy from the page header to push to Vector
Save vs. Publish. Save updates your working draft; the live Vector instance keeps running the previously published extension. To push the change live, click Publish on the page header to create a new version and deploy.
Worked Example: Tag CloudTrail with a Team
You manage two AWS accounts — production and analytics — and want every CloudTrail event tagged with the responsible team so dashboards and detections can filter cleanly.
-
Open the
aws_cloudtrail_prodlog source → Extension tab -
Write:
if .udm.cloud_account_id == "111111111111" { .udm.team = "platform" } else if .udm.cloud_account_id == "222222222222" { .udm.team = "data" } -
Paste a sample CloudTrail event into the Test panel and click Test — confirm
teamappears in the output -
Toggle Enabled → Save → Publish from the page header
The OOTB CloudTrail parser keeps running unchanged. Your team tag rides on top.
Worked Example: Drop a Noisy Health Check
A firewall feed includes health-check pings that double your event volume but never trigger detections:
if .udm.action == "allow" && .src_ip == "10.0.0.5" && .dest_port == 443 {
abort
}abort in VRL halts the transform and drops the event before it reaches the combiner. The OOTB parser still processes everything else.
Validation — Three Gates
Invalid extension VRL never reaches a running Vector. nano enforces three independent layers:
| Gate | What it catches |
|---|---|
| Publish-time | When you click Publish, the server runs validate_vrl on both the parser and the extension. Syntax errors, unbalanced braces, and blocked functions (get_env_var, http_request, dns_lookup, etc.) reject the publish — the previous version stays live and the error message names the offending transform. |
| Combined-chain test | The Test button on the Extension tab runs the full parser_vrl → extension_vrl chain against your sample event before you publish. Field-name mismatches with the upstream parser surface immediately, so you can catch them in the draft loop. |
| Deploy-time | Vector's own vector validate runs against the staged config after publish; on any failure the previous version stays live and the UI shows a deploy-failure status. |
The AI sidebar re-validates every suggestion before returning it, so accepted suggestions are almost always already publish-clean. Save persists your draft as-is; the validation gates fire when you publish.
Version History
Extensions piggyback on the same publish/version flow as the base parser:
- Each Publish snapshots both
parser_vrlandextension_vrlinto a new version - The Versions tab diff shows changes to either
- Revert restores both fields to the chosen version's snapshot — you don't have to revert parser and extension separately
Sampling Interaction
Extensions run before the optional sample transform, so an enabled extension applies to every event before sampling decisions. A normalization or enrichment in the extension is visible to the sampling exclude condition, which means you can write rules like:
.udm.criticality = if .src_ip == "10.0.1.5" { "high" } else { "low" }and then exclude criticality == "high" from sampling on the Configuration tab.
Limitations (v1)
- One extension per log source. Stacking multiple extensions with explicit ordering will come later — for now, compose your logic in a single transform.
- VRL only. No declarative shorthand for common cases like "add a constant field." Use VRL with one-line assignments.
- No conflict lint. If you set
.udm.userin your extension and a future OOTB parser update also sets it, the extension wins (it runs second). Watch the Versions diff when pulling parser updates. - No cross-source library. Each log source's extension is its own artifact; copy-paste between sources for now.
Related
- Data Ingestion — feed onboarding, AI parser generation, publish flow
- Supported Data Sources — which sources support
source_typenatively - UDM Fields — canonical field names available in extensions