Extends the FilterBar query language with a json[field] <op> value comparison, parsed by filter_parser.pest/rs alongside metric[param], and evaluated in engine.rs by parsing each line as JSON at query time (lines that aren't valid JSON, or lack the field, simply don't match). Also wired into alerts.rs since json[field], like regex/sequence/ timestamp, only needs the line's own text. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XFUNZwCvz3kcod3352ZR2o
49 lines
1.9 KiB
Plaintext
49 lines
1.9 KiB
Plaintext
// Grammar for the FilterBar query language.
|
|
//
|
|
// Supports:
|
|
// - regex("...") raw-text regex search over log lines
|
|
// - metric_name[param] <op> value metric comparisons
|
|
// - json[field] <op> value JSON field comparisons (line parsed as JSON)
|
|
// - sequence <op> value reserved metric name (no [param])
|
|
// - timestamp <op> value reserved metric name (no [param])
|
|
// - `and` / `or` boolean combinators, with `and` binding tighter than `or`
|
|
// - parenthesized sub-expressions
|
|
|
|
WHITESPACE = _{ " " | "\t" | "\n" | "\r" }
|
|
|
|
file = { SOI ~ or_expr ~ EOI }
|
|
|
|
or_expr = { and_expr ~ (or_kw ~ and_expr)* }
|
|
and_expr = { term ~ (and_kw ~ term)* }
|
|
|
|
term = _{ regex_expr | comparison | "(" ~ or_expr ~ ")" }
|
|
|
|
// These must be atomic (`@`): a non-atomic rule would let pest's implicit
|
|
// whitespace insertion slip in between the keyword and its own boundary
|
|
// check below, which breaks the lookahead (it would see the first
|
|
// non-whitespace character *after* skipping the separating space, instead
|
|
// of the character immediately following the keyword).
|
|
and_kw = @{ "and" ~ !(ASCII_ALPHANUMERIC | "_") }
|
|
or_kw = @{ "or" ~ !(ASCII_ALPHANUMERIC | "_") }
|
|
|
|
regex_expr = { "regex" ~ "(" ~ string_literal ~ ")" }
|
|
|
|
string_literal = ${ "\"" ~ inner_str ~ "\"" }
|
|
inner_str = @{ (escaped_char | !("\"" | "\\") ~ ANY)* }
|
|
escaped_char = @{ "\\" ~ ANY }
|
|
|
|
comparison = _{ json_comparison | metric_comparison }
|
|
|
|
// `json[field] <op> value` must be tried before `metric_comparison` since "json" is
|
|
// otherwise a syntactically valid (if never declared) metric name.
|
|
json_comparison = { "json" ~ "[" ~ param ~ "]" ~ op ~ value }
|
|
metric_comparison = { metric ~ ("[" ~ param ~ "]")? ~ op ~ value }
|
|
|
|
metric = @{ ident }
|
|
param = @{ ident }
|
|
ident = @{ (ASCII_ALPHANUMERIC | "_")+ }
|
|
|
|
op = { "<=" | ">=" | "==" | "!=" | "<" | ">" }
|
|
|
|
value = @{ (!(WHITESPACE | ")") ~ ANY)+ }
|