Multiline Parsing
In an ideal world, applications might log their messages within a single line, but in reality applications generate multiple log messages that sometimes belong to the same context. But when is time to process such information it gets really complex. Consider application stack traces which always have multiple log lines.
Starting from Fluent Bit v1.8, we have implemented a unified Multiline core functionality to solve all the user corner cases. In this section, you will learn about the features and configuration options available.

Concepts

The Multiline parser engine exposes two ways to configure and use the functionality:
    Built-in multiline parser
    Configurable multiline parser

Built-in Multiline Parsers

Without any extra configuration, Fluent Bit exposes certain pre-configured parsers (built-in) to solve specific multiline parser cases, e.g:
Parser
Description
docker
Process a log entry generated by a Docker container engine. This parser supports the concatenation of log entries split by Docker.
cri
Process a log entry generated by CRI-O container engine. Same as the docker parser, it supports concatenation of log entries
go
Process log entries generated by a Go based language application and perform concatenation if multiline messages are detected.
python
Process log entries generated by a Python based language application and perform concatenation if multiline messages are detected.
java
Process log entries generated by a Google Cloud Java language application and perform concatenation if multiline messages are detected.

Configurable Multiline Parsers

Besides the built-in parsers listed above, through the configuration files is possible to define your own Multiline parsers with their own rules.
A multiline parser is defined in a parsers configuration file by using a [MULTILINE_PARSER] section definition. The Multiline parser must have a unique name and a type plus other configured properties associated with each type.
To understand which Multiline parser type is required for your use case you have to know beforehand what are the conditions in the content that determines the beginning of a multiline message and the continuation of subsequent lines. We provide a regex based configuration that supports states to handle from the most simple to difficult cases.
Property
Description
Default
name
Specify a unique name for the Multiline Parser definition. A good practice is to prefix the name with the word multiline_ to avoid confusion with normal parser's definitions.
type
Set the multiline mode, for now, we support the type regex.
parser
Name of a pre-defined parser that must be applied to the incoming content before applying the regex rule. If no parser is defined, it's assumed that's a raw text and not a structured message.
Note: when a parser is applied to a raw text, then the regex is applied against a specific key of the structured message by using the key_content configuration property (see below).
key_content
For an incoming structured message, specify the key that contains the data that should be processed by the regular expression and possibly concatenated.
flush_timeout
Timeout in milliseconds to flush a non-terminated multiline buffer. Default is set to 5 seconds.
5s
rule
Configure a rule to match a multiline pattern. The rule has a specific format described above, multiple rules can be defined.

Lines and States

Before start configuring your parser you need to know the answer to the following questions:
    1.
    What is the regular expression (regex) that matches the first line of a multiline message ?
    2.
    What are the regular expressions (regex) that match the continuation lines of a multiline message ?
When matching regex, we have to define states, some states define the start of a multiline message while others are states for the continuation of multiline messages. You can have multiple continuation states definitions to solve complex cases.
The first regex that matches the start of a multiline message is called start_state, then other regexes continuation lines can have different state names.

Rules Definition

A rule specifies how to match a multiline pattern and perform the concatenation. A rule is defined by 3 specific components:
    1.
    state name
    2.
    regular expression pattern
    3.
    next state
A rule might be defined as follows (comments added to simplify the definition) :
1
# rules | state name | regex pattern | next state
2
# --------|----------------|---------------------------------------------
3
rule "start_state" "/(Dec \d+ \d+\:\d+\:\d+)(.*)/" "cont"
4
rule "cont" "/^\s+at.*/" "cont"
Copied!
In the example above, we have defined two rules, each one has its own state name, regex paterns, and the next state name. Every field that composes a rule must be inside double quotes.
The first rule of state name must always be start_state, and the regex pattern must match the first line of a multiline message, also a next state must be set to specify how the possible continuation lines would look like.
To simplify the configuration of regular expressions, you can use the Rubular web site. We have posted an example by using the regex described above plus a log line that matches the pattern: https://rubular.com/r/NDuyKwlTGOvq2g

Configuration Example

The following example provides a full Fluent Bit configuration file for multiline parsing by using the definition explained above.
Example files content:
fluent-bit.conf
parsers_multiline.conf
test.log
This is the primary Fluent Bit configuration file. It includes the parsers_multiline.conf and tails the file test.log by applying the multiline parser multiline-regex-test. Then it sends the processing to the standard output.
1
[SERVICE]
2
flush 1
3
log_level info
4
parsers_file parsers_multiline.conf
5
6
[INPUT]
7
name tail
8
path test.log
9
read_from_head true
10
multiline.parser multiline-regex-test
11
12
[OUTPUT]
13
name stdout
14
match *
Copied!
This second file defines a multiline parser for the example.
1
[MULTILINE_PARSER]
2
name multiline-regex-test
3
type regex
4
flush_timeout 1000
5
#
6
# Regex rules for multiline parsing
7
# ---------------------------------
8
#
9
# configuration hints:
10
#
11
# - first state always has the name: start_state
12
# - every field in the rule must be inside double quotes
13
#
14
# rules | state name | regex pattern | next state
15
# ------|---------------|--------------------------------------------
16
rule "start_state" "/(Dec \d+ \d+\:\d+\:\d+)(.*)/" "cont"
17
rule "cont" "/^\s+at.*/" "cont"
Copied!
An example file with multiline content:
1
single line...
2
Dec 14 06:41:08 Exception in thread "main" java.lang.RuntimeException: Something has gone wrong, aborting!
3
at com.myproject.module.MyProject.badMethod(MyProject.java:22)
4
at com.myproject.module.MyProject.oneMoreMethod(MyProject.java:18)
5
at com.myproject.module.MyProject.anotherMethod(MyProject.java:14)
6
at com.myproject.module.MyProject.someMethod(MyProject.java:10)
7
at com.myproject.module.MyProject.main(MyProject.java:6)
8
another line...
9
Copied!
By running Fluent Bit with the given configuration file you will obtain:
1
$ fluent-bit -c fluent-bit.conf
2
3
[0] tail.0: [0.000000000, {"log"=>"single line...
4
"}]
5
[1] tail.0: [1626634867.472226330, {"log"=>"Dec 14 06:41:08 Exception in thread "main" java.lang.RuntimeException: Something has gone wrong, aborting!
6
at com.myproject.module.MyProject.badMethod(MyProject.java:22)
7
at com.myproject.module.MyProject.oneMoreMethod(MyProject.java:18)
8
at com.myproject.module.MyProject.anotherMethod(MyProject.java:14)
9
at com.myproject.module.MyProject.someMethod(MyProject.java:10)
10
at com.myproject.module.MyProject.main(MyProject.java:6)
11
"}]
12
[2] tail.0: [1626634867.472226330, {"log"=>"another line...
13
"}]
14
Copied!
The lines that did not match a pattern are not considered as part of the multiline message, while the ones that matched the rules were concatenated properly.
Last modified 3mo ago