Fluent Bit’s modify filter can dynamically alter record data, but its real power emerges when you combine it with conditional logic, allowing you to route, drop, or transform data based on its content.
Here’s Fluent Bit processing logs in real-time, applying a conditional modification:
# Start Fluent Bit with a config that uses the modify filter for conditional logic
fluent-bit -c fluent-bit.conf
Let’s imagine we’re receiving logs from multiple applications, and we want to tag Kubernetes pods with a specific label if they are running in the production namespace and have error in their log message.
Our fluent-bit.conf might look like this:
[SERVICE]
Flush 1
Daemon off
Log_Level info
[INPUT]
Name tail
Path /var/log/app/*.log
Tag app.logs
[FILTER]
Name modify
Match app.logs
Add_Label environment production
Add_Label critical_error false
# Conditional logic starts here
Set critical_error true
If $kubernetes['namespace'] == 'production' && $log * "error"
[OUTPUT]
Name stdout
Match *
In this configuration:
- We define a
tailinput to read logs from/var/log/app/*.logand tag them asapp.logs. - The
modifyfilter is applied toapp.logs. - We initially add two labels:
environmentset toproductionandcritical_errorset tofalse. These are baseline values. - The crucial part is the
Ifcondition:Set critical_error true If $kubernetes['namespace'] == 'production' && $log * "error".Set critical_error true: This tells Fluent Bit to set thecritical_errorfield totrue.If $kubernetes['namespace'] == 'production' && $log * "error": This is the condition. TheSetaction only happens if Fluent Bit can access a field namedkubernetes(which it will have if the Kubernetes filter is also enabled and processing these logs), and within that, a fieldnamespacethat equals'production'. Additionally, the log message itself ($log) must contain the substring"error".
If a log record matches these criteria (i.e., it’s from the production namespace and its message contains "error"), the critical_error label will be updated from its initial false to true. Otherwise, it remains false.
This allows for powerful data enrichment and routing. Imagine a scenario where you want to send errors from production to a separate, high-priority alert system. You could use this conditional logic to set a flag, and then a subsequent output plugin (like elasticsearch or kafka) could use a Match clause like Match environment=production,critical_error=true to route only those specific logs.
The modify filter supports a wide range of actions beyond Set and Add_Label, including Remove, Rename, Drop, and Replace. These can all be combined with If conditions. For instance, you could Drop logs that don’t meet certain criteria or Replace a sensitive field’s value if it’s detected in a specific context.
The If statement uses a C-style syntax with logical operators (&& for AND, || for OR, ! for NOT) and supports comparisons (==, !=, >, <, >=, <=). You can also use string matching with * (wildcard) and ~ (regex). For example, If $http.request.method * "POST" would match any POST requests.
What most people don’t realize is the granular control you have over which fields are checked within the If condition. If you’re using the Kubernetes filter, you can directly access fields like $kubernetes['pod_name'], $kubernetes['namespace'], or $kubernetes['labels']['app']. If you’ve parsed JSON logs, you can access nested fields like $json_payload['user']['id']. This deep inspection is key to building sophisticated routing and filtering rules.
The next logical step is to explore how to use these conditionally modified records for dynamic output routing.