transform

package
v0.84.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 31, 2026 License: BSD-3-Clause Imports: 10 Imported by: 0

README

Transform plugin

It transforms events with programs written in a small expression language. A single transform action can rename, reshape, parse and delete fields — work that otherwise takes a chain of single-purpose actions.

Example:

pipelines:
  example_pipeline:
    ...
    actions:
    - type: transform
      source: |
        # parse lines like "INFO 2025-05-25 11:11:11,222 [shard 1] compaction - done"
        m = capture(.log, r'^(?P<level>\S+)\s+(?P<time>\S+ \S+)\s+\[(?P<shard>[^\]]+)\]\s+(?P<operation>\S+)\s+-\s+(?P<message>.+)$')
        if m != null {
          .level = m.level
          .time = m.time
          .shard = m.shard
          .operation = m.operation
          .message = m.message
          del .log
        }
    ...

The event {"log":"INFO 2025-05-25 11:11:11,222 [shard 1] compaction - done"} becomes:

{
  "level": "INFO",
  "time": "2025-05-25 11:11:11,222",
  "shard": "shard 1",
  "operation": "compaction",
  "message": "done"
}

The program is compiled once at pipeline start; an invalid program fails fast at startup. A runtime error (e.g. a type error on a particular event) stops the program for that event only: the error is logged and the event continues down the pipeline, keeping the fields that were set before the error.

Config params

source string

The transformation program executed for every event. See the language reference and the list of built-in functions below.


Language

A program is a list of expressions executed top to bottom for every event. Expressions are separated by newlines, or by ; when written on one line. Comments start with # and last to the end of the line.

Event fields

Paths address fields of the current event and always start with a dot:

.level                    # top-level field
.user.name                # nested field
."key with spaces"        # quoted field name
.items[0]                 # array element
.items[-1]                # array element, counted from the end
.items[i]                 # index from a variable

Reading a missing path returns null — it is never an error, so checks like if .user.name == null { ... } are safe on any event.

Assigning to a path writes the field and creates missing parent objects on the way:

.a.b.c = 1                # {} -> {"a":{"b":{"c":1}}}

del removes a field (no-op when the field does not exist):

del .user.password

Path dots must be written tightly: .a.b is one path, while .a .b is a compile error.

Values and literals
type literals
integer 42, 0
float 3.14, 1e10, 1.5e-3
string "hello" with \n, \t, \" escapes
raw string s'C:\new\path' — backslashes kept as is
regex r'\d+' — compiled at startup
timestamp t'2024-01-15T10:30:00Z' — RFC3339, 2006-01-02T15:04:05 or 2006-01-02
bool true, false
null null
array [1, "two", true]
object {level: "info", "other key": 2}

In conditions null and false are falsy; every other value is truthy.

Variables

Variables hold intermediate values and live for one event:

name = .user.name             # read a field into a variable
parts = capture(.log, r'...') # keep a function result
.out = name                   # write it back to the event

Fields of object values are accessed with a dot or an index; both forms are assignable, and arrays grow with nulls when assigned past their end:

parts.level                   # same as parts["level"]
arr[0] = 1
obj.key = "value"

Member access dots follow the same rule as paths: m.level is member access, m .level is a compile error.

Operators

In order of increasing precedence:

operators meaning
= assignment, right-associative: a = b = 1
|| logical or, short-circuit
&& logical and, short-circuit
== != equality (integers and floats compare numerically)
< <= > >= comparison of numbers, strings or timestamps
+ - addition, subtraction; + also concatenates strings
* / % multiplication, division, modulo; division by zero is a runtime error
! - (unary) negation
f() a[i] a.b call, index, member access

+ concatenates only strings with strings — convert other values first: "code " + string(.code).

Control flow
if .status >= 500 {
  .severity = "crit"
} else if .status >= 400 {
  .severity = "warn"
} else {
  .severity = "ok"
}

for i, item in .items {      # iterate an array; use _ to skip a variable
  .items[i] = item
}

if .level == "DEBUG" {
  abort                      # stop the program for this event
}

abort only stops the transform program — the event itself continues down the pipeline.

Functions

Functions are called with positional and named arguments. Positional arguments are required; named arguments are optional and fall back to their defaults: fn(value, option: "x").

  • upcase(value) — returns the string in upper case.

    .level = upcase(.level)    # "info" -> "INFO"
    
  • string(value) — converts any value to its string representation; null becomes an empty string. Use it to build strings from non-string fields:

    .msg = "code is " + string(.code)
    
  • capture(value, pattern) — matches the string against a regular expression and returns an object of its named groups (?P<name>...), or null when the value does not match (unnamed groups are ignored):

    m = capture(.log, r'^(?P<level>\S+)\s+(?P<message>.+)$')
    if m != null {
      .level = m.level
      .message = m.message
    }
    
  • after(value, separator) — returns everything after the first occurrence of separator; the value is returned unchanged when the separator is not found.

    .message = after(.log, " - ")
    
  • before(value, separator) — returns everything before the first occurrence of separator; unchanged when not found.

    .level = before(.log, " ")
    
  • between(value, open, close) — returns the text between the first open and the following close; unchanged when either delimiter is not found.

    .shard = between(.log, "[", "]")
    


Generated using insane-doc

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Config

type Config struct {
	// > @3@4@5@6
	// >
	// > The transformation program executed for every event.
	// > See the language reference and the list of built-in functions below.
	Source string `json:"source"` // *
}

! config-params ^ config-params

type Plugin

type Plugin struct {
	// contains filtered or unexported fields
}

func (*Plugin) Do

func (p *Plugin) Do(event *pipeline.Event) pipeline.ActionResult

func (*Plugin) Start

func (p *Plugin) Start(config pipeline.AnyConfig, params *pipeline.ActionPluginParams)

func (*Plugin) Stop

func (p *Plugin) Stop()

type Program

type Program struct {
	// contains filtered or unexported fields
}

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL