Skip to content

multiline: add built in multiline json parser - #2671

Open
lecaros wants to merge 1 commit into
masterfrom
lecaros-built-in-ml-json-parser
Open

multiline: add built in multiline json parser#2671
lecaros wants to merge 1 commit into
masterfrom
lecaros-built-in-ml-json-parser

Conversation

@lecaros

@lecaros lecaros commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

adds documentation for fluent/fluent-bit#12264

Summary by CodeRabbit

  • Documentation
    • Added guidance for processing pretty-printed JSON split across multiple lines.
    • Documented the built-in JSON multiline parser, including limitations and configuration examples.
    • Clarified when to use multiline parsing versus JSON Lines parsing.
    • Explained how to combine multiline parsing with the Parser filter to parse assembled log fields.
    • Added links to relevant JSON multiline parsing documentation.

@lecaros
lecaros requested review from a team and eschabell as code owners August 12, 2026 15:39
@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: c97095f1-5205-4bcf-af04-d928deb7aeba

📥 Commits

Reviewing files that changed from the base of the PR and between f190973 and 12f0308.

📒 Files selected for processing (1)
  • pipeline/parsers/multiline-parsing.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • pipeline/parsers/multiline-parsing.md

📝 Walkthrough

Walkthrough

The documentation adds guidance for parsing pretty-printed JSON with Tail’s built-in json multiline parser and the Parser filter. It distinguishes this workflow from JSON Lines and provides YAML and classic configuration examples.

Changes

JSON multiline parsing

Layer / File(s) Summary
JSON parser reference and examples
pipeline/parsers/multiline-parsing.md
Documents the built-in json multiline parser, final-buffer behavior, JSON Lines differences, Parser filter usage, limitations, and YAML and classic configuration examples.
Tail and filter guidance
pipeline/inputs/tail.md, pipeline/filters/multiline-stacktrace.md
Directs pretty-printed JSON users to Tail’s built-in parser and the multiline parsing reference. Clarifies the separate JSON Lines workflow.

Estimated code review effort: 1 (Trivial) | ~5 minutes

Possibly related PRs

Suggested labels: 5.1

