Skip to main content

Go

Set lang: golang (or go) on the Script processor to run a script against each event through a sandboxed bytecode VM.

- script:
lang: go
source: |
text := import("text")
event.host = text.to_lower(event.host)
warning

This is a Go-like scripting language, not Go. The syntax is familiar — :=, if, for, func, maps and slices — but the Go standard library is not available, and neither are packages, goroutines, channels, structs, interfaces or pointers. A script is a bare sequence of statements: there is no package clause and no main function.

The Event

The event is bound to a global named event, a map keyed by field name:

- script:
lang: go
source: |
if event.bytes > 0 {
event.kilobytes = event.bytes / 1024
}
OperationSyntax
Read a fieldevent.status
Read a field whose name contains a dotevent["source.ip"]
Write a fieldevent.status = "ok"
Delete a fielddelete(event, "status")
Test for a field!is_undefined(event.status)

A field that is not present reads as undefined.

The script receives a converted copy of the event and the result is written back after the script finishes successfully. A script that fails, or that exhausts its time budget, leaves the event exactly as it arrived — see Failure Behavior.

Replacing event with anything other than a map fails the processor. So does building a structure that refers back to itself.

Parameters

Values under params are available as a params map:

- script:
lang: go
params:
threshold: 70
source: |
event.high = event.score > params.threshold

params is a fresh copy on every event. Writes to it are discarded when the event finishes.

Modules

Five modules are available through import:

ModuleProvides
textString manipulation, regular expressions, conversion
mathNumeric functions and constants
timesDurations, formatting, date arithmetic
jsonencode, decode, and their indented variants
randPseudo-random numbers

Import each one before use:

- script:
lang: go
source: |
text := import("text")
json := import("json")
parsed := json.decode(event.payload)
event.user = text.to_lower(parsed.user)

Two functions are deliberately withheld:

  • times.sleep is removed. A sleeping script would hold a pipeline worker for its full duration without the time budget being able to interrupt it. Calling it fails the script.
  • json.encode is replaced with a version that rejects self-referential and excessively nested input rather than recursing until the process runs out of stack.

Importing any other module — or importing a file from disk — is not possible.

The built-in string() conversion is also replaced with a guarded version. It behaves the same way on ordinary values.

Limits

ConstraintValue
Time budget per event50 milliseconds
Maximum source size64 KiB
Allocation cap50,000 objects
Constant pool1,000 entries

All four are fixed and cannot be changed from the pipeline configuration. The time budget is substantially tighter than the JavaScript engine's one second, which makes this engine a poor choice for anything that iterates over a large collection.

A script that exceeds the allocation cap fails with an allocation-limit error rather than consuming memory. A source body over 64 KiB is rejected before it is compiled.

Scripts hold no state between events. Use the Cache Set and Cache Get processors where a value has to survive across events.

Failure Behavior

The engine writes back to the event only after the script has run to completion. A script that fails partway through changes nothing — a compile error, a runtime error, an allocation-limit breach and a timeout all leave the event exactly as it arrived.

This is the opposite of the JavaScript engine, which writes to the event as the script runs and so leaves partial modifications behind when a script throws.

The event continues down the pipeline either way. The processor records the failure in the _ingest.on_failure_* fields and runs its on_failure chain, unless ignore_failure is set.

Compilation

Each distinct source string is compiled to bytecode once and reused for every event that reaches it, across every pipeline that happens to contain the identical text.

Examples

Derive a transport name from a port...

{
"destination.port": 443,
"host": "WEB-01"
}
- script:
lang: go
source: |
text := import("text")
event.host = text.to_lower(event.host)
if event["destination.port"] == 443 {
event["network.protocol"] = "https"
}

The event is written back once the script completes...

{
"destination.port": 443,
"host": "web-01",
"network.protocol": "https"
}

Parse an embedded JSON payload and promote two of its fields...

- script:
lang: go
source: |
json := import("json")
parsed := json.decode(event.payload)
if !is_error(parsed) {
event.user = parsed.user
event.action = parsed.action
}