LogsQL Typed AST β Architecture Reference
Overviewβ
internal/logsql provides a typed AST, recursive-descent parser, capability-aware builder, and version gating for VictoriaLogs LogsQL queries. It mirrors the structure of internal/logql (the existing LogQL parser) and targets VictoriaLogs v1.40 and later.
The package is used in two modes:
- Direct construction β callers assemble
logsql.Exprnodes with the builder API and callString()to emit the final query. - Parse + re-emit β callers parse an existing LogsQL string into an AST, inspect or transform nodes, and re-emit via
String().
Package Structureβ
| File | Responsibility |
|---|---|
ast.go | All typed AST nodes β interfaces, filter nodes, pipe stages, stats functions |
scanner.go | Lexer β tokenises LogsQL syntax |
parser.go | Recursive-descent parser β Parse(string) (*Query, error), ParseFilter(string) (FilterExpr, error) |
capabilities.go | Capabilities struct, CapabilitiesFor(semver string) Capabilities |
builder.go | Builder API β NewQuery(), NewBuilder(caps), constructor helpers, BestTopN(), BestIPv4Range() |
AST Node Hierarchyβ
Parser Flowβ
Query Construction Flowβ
VictoriaLogs Version Capability Matrixβ
The package targets v1.40 minimum. All features in the v1.40 baseline are always available.
| Version range | Feature additions |
|---|---|
| v1.40βv1.43 | Baseline: PipeHits, PipeRunning, PipeBlock, PipeUniq, PipeTop, StatsHistogram |
| v1.44 | rate_sum() stats function (Capabilities.StatsRateSum) |
| v1.45βv1.48 | ipv4_range() field filter (Capabilities.FieldIPv4Range) |
| v1.49 | Metadata substring filter (Capabilities.MetadataSubstring) |
| v1.50+ | Dense pattern windowing (Capabilities.DensePatternWindowing) |
CapabilitiesFor(semver) is called once at proxy startup from storeBackendVersion(). Unsupported versions (pre-v1.40, malformed) return a zero Capabilities (all false), which is the safest possible degraded state.
FieldOp Referenceβ
| Constant | LogsQL syntax | VL version |
|---|---|---|
FieldOpExact | field:="value" | v1.40+ |
FieldOpRegexp | field:~"pattern" | v1.40+ |
FieldOpPrefix | field:prefix* | v1.40+ |
FieldOpSubstring | field:*sub* | v1.40+ |
FieldOpEmpty | field:"" | v1.40+ |
FieldOpAny | field:* | v1.40+ |
FieldOpGT | field:>val | v1.40+ |
FieldOpGTE | field:>=val | v1.40+ |
FieldOpLT | field:<val | v1.40+ |
FieldOpLTE | field:<=val | v1.40+ |
FieldOpRange | field:range(min,max) | v1.40+ |
FieldOpIn | field:in(a,b,c) | v1.40+ |
FieldOpIPv4Range | field:ipv4_range(first,last) | v1.45+ |
Integration Pathβ
Typed AST-to-AST translator (internal/logql/translate.go)β
Translate(expr Expr, opts TranslateOptions) (string, error) is a second, typed translation path that maps LogQL AST nodes directly to internal/logsql types β no String() roundtrip through the LogQL printer.
TranslateOptions carries three fields:
LabelFn func(string) stringβ optional label-name rewriter (e.g. OTel dottedβunderscore)StreamFields []stringβ fields declared as stream labels; routed toFilterExprinstead of pipesCaps *logsql.Capabilitiesβ gates VL version-specific constructs
Node mapping:
| LogQL node | LogsQL output |
|---|---|
*LogQuery | FilterExpr + []Pipe via stream selector + pipeline stages |
*StreamSelectorExpr | logsql.FilterExpr (label matchers) |
*LineFilterStage | logsql.PipeFilter |
*LabelFilterStage | logsql.PipeFilter (label conditions) |
*JSONParserStage | logsql.PipeUnpackJSON |
*LogfmtParserStage | logsql.PipeUnpackLogfmt |
*RegexpParserStage | logsql.PipeExtractRegexp |
*DropStage (bare labels) | logsql.PipeDelete |
*KeepStage (bare labels) | logsql.PipeKeep |
*LineFormatStage (simple) | logsql.PipeFormat |
*RangeAggregation, *VectorAggregation, *BinOpExpr, *OpaqueMetricExpr | errFallthrough β delegate to existing string translator |
errFallthrough is a package-private sentinel error. When returned, callers fall back to the existing translator.TranslateLogQLWithCapabilities string path unchanged β metric nodes are not yet handled by the typed path and route to the existing Tier 1/2 translators.
The proxy's main translation path (translator.TranslateLogQLWithCapabilities) is unchanged. logql.Translate is wired but not yet called by handlers; handler migration is planned for a follow-on PR.
Builder integration pathβ
Once the AST-to-AST path is wired to handlers, the full pipeline becomes:
logql.Translate(expr, opts)maps LogQL AST βlogsqlAST- Builder's
Build*methods returnlogsql.FilterExpror[]logsql.Pipe logsql.NewQuery(filter, pipes...)assembles the full ASTq.String()emits the final LogsQL query at the HTTP boundary
Test Coverage Summaryβ
| File | Tests | Coverage focus |
|---|---|---|
ast_test.go | 84 | All String() methods |
scanner_test.go | 12 | Token stream, quoted strings, raw strings |
capabilities_test.go | 13 | Version matrix, edge cases |
builder_test.go | 10 | Direct construction, BestTopN, BestIPv4Range |
parser_test.go | 38 | Round-trip (25 cases), ParseFilter, error cases, stats funcs |
edge_cases_test.go | ~110 | All FieldOps, nesting, boundary versions, malformed semver |
fuzz_test.go | 4 fuzz | Never panics on arbitrary input |
translate_test.go | 17 | Translate(): stream selectors, line/label filters, parsers, drop/keep/lineformat, errFallthrough for metric nodes |
| Total | 299 |
Design Notesβ
internal/logsql is built in three layers:
- Typed AST (
ast.go) β 30+ node types whoseString()methods emit valid LogsQL - Parser (
scanner.go+parser.go) β recursive-descent parser that round-trips what the translator emits - Capability-aware builder (
capabilities.go+builder.go) β selects the best LogsQL construct for the detected VL version
Callers import the package and construct queries using the builder API. The minimum supported VictoriaLogs version is v1.40.