Support for CEL - #267
Open
mrueg wants to merge 1 commit into
Open
Conversation
Member
Author
|
@SuperQ @rustycl0ck any thoughts on this? Would love to get some early feedback to see if this is something you'd be interested in adding. |
|
Thanks a lot for this MR, just tested this branch and it seems to work fine. We used: This should potentially solve a lot of related issues that need a bit more advance logic, such as: Please add a bit of documentation, then it would be perfect 🚀 |
Member
Author
|
@sbor23 thanks for testing it! I still need to figure out a couple of things here, I have updated the original messages |
mrueg
force-pushed
the
add-cel
branch
2 times, most recently
from
November 16, 2023 14:07
75a0c7e to
72ab3d8
Compare
Member
Author
|
I went ahead with the engine field solution |
mrueg
force-pushed
the
add-cel
branch
2 times, most recently
from
November 16, 2023 21:46
5a26a4a to
bdc4eb9
Compare
mrueg
force-pushed
the
add-cel
branch
2 times, most recently
from
March 27, 2024 19:49
d0c9753 to
5f61823
Compare
mrueg
force-pushed
the
add-cel
branch
2 times, most recently
from
November 6, 2024 22:05
e4fa7aa to
d4ad336
Compare
|
@mrueg any reason this still has WIP in the title? Any chance it can be reviewed and merged? |
Metrics can select 'engine: cel' to be scraped with CEL (Common Expression Language) instead of JSONPath. The engine is chosen per metric and applies to its path, labels, values and epoch timestamp, so both engines can be mixed within a module. The members of the scraped document are bound as variables, and the document itself is bound as 'root', which is what makes documents that are not JSON objects, such as a top-level list, reachable. Expressions are parsed once and their programs cached, and they are compiled when the metric list is built, so '--config.check' reports a broken expression instead of every scrape doing so. Unknown engines are rejected when the config is loaded. Values are rendered to match the JSONPath engine: a null becomes NaN, and whole numbers are formatted without an exponent. 'allow_missing_key' covers CEL as well, where it skips the metric for an unknown member, an unknown key or an index out of bounds. Also make 'epochTimestamp' take effect: yaml.v2 keyed the field as 'epochtimestamp', so the documented spelling was silently ignored. Both spellings are accepted now, and SanitizeIntValue parses the exponent notation the JSONPath engine renders large numbers in, which is what kept timestamps from working there. The CEL value to JSON conversion is adapted from https://github.com/google/cel-go/blob/cfbf821f1b458533051306305a39b743db7c4bdb/codelab/codelab.go#L274 (Apache-2.0 Licensed) Signed-off-by: Manuel Rüger <manuel@rueg.eu>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This adds support for queries using the Common Expression Language (CEL), as an alternative to JSONPath.
See: #263
Config format
Resolved in favour of selecting an engine for the query, rather than adding a parallel set of
cel/labels_celfields:The engine is chosen per metric and applies to all of its expressions —
path,labels,valuesandepochTimestamp— so both engines can be mixed freely within a module. Unknown engines are rejected when the config is loaded.How expressions are evaluated
The members of the scraped document are bound as variables, so
.counterandcounterboth select a top-level member. The document itself is additionally bound asroot, which is what makes documents that are not JSON objects reachable at all — a top-level list is scraped withpath: 'root'. A member actually namedrootshadows that binding.Expressions are parsed once and their programs cached, instead of building a CEL environment for every value, label and scrape. They are compiled when the metric list is built, so a broken expression is reported by
--config.checkrather than by every scrape. Expressions are deliberately not type-checked, since the shape of the scraped document is only known at scrape time; a member the document does not contain is reported when the expression is evaluated.Values are rendered to match the JSONPath engine: a JSON
nullbecomesNaN, and whole numbers are formatted without an exponent.allow_missing_keycovers CEL as well, where it skips the metric for an unknown member, an unknown key or an index out of bounds, while any other evaluation error (e.g. a type mismatch) is still reported.Also in this PR:
epochTimestampnever took effectyaml.v2derives the key from the lowercased field name, so it looked forepochtimestampand silently ignored theepochTimestampspelling thatexamples/config.ymland the docs use. The field has an explicit tag now, and a customUnmarshalYAMLkeeps accepting the all-lowercase spelling so existing configs do not regress.That alone was not enough to make the feature work with JSONPath: a JSON number decodes to a
float64, which renders as1.657568506e+09once it grows large enough, andSanitizeIntValuecould not parse that. It now accepts float-formatted integers, so timestamps work on both engines.The timestamped examples were object scrapes reading a top-level timestamp, which cannot work — the timestamp is looked up in the same document as the value. They are value scrapes now, and
examples/data.jsonuses milliseconds, which is whattime.UnixMilliexpects. The README states the unit.Tests
exporter/cel_test.go: expression evaluation (member access,root, macros, nulls, large integers, top-level arrays and scalars, JSON output),allow_missing_keybehaviour, program caching, and error cases.test/config/good-cel.yml: a CEL translation ofgood.yml, asserted against the same golden response, so both engines are shown to produce identical output.test/config/allow_missing_key.yml: CEL modules added to the existing table.exporter/util_test.go:SanitizeIntValuecoverage, including the exponent notation above.Dependencies
Uses
cel.dev/cel-go v0.32.0. Note that cel-go renamed its module path fromgithub.com/google/cel-gotocel.dev/cel-goin that release.