Lua

The Lua filter allows you to modify the incoming records (even split one record into multiple records) using custom Lua scripts.

Due to the necessity to have a flexible filtering mechanism, it is now possible to extend Fluent Bit capabilities by writing custom filters using Lua programming language. A Lua-based filter takes two steps:

  1. Configure the Filter in the main configuration

  2. Prepare a Lua script that will be used by the Filter

Configuration Parameters

The plugin supports the following configuration parameters:

Getting Started

In order to test the filter, you can run the plugin from the command line or through the configuration file. The following examples use the dummy input plugin for data ingestion, invoke Lua filter using the test.lua script and call the cb_print() function which only prints the same information to the standard output:

Command Line

From the command line you can use the following options:

$ fluent-bit -i dummy -F lua -p script=test.lua -p call=cb_print -m '*' -o null

Configuration File

In your main configuration file append the following Input, Filter & Output sections:

[INPUT]
    Name    dummy

[FILTER]
    Name    lua
    Match   *
    script  test.lua
    call    cb_print

[OUTPUT]
    Name    null
    Match   *

Lua Script Filter API

The life cycle of a filter have the following steps:

  1. Upon Tag matching by this filter, it may process or bypass the record.

  2. If tag matched, it will accept the record and invoke the function defined in the call property which basically is the name of a function defined in the Lua script.

  3. Invoke Lua function and pass each record in JSON format.

  4. Upon return, validate return value and continue the pipeline.

Callback Prototype

The Lua script can have one or multiple callbacks that can be used by this filter. The function prototype is as follows:

function cb_print(tag, timestamp, record)
    ...
    return code, timestamp, record
end

Function Arguments

Return Values

Each callback must return three values:

Code Examples

For functional examples of this interface, please refer to the code samples provided in the source code of the project located here:

https://github.com/fluent/fluent-bit/tree/master/scripts

Inline configuration

The Fluent Bit smoke tests include examples to verify during CI.

service:
    flush:           1
    daemon:          off
    log_level:       info

pipeline:
    inputs:
        - random:
            tag:           test
            samples:       10

    filters:
        - lua:
            match:         "*"
            call:          append_tag
            code:          |
                function append_tag(tag, timestamp, record)
                   new_record = record
                   new_record["tag"] = tag
                   return 1, timestamp, new_record
                end

    outputs:
        - stdout:
            match:         "*"

In classic mode:

[SERVICE]
	flush 1
	daemon off
	log_level debug

[INPUT]
	Name random
	Tag test
	Samples 10

[FILTER]
	Name Lua
	Match *
	call append_tag
	code function append_tag(tag, timestamp, record) new_record = record new_record["tag"] = tag return 1, timestamp, new_record end

[OUTPUT]
	Name stdout
	Match *

Environment variable processing

As an example that combines a bit of LUA processing with the Kubernetes filter that demonstrates using environment variables with LUA regex and substitutions.

Kubernetes pods generally have various environment variables set by the infrastructure automatically which may contain useful information.

In this example, we want to extract part of the Kubernetes cluster API name.

The environment variable is set like so: KUBERNETES_SERVICE_HOST: api.sandboxbsh-a.project.domain.com

We want to extract the sandboxbsh name and add it to our record as a special key.

      [FILTER]
          Name                lua
          Alias               filter-iots-lua
          Match               iots_thread.*
          Script              filters.lua
          Call                set_landscape_deployment

  filters.lua: |
    -- Use a Lua function to create some additional entries based
    -- on substrings from the kubernetes properties.
    function set_landscape_deployment(tag, timestamp, record)
        local landscape = os.getenv("KUBERNETES_SERVICE_HOST")
        if landscape then
            -- Strip the landscape name from this field, KUBERNETES_SERVICE_HOST
            -- Should be of this format
            -- api.sandboxbsh-a.project.domain.com
            -- Take off the leading "api."
            -- sandboxbsh-a.project.domain.com
            --print("landscape1:" .. landscape)
            landscape = landscape:gsub("^[^.]+.", "")
            --print("landscape2:" .. landscape)
            -- Take off everything including and after the - in the cluster name
            -- sandboxbsh
            landscape = landscape:gsub("-.*$", "")
            -- print("landscape3:" .. landscape)
            record["iot_landscape"] = landscape
        end
        -- 2 - replace existing record with this update
        return 2, timestamp, record
    end

Number Type

+Lua treats number as double. It means an integer field (e.g. IDs, log levels) will be converted double. To avoid type conversion, The type_int_key property is available.

Protected Mode

Fluent Bit supports protected mode to prevent crash when executes invalid Lua script. See also Error Handling in Application Code.

Record Split

The Lua callback function can return an array of tables (i.e., array of records) in its third record return value. With this feature, the Lua filter can split one input record into multiple records according to custom logic.

For example:

Lua script

function cb_split(tag, timestamp, record)
    if record["x"] ~= nil then
        return 2, timestamp, record["x"]
    else
        return 2, timestamp, record
    end
end

Configuration

[Input]
    Name    stdin

[Filter]
    Name    lua
    Match   *
    script  test.lua
    call    cb_split

[Output]
    Name    stdout
    Match   *

Input

{"x": [ {"a1":"aa", "z1":"zz"}, {"b1":"bb", "x1":"xx"}, {"c1":"cc"} ]}
{"x": [ {"a2":"aa", "z2":"zz"}, {"b2":"bb", "x2":"xx"}, {"c2":"cc"} ]}
{"a3":"aa", "z3":"zz", "b3":"bb", "x3":"xx", "c3":"cc"}

Output

[0] stdin.0: [1538435928.310583591, {"a1"=>"aa", "z1"=>"zz"}]
[1] stdin.0: [1538435928.310583591, {"x1"=>"xx", "b1"=>"bb"}]
[2] stdin.0: [1538435928.310583591, {"c1"=>"cc"}]
[3] stdin.0: [1538435928.310588359, {"z2"=>"zz", "a2"=>"aa"}]
[4] stdin.0: [1538435928.310588359, {"b2"=>"bb", "x2"=>"xx"}]
[5] stdin.0: [1538435928.310588359, {"c2"=>"cc"}]
[6] stdin.0: [1538435928.310589790, {"z3"=>"zz", "x3"=>"xx", "c3"=>"cc", "a3"=>"aa", "b3"=>"bb"}]

See also Fluent Bit: PR 811.

Last updated