Suggested reviewers: eschabell

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the main change: documentation for the built-in multiline JSON parser.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch lecaros-built-in-ml-json-parser

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@pipeline/parsers/multiline-parsing.md`:
- Line 869: Update the example reference in the multiline parsing documentation
to point to an existing Fluent Bit repository example path, or add the missing
json-001 example files so the current link resolves successfully.
- Around line 880-884: Add time_keep: on to the YAML json parser definition and
Time_Keep On to the corresponding json_lines parser definition. Update the
output example to retain the parsed time field and include the default date
field emitted by json_lines.
- Line 266: Update the `flush_timeout` description to identify it as the timeout
for a non-terminated multiline buffer waiting for additional input, rather than
framing it only as a shutdown behavior. Keep the `exit_on_eof` and `grace`
recommendation for flushing the final buffer in a separate sentence.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: bc2698d8-2a45-4699-8086-c937b889fe4b

📥 Commits

Reviewing files that changed from the base of the PR and between 21a0519 and f190973.

📒 Files selected for processing (3)
  • pipeline/filters/multiline-stacktrace.md
  • pipeline/inputs/tail.md
  • pipeline/parsers/multiline-parsing.md


- The multiline parser isn't affected by the `buffer_max_size` configuration option, allowing the composed log record to grow beyond this size. The `skip_long_lines` option won't be applied to multiline messages.
- It's not possible to get the time key from the body of the multiline message. However, it can be extracted and set as a new key by using a filter.
- When using the built-in `json` parser on static files, the last pretty-printed object may not flush until the next line starting with `{` or until `flush_timeout` (default 4 seconds) during shutdown. With `exit_on_eof`, allow enough `grace` time for the final buffer to flush.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -e
file="pipeline/parsers/multiline-parsing.md"
printf '%s\n' '--- target context ---'
sed -n '250,275p' "$file"
printf '%s\n' '--- related references ---'
rg -n -C 3 'flush_timeout|exit_on_eof|grace|built-in `json`|static files' "$file"
printf '%s\n' '--- repository references ---'
rg -n -C 3 'flush_timeout|exit_on_eof' --glob '!pipeline/parsers/multiline-parsing.md' .

Repository: fluent/fluent-bit-docs

Length of output: 9743


🌐 Web query:

Fluent Bit built-in json parser flush_timeout multiline parser exit_on_eof grace shutdown documentation

💡 Result:

Fluent Bit provides built-in mechanisms for JSON parsing, multiline log aggregation, and lifecycle management. JSON Parser: Fluent Bit includes a built-in JSON parser used to structure log data [1]. You can configure it by setting the format to 'json' in your parser definition [1][2]. Supported parameters include time_key, time_format, and types (e.g., integer, bool, string) to control how fields are decoded [2][3][4]. Multiline Parser: Multiline parsers combine log entries that span multiple lines (such as stack traces) into a single cohesive message [5][6]. They are configured in a multiline_parsers section [7]. You must specify a type (e.g., regex) and define rules consisting of states (start_state, continuation_state) and regex patterns to identify log boundaries [5][7]. Lifecycle and Shutdown Configuration: - grace: Defined in the [SERVICE] section, this sets the duration in seconds that Fluent Bit waits for active tasks to complete before force-quitting during a shutdown process [8][9]. The default is 5 seconds [8]. - flush_timeout: While there is no global flush_timeout, the 'flush' parameter in the [SERVICE] section defines the frequency (in seconds.nanoseconds) with which data is sent to output plugins [8][9]. Within a multiline parser, 'flush_timeout' can also be specified to define how long to wait for a full multiline message before flushing incomplete data [7]. - exit_on_eof: Primarily used with the Tail input plugin, setting 'exit_on_eof' to 'on' causes the plugin to stop reading and trigger an engine shutdown as soon as the end of the input file is reached [10][11]. - Shutdown Behavior: Fluent Bit attempts to synchronize offsets and flush chunks during graceful shutdowns (SIGTERM) [10]. If 'storage.backlog.flush_on_shutdown' is enabled, the engine will also attempt to flush all backlog filesystem chunks before exiting [8].

Citations:


🏁 Script executed:

#!/bin/bash
set -e
python3 - <<'PY'
import json
import urllib.request

urls = {
    "multiline_json_parser": "https://api.github.com/repos/fluent/fluent-bit/contents/src/multiline",
    "issue_12264": "https://api.github.com/repos/fluent/fluent-bit/issues/12264",
}
for name, url in urls.items():
    print(f"--- {name} ---")
    req = urllib.request.Request(url, headers={"Accept": "application/vnd.github+json", "User-Agent": "review-check"})
    with urllib.request.urlopen(req, timeout=20) as response:
        data = json.load(response)
    if isinstance(data, list):
        for item in data:
            print(item.get("name"), item.get("download_url"))
    else:
        print(json.dumps({
            "title": data.get("title"),
            "state": data.get("state"),
            "body": data.get("body"),
            "comments": data.get("comments"),
        }, indent=2))
PY

Repository: fluent/fluent-bit-docs

Length of output: 2477


🌐 Web query:

site:github.com/fluent/fluent-bit "flush_timeout" "json" "exit_on_eof"

💡 Result:

In Fluent Bit, the interaction between flush_timeout (used in multiline parsers) and Exit_On_Eof (used in the tail input plugin) is a known source of data loss during batch processing [1][2][3]. Exit_On_Eof is an input configuration setting that instructs Fluent Bit to terminate as soon as it reaches the end of the monitored file(s) [4][5][6]. It is primarily intended for bulk loading and testing purposes [4][6]. flush_timeout is a configuration option within a multiline parser that defines the maximum amount of time (in milliseconds) the parser will wait for subsequent lines to complete a multiline record before flushing the currently buffered lines [7][8]. The conflict arises because Exit_On_Eof can trigger a shutdown before the multiline parser's flush_timeout interval has elapsed or before pending buffers are processed [1][3]. When Exit_On_Eof is triggered, Fluent Bit initiates its shutdown sequence [5]. If a multiline record is still being buffered (waiting for more lines to arrive or for the flush_timeout to expire), that partial record is often abandoned and lost because the process terminates before the parser can emit the final output [1][3]. Users frequently report that when running in batch mode with Exit_On_Eof, the last multiline log entries are either incomplete or missing entirely [1][2][9]. There is no native configuration option that effectively synchronizes a "safe shutdown" where the parser is forced to flush all remaining multiline buffers before the tail input fully exits [1][3]. Consequently, this combination is generally discouraged for critical batch processing where data integrity is required [3].

Citations:


🏁 Script executed:

#!/bin/bash
set -e
api='https://api.github.com'
hdr=(-H 'Accept: application/vnd.github+json' -H 'User-Agent: review-check')

printf '%s\n' '--- pull request 12264 ---'
curl -ksS "${hdr[@]}" "$api/repos/fluent/fluent-bit/pulls/12264" |
  jq '{title,body,state,merged_at,changed_files}'

printf '%s\n' '--- pull request files ---'
curl -ksS "${hdr[@]}" "$api/repos/fluent/fluent-bit/pulls/12264/files?per_page=100" |
  jq -r '.[] | [.filename, .status, (.patch // "")] | `@tsv`'

printf '%s\n' '--- multiline source candidates ---'
curl -ksS "${hdr[@]}" "$api/repos/fluent/fluent-bit/contents/src" |
  jq -r '.[].name' | grep -Ei 'multi|parser'

printf '%s\n' '--- tail source references ---'
curl -ksS "${hdr[@]}" "$api/repos/fluent/fluent-bit/git/trees/master?recursive=1" |
  jq -r '.tree[] | select(.path | test("multiline|in_tail|parser"; "i")) | .path' |
  grep -E '(^src/|^plugins/in_tail/)' | head -100

Repository: fluent/fluent-bit-docs

Length of output: 382


Describe flush_timeout as a multiline-buffer timeout. It applies when a non-terminated buffer waits for more input, not only during shutdown. Keep the exit_on_eof and grace guidance in a separate sentence.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pipeline/parsers/multiline-parsing.md` at line 266, Update the
`flush_timeout` description to identify it as the timeout for a non-terminated
multiline buffer waiting for additional input, rather than framing it only as a
shutdown behavior. Keep the `exit_on_eof` and `grace` recommendation for
flushing the final buffer in a separate sentence.

Comment thread pipeline/parsers/multiline-parsing.md Outdated
Comment on lines +880 to +884
parsers:
- name: json
format: json
time_key: time
time_format: "%Y-%m-%dT%H:%M:%S.%L"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -eu

printf '%s\n' '--- target file locations ---'
rg -n -C 12 'time_key|time_keep|json_lines|date|github.com/fluent/fluent-bit-docs|Time_Keep|Time_Key' pipeline/parsers/multiline-parsing.md

printf '%s\n' '--- repository references to JSON parser timestamp behavior ---'
rg -n -S -C 4 'time_keep|Time_Keep|json_lines|Time_Key|generated.*date|date.*field' . \
  -g '*.md' -g '*.yaml' -g '*.yml' -g '*.conf' -g '*.c' -g '*.cc' -g '*.cpp' -g '*.h' -g '*.cxx' \
  | head -n 500

Repository: fluent/fluent-bit-docs

Length of output: 40264


🌐 Web query:

Fluent Bit JSON parser Time_Keep default date field json_lines multiline parser documentation

💡 Result:

In Fluent Bit, the Time_Keep configuration option determines whether the original time field is retained after it has been parsed and used to set the event's internal timestamp [1][2]. When Time_Keep is enabled (set to 'on' or 'true'), the parser keeps the original time key in the resulting record [1][2]. When it is disabled (the default setting), the parser drops the original time field once the timestamp has been processed [1][2]. This setting applies to custom parsers, including those using the JSON format [1][3][2]. Regarding your query about multiline parsing and 'json_lines': 1. Multiline Parsing: Fluent Bit handles multiline logs using a separate multiline parser configuration, which can be defined in a [MULTILINE_PARSER] section (or under a multiline_parsers section in YAML) [4][5]. 2. JSON Lines: If you are processing a file where each line is a valid JSON object (often referred to as JSON Lines), you typically do not need a complex multiline parser. Instead, you can use the Tail input plugin with the 'json' parser directly [6][7]. If your logs are multiline JSON objects, the multiline parser must be configured to identify the start of a record and can optionally apply a pre-defined parser to that content [4][5]. To ensure the time field is kept when using a JSON parser, you would configure your parser as follows: Example YAML configuration: parsers: - name: my_json_parser format: json time_key: time time_format: '%Y-%m-%dT%H:%M:%S.%L' time_keep: on Example classic configuration: [PARSER] Name my_json_parser Format json Time_Key time Time_Format %Y-%m-%dT%H:%M:%S.%L Time_Keep On

Citations:


🏁 Script executed:

#!/bin/bash
set -eu

sed -n '946,990p' pipeline/parsers/multiline-parsing.md
printf '%s\n' '--- link target checks ---'
if command -v git >/dev/null 2>&1; then
  git ls-remote https://github.com/fluent/fluent-bit.git \
    refs/heads/master refs/heads/main 2>/dev/null | head -n 5 || true
fi
printf '%s\n' '--- local documentation for parser retention and stdout date fields ---'
sed -n '1,35p' pipeline/parsers/configuring-parser.md
sed -n '1,28p' pipeline/outputs/standard-output.md

Repository: fluent/fluent-bit-docs

Length of output: 6677


Keep the parsed time field in both parser definitions.

time_keep defaults to false, so the parser removes time. Add time_keep: on and Time_Keep On. Update the output example to include both time and the default date field emitted by json_lines.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pipeline/parsers/multiline-parsing.md` around lines 880 - 884, Add time_keep:
on to the YAML json parser definition and Time_Keep On to the corresponding
json_lines parser definition. Update the output example to retain the parsed
time field and include the default date field emitted by json_lines.

Signed-off-by: lecaros <lecaros@chronosphere.io>
@lecaros
lecaros force-pushed the lecaros-built-in-ml-json-parser branch from f190973 to 12f0308 Compare August 12, 2026 15:49
| `docker` | Process a log entry generated by a Docker container engine. This parser supports the concatenation of large log entries split by Docker. If you use this parser, and you also want to concatenate log lines like stack traces, you can add the [multiline filter](../../pipeline/filters/multiline-stacktrace.md) to specify additional parsers. |
| `go` | Process log entries generated by a Go-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. |
| `json` | Group pretty-printed JSON objects that span multiple lines. The parser concatenates lines only; use a [Parser filter](../../pipeline/filters/parser.md) with `parser: json` on the assembled `log` field to extract structured fields. |

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[markdownlint] reported by reviewdog 🐶
error MD060/table-column-style Table column style [Table pipe has extra space to the left for style "compact"]

Comment on lines 24 to 28
| `go` | Process log entries generated by a Go-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. |
| `json` | Group pretty-printed JSON objects that span multiple lines. The parser concatenates lines only; use a [Parser filter](../../pipeline/filters/parser.md) with `parser: json` on the assembled `log` field to extract structured fields. |
| `python` | Process log entries generated by a Python-based language application and perform concatenation if multiline messages are detected. |
| `ruby` | Process log entries generated by a Ruby-based language application and perform concatenation if multiline messages are detected. |

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[markdownlint-fix] reported by reviewdog 🐶

Suggested change
| `go` | Process log entries generated by a Go-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. |
| `json` | Group pretty-printed JSON objects that span multiple lines. The parser concatenates lines only; use a [Parser filter](../../pipeline/filters/parser.md) with `parser: json` on the assembled `log` field to extract structured fields. |
| `python` | Process log entries generated by a Python-based language application and perform concatenation if multiline messages are detected. |
| `ruby` | Process log entries generated by a Ruby-based language application and perform concatenation if multiline messages are detected. |
| `go` | Process log entries generated by a Go-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. |
| `json` | Group pretty-printed JSON objects that span multiple lines. The parser concatenates lines only; use a [Parser filter](../../pipeline/filters/parser.md) with `parser: json` on the assembled `log` field to extract structured fields. |
| `python` | Process log entries generated by a Python-based language application and perform concatenation if multiline messages are detected. |
| `ruby` | Process log entries generated by a Ruby-based language application and perform concatenation if multiline messages are detected. |

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant