Skip to main content

Eval

Data Manipulation Cribl Compatible

Synopsis

Evaluates an ordered list of field value expressions against the event, then applies Keep/Remove wildcard-based field pruning to the result. eval is the native implementation of Cribl's Eval function.

Schema

- eval:
add:
- field: <ident>
value_expression: <script>
keep: <string[]>
remove: <string[]>
filter: <script>
tag: <string>
description: <text>
if: <script>
disabled: <boolean>
ignore_failure: <boolean>
on_failure: <processor[]>
on_success: <processor[]>

Configuration

FieldRequiredDefaultDescription
addNOrdered list of field value-expression rows. Each row is evaluated in list order against the same event, so a later row's value_expression sees every field set by an earlier row.
keepNWildcard field-name allow-list. A field matching keep is never removed by remove, even if it also matches remove. Has no effect while remove is empty.
removeNWildcard field-name list. Any field matching a remove term is deleted from the event, unless it also matches keep. This is the only field that deletes anything — a keep list with no remove list removes nothing.
filterNCribl-style JavaScript truthiness expression evaluated after if. A falsy result silently skips the processor. Distinct from if, which uses the native expression language.
tagNIdentifier for this processor instance.
descriptionNExplanatory note.
ifNCondition that must be true for the processor to run.
disabledNfalseWhen true, the processor is skipped.
ignore_failureNfalseContinue pipeline processing if a value_expression fails to compile or evaluate.
on_failureNProcessors to run when this processor fails.
on_successNProcessors to run when this processor passes an event through.

Add

FieldRequiredDefaultDescription
fieldNOutput field name the row's value_expression result is assigned to. Always a single flat event-map key — even when it contains dots, hyphens, or other characters — never a nested path. Leave empty to run value_expression purely for its side effects without assigning any field (Cribl's "execution without assignment" idiom).
value_expressionYJavaScript expression, evaluated via the same engine backing filter. Bare identifiers resolve against the event's fields.

Details

eval is the native implementation of Cribl's Eval function. DataStream's Cribl-pipeline converter maps a Cribl eval block to this processor.

Processing runs in a fixed order: if (native expression language) gates the processor first, then filter (Cribl-style JavaScript truthiness) gates it second, then add is evaluated row by row in list order, and finally keep/remove pruning is applied once to the resulting field set. Because every row in add runs against the same live event, a later row's value_expression can read a field an earlier row just wrote — add: [{field: a, value_expression: "1"}, {field: b, value_expression: "a + 1"}] sets b to 2.

Two independent expression languages are in play. if is evaluated by DataStream's own native expression language, exactly like every other processor's if field — it does not go through JavaScript. filter and every value_expression in add are evaluated by a separate Cribl-compatible JavaScript engine: bare identifiers (status, srcIp) resolve directly against the event's fields, without a ctx. or event. prefix. A field name that isn't a valid JavaScript identifier — one containing a dot, hyphen, or space — cannot be referenced as a bare identifier; reference it through bracket notation on the engine's exposed event object instead, for example __e["user-agent"]. This same JavaScript engine exposes a C.* helper namespace (including C.Net, C.Text, C.Time, C.Mask, C.Encode, C.Decode, C.Lookup) to both filter and every value_expression.

When field is non-empty, its value_expression result is assigned to that exact flat key — writing undefined removes the field entirely, while writing a literal null stores null (the field still exists). Cribl's Name field supports dotted nested addressing; this processor's field does not — a field of a.b.c writes the single flat key "a.b.c", never a nested a: {b: {c: ...}}} structure. To mutate a nested object directly, leave field empty and have value_expression do it itself (for example parent.child = childValue).

remove is the only setting that deletes fields; a keep list paired with an empty remove list deletes nothing. A field matching both keep and remove is never removed — keep always wins. Both lists use the same wildcard syntax: * matches any run of characters at any position in the term (leading, trailing, or both), and a term with no * matches only by exact equality; prefixing a term with ! negates it. Within each list, terms are evaluated in order and the first term that matches a field decides its outcome — not the last — so remove: ["!foobar", "foo*"] keeps foobar but removes every other field starting with foo, while remove: ["!foo*", "*"] removes every field except those starting with foo. Fields whose name starts with __ (internal fields) can only be deleted by an exact, non-wildcard remove term; a wildcard term never touches them. A dotted term such as _raw.Timestamp is resolved as a literal nested path once the top-level pass has completed, letting remove delete a single key inside an object-valued field without disturbing the rest of it; a wildcard top-level term such as _raw* protects or removes the whole _raw field, including everything nested inside it.

A value_expression that fails to compile or evaluate fails the processor with an error of the form eval: value expression for "<field>": <error>. A malformed filter expression fails the processor immediately, the same way a malformed if does — it is not routed through on_failure or suppressed by ignore_failure.

Examples

Ordered Field Evaluation

Evaluating three fields where each expression can see the fields set before it...

{}
- eval:
add:
- field: a
value_expression: "1"
- field: b
value_expression: "a + 1"
- field: c
value_expression: "a + b"

b's expression reads the a just written by the first row, and c's expression reads both...

{
"a": 1,
"b": 2,
"c": 3
}

Undefined Removes a Field, Null Preserves It

Assigning undefined to one field and literal null to another...

{
"toRemove": "will be deleted",
"keepMe": "still here"
}
- eval:
add:
- field: toRemove
value_expression: "undefined"
- field: nullField
value_expression: "null"

toRemove is deleted outright, while nullField is created holding a literal null rather than being omitted...

{
"keepMe": "still here",
"nullField": null
}

Execution Without Assignment

Leaving field empty to mutate a nested object directly, instead of assigning a flat key...

{
"foo": {
"existing": "yes"
}
}
- eval:
add:
- value_expression: "Object.assign(foo, {merged: true})"

With no field, value_expression runs purely for its side effect and no new top-level key is assigned from its result...

{
"foo": {
"existing": "yes",
"merged": true
}
}

Keep Wins Over Remove

Pruning an event down to an allow-list with remove: ["*"], while keep protects specific fields...

{
"cribl_pipe": "p1",
"_time": 123.0,
"host": "h1",
"extra1": "drop me",
"extra2": "drop me too"
}
- eval:
keep: ["cribl_*", "_time", "host"]
remove: ["*"]

remove: ["*"] matches every field, but cribl_pipe, _time, and host also match keep and survive; extra1/extra2 match only remove and are deleted...

{
"cribl_pipe": "p1",
"_time": 123.0,
"host": "h1"
}

Gating with the Cribl filter Field

Running add only when a Cribl-style filter expression is truthy...

{
"status": "error"
}
- eval:
filter: "status == 'error'"
add:
- field: action
value_expression: "'blocked'"

filter evaluates truthy against the bare status identifier, so add runs and sets action; had status been anything else, the processor would have been skipped and the event left untouched...

{
"status": "error",
"action": "blocked"
}