Compiled Rules
contains pre-compiled quicktemplate rules linked into the korrel8r executable.
Compiled rules are the performance and type-safety alternative to configuration-file rules (see github.com/korrel8r/korrel8r/pkg/rules). Both types use the same YAML rule-metadata schema and produce the same result: a rule linking start classes to goal classes, applied to a start object to generate goal queries.
Quick Rules vs Configuration Rules
Quick rules (*.qtpl):
- Compiled into the binary.
- Require rebuild (make generate + build) to change.
- Use quicktemplate syntax; {% code %} blocks run type-checked Go.
- Best for: hot paths, complex Go logic.
Configuration rules (YAML):
- Loaded from YAML files at runtime; no rebuild needed.
- Use Go text/template syntax.
- Best for: quick changes, user-installed rules.
Writing a Quick Rule
A rule is a {% func %} template preceded by a YAML annotation. The annotation describes the rule graph metadata; the function body generates the goal query. Together they look like this in a *.qtpl file:
# MetricToPod creates a k8s Pod query from the pod labels of a metric.
name: MetricToPod
start:
domain: metric
classes: [metric]
goal:
domain: k8s
classes: [Pod]
{% func MetricToPod(o interface{}) %}
{% code
m := o.(metric.Object)
ns := Default(m.Labels["namespace"], m.Labels["k8s_namespace_name"])
name := Default(m.Labels["pod"], m.Labels["k8s_pod_name"])
RequireAll(ns, name)
%}
k8s:Pod:{"namespace":{%q= ns %},"name":{%q= name %}}
{% endfunc %}{% func RuleName(o interface{}) %} receives the start object. Use a type assertion in a {% code %} block to access domain-specific fields.
Template Body
The function body writes goal query strings to the output; each non-blank line becomes one goal query. Supported constructs:
- {% code %} -- an arbitrary Go block (type assertions, label lookups, loops).
- {%q= x %} -- writes x JSON-quoted, for safely embedding values in a query.
- {%= x %} -- writes x (HTML-escaped).
- Fail -- panics with a formatted message, aborting rule execution.
- A blank (whitespace-only) output means the rule does not apply.
Error Handling
Rule execution recovers from panics, so panic is the correct way to signal that a rule cannot apply. Use Fail for an explicit message, or let Go’s normal runtime panics (nil dereference, bad type assertion, etc.) abort execution. There is no need to defensively check for these errors when the intended outcome is simply to skip the rule.
Helper functions for error handling:
- Fail(format, args…) -- panic with a formatted error.
- Require(v) -- return v if non-empty, panic otherwise.
- RequireAll(values…) -- panic if any value is empty.
- Empty(v) -- true if v is nil, false, zero, or zero-length.
- Default(dflt, v) -- return v if non-empty, else dflt.
- ToJSON(v) -- serialize v to JSON, panic on error.
Imports
Templates may import Go use inside {% code %} blocks. Rule templates typically import the start-object’s domain package (for type assertions) and pkg/rules (for Fail):
{% %}
{% import "github.com/korrel8r/korrel8r/pkg/domains/metric" %}
{% import "github.com/korrel8r/korrel8r/pkg/rules" %}YAML Annotation
The bare text between two template-tag blocks is a YAML descriptor for the following rule, using the same schema as a configuration-file rule (see github.com/korrel8r/korrel8r/pkg/config). At startup Rules parses the annotations from the embedded *.qtpl source and verifies that:
- Every rule has a name that matches its {% func %} name exactly.
- Rule names are unique across all *.qtpl files.
- start and goal each specify a domain (classes are optional).
YAML comments (#) may be used anywhere in the metadata.
Directory Layout
- *.qtpl -- Quicktemplate rule sources. Edit these.
- *.qtpl.go -- Generated by qtc. Do not edit.
- applyfuncs.go -- Generated applyFuncs map. Do not edit.
- doc.go -- (this file).
- helpers.go, k8s_helpers.go -- Shared helper functions for templates.
Compiling
make generate compiles every *.qtpl with qtc (producing *.qtpl.go) and regenerates applyfuncs.go from the {% func %} declarations:
make generate # also runs from 'make lint'
go build ./...Never edit the generated files by hand.
Testing
Add table-driven cases to quickrules_test.go (a start object in, the expected goal query strings out):
go test ./pkg/rules/quickrules/Loading
Rules returns the pre-compiled rules for a set of domains. The korrel8r CLI adds them to every engine (see cmd/korrel8r/main.go) alongside configuration rules, so a compiled rule takes effect as soon as it is linked in.