Skip to content

fix(rule): template configured label values - #10

Draft
0x91 wants to merge 1 commit into
mainfrom
label-templating
Draft

fix(rule): template configured label values#10
0x91 wants to merge 1 commit into
mainfrom
label-templating

Conversation

@0x91

@0x910x91 commented Jul 14, 2026

Copy link
Copy Markdown

Configured rule labels are copied verbatim into alerts, so vmalert-style templates in label values (e.g. fluidstack_grouping_key: "Foo | {{ $labels.team }}") reach Alertmanager as literal strings; only annotations are templated. vmalert templates both, and chalert documents itself as vmalert-compatible, so any rule ported from vmalert that templates a label silently breaks.

I now run configured label values containing {{ through the same normalize+template pipeline the annotations use (legacy $labels/$value rewrite, missingkey=zero). The template sees the query row's labels before configured overrides as .Labels, matching vmalert, and the exported_ collision rule applies to the rendered value. Values without {{ take the previous verbatim path with no template parse. On parse or exec errors the raw string is kept and a warning is logged, same as annotations; templating can never drop a label or fail the evaluation loop.

Rendering happens in buildLabels, before hashLabels(), so the rendered value is the alert identity for dedup and the persisted state tables. Migration note: rules already (mis)using templates in labels change alert identity on upgrade — their literal-keyed alerts resolve and re-fire once with rendered keys. That is the intended fix.

Tested with new table-driven cases in rule_test.go: rendering from row labels (legacy and Go syntax), missing labels rendering empty rather than <no value>, parse and exec errors falling back to the raw string with evaluation still succeeding, non-templated labels passing through byte-identical, the pre-override template context with exported_ collision, and alert-ID equality between templated and literal label sets. go test ./..., go test -tags integration ./integration (ClickHouse testcontainer), go vet ./..., and gofmt are all clean. The gofmt hunk in rule/conformance_test.go fixes a pre-existing misalignment.

Configured rule labels were copied verbatim into alerts, so
vmalert-style templates in label values (e.g. "{{ $labels.team }}")
reached Alertmanager as literal strings; only annotations were
templated. vmalert templates both, and chalert documents itself as
vmalert-compatible, so any rule ported from vmalert that templates
a label silently broke.
Run configured label values containing "{{" through the same
normalize+template pipeline as annotations. The template sees the
query row's labels (before configured overrides) as .Labels,
matching vmalert; the "exported_" collision rule applies to the
rendered value. Values without "{{" take the previous verbatim
path. On parse or exec errors the raw string is kept and a warning
is logged, as for annotations.
Rendering happens in buildLabels, before hashLabels(), so the
rendered value is the alert identity for dedup and persisted state.
Rules already using templates in labels change identity on upgrade:
their literal-keyed alerts resolve and re-fire once with rendered
keys.
Also gofmt rule/conformance_test.go (pre-existing misalignment).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@0x91
0x91 marked this pull request as draft July 14, 2026 15:56
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@0x91