JavaScript
Set lang: javascript (or js) on the Script processor to run a
JavaScript body against each event.
- script:
lang: js
source: |
__e.user = __e.user.toLowerCase();
The engine is a sandboxed interpreter embedded in the Director. It is not Node.js: there is no module system, no file system, no network, and no timers.
Two Forms
The same engine compiles two different things, and the difference decides how the code is written.
| Form | Used by | Grammar |
|---|---|---|
| Script | The Script processor's source | Full statements, loops and function declarations. Runs in strict mode. Fields are reached through __e explicitly. Nothing is returned. |
| Expression | The Script processor's filter, and Eval field values | A single expression. Bare field names resolve against the event. The value is returned automatically. |
A script body is wrapped in a function and invoked once per event, so a return statement is legal but
its value is discarded. All output is written to the event.
A script reaches fields explicitly... | |
An expression does not, and needs no | |
The Event
__e is the event. It is a live handle, not a copy — an assignment reaches the event immediately, and
there is no commit step.
| Operation | Syntax |
|---|---|
| Read a field | __e.status |
| Read a field whose name contains a dot | __e['source.ip'] |
| Write a field | __e.status = 'ok' |
| Delete a field | delete __e.status, or __e.status = undefined |
| Test for a field | __e.status !== undefined |
Assigning undefined deletes the field rather than storing the value. Assigning null stores a null.
__e exposes the event's top-level keys. A field holding an object behaves like an ordinary JavaScript
object, so __e.user.name = 'j' works and modifies the event, but the enclosing object must already
exist — create it first where it might not.
A field that is not present reads as undefined, so a missing field never throws on read.
__e is the only name bound to the event. Scripts written for other platforms may use event or
__pack; neither exists here.
Parameters
Values under params are available to the script as a params object:
- script:
lang: js
params:
threshold: 70
allowed: ["web-01", "web-02"]
source: |
__e.high = __e.score > params.threshold;
__e.known = params.allowed.includes(__e.host);
params is a fresh deep copy on every event, nested values included. A script may write to it, but
those writes are discarded when the event finishes — params cannot carry a value from one event to
the next. With no params block it is an empty object, never undefined, so reading a key that was
never configured yields undefined rather than throwing.
Function Library
The engine ships a library of helper functions under a C namespace — network tests, text parsing,
time formatting, masking, hashing, encoding and CSV lookups. Each group has its own page:
| Group | Covers |
|---|---|
| Network | C.Net — CIDR matching, address classification, Community ID |
| Text | C.Text — entropy, hashing, XML and Windows Event parsing |
| Time | C.Time — parsing, formatting, time zones, partitioning |
| Masking | C.Mask — redaction, Luhn, digests, and C.Crypto.createHmac |
| Encoding | C.Encode, C.Decode — Base64, gzip, deflate, hex, MIME, URI |
| Lookups | C.Lookup and its CIDR, regex and case-insensitive variants |
| Context | C.Misc, C.vars, C.env, C.os, version values and logging |
The C namespace is frozen. Assigning to it, or to any function inside it, has no effect.
Restrictions
Script bodies run in strict mode. The practical consequences:
- Assigning to a name that was never declared throws. Declare locals with
letorconst. - The value of
thisat the top level isundefined, not a global object.
Beyond strict mode, the runtime is hardened so that one event's script cannot affect another's:
- New global variables cannot be created. An attempt is silently ignored.
globalThisisundefined.- The prototypes of the built-in types —
Object,Array,String,Number,Function,RegExp,Date,Errorand the rest — are frozen, so they cannot be extended or patched. - There is no
require, noimport, and noconsole. Usedebug()orC.log()to emit a message.
Math, JSON, Date, RegExp, Map, Set, Promise, Proxy and BigInt are all available and
behave normally. Regular expressions use JavaScript syntax and semantics.
Limits
A single script gets one second of wall-clock time per event. Exceeding it fails the processor with a timeout error. The budget is fixed and cannot be raised from the pipeline configuration.
There is no cap on allocation or iteration count — the time budget is the only bound, so a script that builds an unbounded structure runs until the second expires.
Scripts hold no state between events. Each event gets a fresh invocation, and because new globals cannot be created there is no place to keep a running total. Use the Cache Set and Cache Get processors where a value has to survive across events.
Failure Behavior
A script that throws stops at the point of the throw. Fields it already modified stay modified — writes reach the event as they happen, so there is no rollback.
The event itself continues down the pipeline. The processor records the failure in the
_ingest.on_failure_* fields and runs its on_failure
chain; setting ignore_failure: true suppresses both and lets the partially modified event pass
silently.
Where a script performs several related writes, guard the whole body so a failure cannot leave the event half-updated:
Validate before writing anything... | |
Compilation
Each distinct source string is compiled once per pipeline and reused for every event that
reaches it. Two processors in the same pipeline with byte-identical source share the compiled result.
The cache is per-pipeline, not process-wide, so the same script used in two pipelines is compiled twice. This is where the two engines differ: the Go engine's compiled scripts are shared across every pipeline in the process.