Fluent Bit Log Collection
Fluent Bit Log Collection
Overview
Fluent Bit is a lightweight, high-performance log processor and forwarder used to collect logs from Linux systems—including RHEL 9 and other supported distributions—and send them to Azure Event Hub for ingestion into Splunk. It provides efficient log collection with built-in buffering, filtering, and metadata enrichment capabilities.
Key Features
- Low resource footprint: Minimal CPU and memory usage
- Persistent buffering: Filesystem-backed storage prevents log loss during network issues
- Dynamic configuration: Automatically monitors configured log paths
- Metadata enrichment: Adds sourcetype and source fields for Splunk routing
- Multiple input sources: Collects from systemd journal and file-based logs
Architecture
Log Sources → Fluent Bit → Azure Event Hub → Splunk
Fluent Bit runs as a systemd service under the svc_eoa_fluentbit service account, which requires read access to monitored log directories and files via POSIX ACLs.
Metadata Mapping for Splunk
Fluent Bit enriches log events with metadata fields that map to Splunk index-time fields:
| Fluent Bit Field | Splunk Field | Description | Example |
|---|---|---|---|
type | sourcetype | Log format/category identifier | linux:audit, linux:sssd |
agg | source | Original log file path or source identifier | /var/log/audit/audit.log, systemd |
How Metadata is Added
The configuration template (99-eoa-fluentbit.conf.j2) uses FILTER blocks to add these fields:
[FILTER]
Name modify
Match {{ category_name }}
Copy data.log_file_path agg
Add type {{ category_config.type }}
typefield: Set fromlinux_fluentbit_log_access_paths.<category>.typevariableaggfield: Copied from the actual log file path (log_file_path) captured by Fluent Bit
These fields are nested under data.* in the JSON payload sent to Azure Event Hub, where they are extracted and mapped to Splunk sourcetype and source during indexing.
Log Collection Configuration
All log categories are defined in defaults/main/linux.yml under the linux_fluentbit_log_access_paths variable. Each category configures:
- Paths: Directories to monitor
- Patterns: Filename patterns to match
- Permissions: ACL permissions for directories and files
- Recursion: Whether to monitor subdirectories
- Type: Splunk sourcetype identifier
Adding New Log Sources
Scenario 1: Logs in a Single Parent Directory
Use Case: Monitor specific log files that exist only in the parent directory, not in subdirectories. This is useful when you want to monitor select files in a high-volume directory without monitoring all files or subdirectories.
Example: System logs in /var/log/ (messages and dnf.log only, not subdirectories)
linux_fluentbit_log_access_paths:
system:
type: linux:system
paths:
- /var/log
patterns:
- "messages"
- "dnf.log"
permissions: rx
file_permissions: r
recursive: false # Do NOT search subdirectories
default_acl: false # Don't set default ACL on /var/log itself
apply_to_existing_files: true
Generated Fluent Bit Paths:
/var/log/messages/var/log/dnf.log
Key Settings:
recursive: false- Only matches files directly in/var/log/, not in subdirectoriespatterns: ["messages", "dnf.log"]- Exact filename matchesdefault_acl: false- Prevents setting default ACL on the high-volume/var/logdirectory
Matches:
- ✅
/var/log/messages - ✅
/var/log/dnf.log - ❌
/var/log/audit/audit.log(in subdirectory) - ❌
/var/log/boot.log(not in patterns list)
Scenario 2: Logs in All Subdirectories (Excluding Parent)
Use Case: Monitor logs in subdirectories at any depth, but NOT in the parent directory itself. This is ideal when all log files are organized in subdirectories (e.g., one subdirectory per extension or service).
Example: Azure extension logs at /var/log/azure/Microsoft.*/*/logs/*.log
linux_fluentbit_log_access_paths:
azure:
type: linux:azure
paths:
- /var/log/azure
patterns:
- "*.log"
permissions: rx
file_permissions: r
recursive: true # Search ALL subdirectories recursively
default_acl: true
apply_to_existing_files: true
Generated Fluent Bit Path: /var/log/azure/**/*.log
Key Settings:
recursive: true- Generates/**wildcard for recursive matching at any depthpatterns: ["*.log"]- Matches any.logfiledefault_acl: true- Ensures new subdirectories (new extensions) automatically inherit ACLs
Important: The /** pattern requires at least one subdirectory level. It will NOT match files directly in /var/log/azure/.
Matches:
- ✅
/var/log/azure/Microsoft.CPlat.Core.LinuxPatchExtension/Events/2024-11-07.log - ✅
/var/log/azure/Microsoft.Azure.Monitor.AzureMonitorLinuxAgent/1.29.5/handler.log - ✅
/var/log/azure/Microsoft.Azure.Extensions.CustomScript/status/0.status - ❌
/var/log/azure/direct.log(no subdirectory between parent and file)
Scenario 3: Logs in All Subdirectories AND Parent Directory
Use Case: Monitor logs at any depth, including the parent directory itself. This is necessary when log files may appear both in the parent directory AND in subdirectories.
Example: Azure logs that may exist in /var/log/azure/extension.log AND /var/log/azure/Microsoft.*/handler.log
Solution: Define two separate categories - one for the parent, one for subdirectories.
linux_fluentbit_log_access_paths:
# Category 1: Parent directory only
azure_parent:
type: linux:azure
paths:
- /var/log/azure
patterns:
- "*.log"
permissions: rx
file_permissions: r
recursive: false # Parent directory only
default_acl: true # Ensures new subdirectories inherit ACLs
apply_to_existing_files: true
# Category 2: All subdirectories recursively
azure_subdirs:
type: linux:azure
paths:
- /var/log/azure
patterns:
- "*.log"
permissions: rx
file_permissions: r
recursive: true # All subdirectories
default_acl: false # Already handled by parent category
apply_to_existing_files: true
Generated Fluent Bit Paths:
/var/log/azure/*.log(fromazure_parent)/var/log/azure/**/*.log(fromazure_subdirs)
Why Two Categories?:
/**pattern does NOT match direct children - requires at least one subdirectory level- Separate non-recursive category ensures parent-level files are monitored
default_acl: trueon parent ensures new subdirectories (new extensions) inherit permissions
Matches:
- ✅
/var/log/azure/extension.log(fromazure_parent) - ✅
/var/log/azure/Microsoft.CPlat.Core.LinuxPatchExtension/handler.log(fromazure_subdirs) - ✅
/var/log/azure/Microsoft.Azure.Monitor/1.29.5/error.log(fromazure_subdirs)
Scenario 4: Logs in Select Subdirectories
Use Case: Monitor logs only in specific named subdirectories, not all subdirectories. This gives you fine-grained control when you only want to monitor certain extensions or services.
Example: Only monitor Azure Monitor and Custom Script extensions, but not other Azure extensions.
Solution: Include a parent directory category with a non-matching pattern to set ACLs for directory traversal, then list each subdirectory explicitly.
linux_fluentbit_log_access_paths:
# Parent directory - ACL traversal only, no actual log monitoring
azure_parent_acl:
type: linux:azure
paths:
- /var/log/azure
patterns:
- "" # Empty pattern - will never match any files
permissions: rx # Allows svc_eoa_fluentbit to traverse into subdirectories
file_permissions: r
recursive: false
default_acl: true # Future subdirectories inherit ACL
apply_to_existing_files: false # No existing files to apply ACL to
azure_monitor:
type: linux:azure:monitor
paths:
- /var/log/azure/Microsoft.Azure.Monitor.AzureMonitorLinuxAgent
patterns:
- "*.log"
permissions: rx
file_permissions: r
recursive: true # Monitor all subdirectories within this extension
default_acl: true
apply_to_existing_files: true
azure_customscript:
type: linux:azure:customscript
paths:
- /var/log/azure/Microsoft.Azure.Extensions.CustomScript
patterns:
- "*.log"
permissions: rx
file_permissions: r
recursive: true # Monitor all subdirectories within this extension
default_acl: true
apply_to_existing_files: true
Generated Fluent Bit Paths:
/var/log/azure/(empty pattern generates path without glob - never matches)/var/log/azure/Microsoft.Azure.Monitor.AzureMonitorLinuxAgent/**/*.log/var/log/azure/Microsoft.Azure.Extensions.CustomScript/**/*.log
Key Settings:
- Parent category with empty pattern: Sets ACL on
/var/log/azurefor directory traversal without monitoring files - Empty pattern (
"") - Won't match any files, safe for Fluent Bit glob parser apply_to_existing_files: false- Skips unnecessary file ACL application on parent (no files match)- Each subdirectory is a separate category with its own
type(allows different Splunk sourcetypes) recursive: trueon subdirectories - Monitors all subdirectories within each extension (e.g., version folders)
Why the Parent Category is Required:
Without ACL on /var/log/azure, the svc_eoa_fluentbit user cannot traverse into subdirectories like Microsoft.Azure.Monitor.AzureMonitorLinuxAgent, even if those subdirectories have correct ACLs. The rx permission on the parent directory is mandatory for filesystem traversal.
Matches:
- ✅
/var/log/azure/Microsoft.Azure.Monitor.AzureMonitorLinuxAgent/1.29.5/handler.log - ✅
/var/log/azure/Microsoft.Azure.Extensions.CustomScript/status/0.status - ❌
/var/log/azure/extension.log(parent directory, blocked by non-matching pattern) - ❌
/var/log/azure/Microsoft.CPlat.Core.LinuxPatchExtension/handler.log(not in monitored extensions)
Scenario 5: Logs in Select Subdirectories AND Parent Directory
Use Case: Monitor specific subdirectories AND the parent directory, but not all subdirectories.
Example: Monitor /var/log/app/, /var/log/app/frontend/, and /var/log/app/backend/, but not /var/log/app/other/.
Solution: Define separate categories for parent and each subdirectory.
linux_fluentbit_log_access_paths:
# Parent directory
app_root:
type: linux:app
paths:
- /var/log/app
patterns:
- "app.log"
- "error.log"
permissions: rx
file_permissions: r
recursive: false # Only parent directory
default_acl: true # Ensures subdirectories inherit ACL
apply_to_existing_files: true
# Frontend subdirectory
app_frontend:
type: linux:app:frontend
paths:
- /var/log/app/frontend
patterns:
- "*.log"
permissions: rx
file_permissions: r
recursive: false # Only this specific subdirectory
default_acl: true
apply_to_existing_files: true
# Backend subdirectory
app_backend:
type: linux:app:backend
paths:
- /var/log/app/backend
patterns:
- "*.log"
permissions: rx
file_permissions: r
recursive: false # Only this specific subdirectory
default_acl: true
apply_to_existing_files: true
Generated Fluent Bit Paths:
/var/log/app/app.log(fromapp_root)/var/log/app/error.log(fromapp_root)/var/log/app/frontend/*.log(fromapp_frontend)/var/log/app/backend/*.log(fromapp_backend)
Benefits:
- Granular control over which subdirectories are monitored
- Different sourcetypes per subdirectory for Splunk routing
- Parent directory ACL inheritance ensures new subdirectories can be added easily
Configuration Reference
Variable Structure
linux_fluentbit_log_access_paths:
<category_name>:
type: <string> # Splunk sourcetype (e.g., linux:audit)
paths: [<string>, ...] # List of directories to monitor
patterns: [<string>, ...] # Filename patterns (glob syntax)
permissions: <string> # Directory ACL permissions (e.g., rx)
file_permissions: <string> # File ACL permissions (e.g., r)
recursive: <boolean> # true = /**/, false = /
default_acl: <boolean> # Set default ACL for inheritance
apply_to_existing_files: <boolean> # Apply ACL to existing files
Field Descriptions
| Field | Type | Description | Example |
|---|---|---|---|
type | string | Splunk sourcetype identifier | linux:audit, linux:sssd |
paths | list | Directories to monitor | ["/var/log/audit"] |
patterns | list | Filename glob patterns | ["audit.log", "*.log"] |
permissions | string | POSIX ACL for directories (allows traversal) | rx (read + execute) |
file_permissions | string | POSIX ACL for files (read-only) | r (read) |
recursive | boolean | true = monitor subdirectories (/**/), false = parent only (/) | false |
default_acl | boolean | Set default ACL on directories for inheritance | true |
apply_to_existing_files | boolean | Apply ACL to existing files during role execution | true |
Pattern Syntax
Fluent Bit supports standard glob patterns:
*- Matches any characters (zero or more)?- Matches exactly one character[abc]- Matches any character in the set**- Recursive wildcard (matches subdirectories at any depth)
Examples:
audit.log- Exact filename match*.log- Any file ending in.logapp_*.log- Files starting withapp_and ending in.logsssd_[a-z]*.log- SSSD logs starting with lowercase letters
ACL Permissions Explained
Why ACLs are Required
Fluent Bit runs as the svc_eoa_fluentbit user, which needs read access to log files. Since log files are typically owned by root or other service accounts, POSIX ACLs grant read-only access without changing file ownership.
Permission Types
-
Directory Access ACL (
permissions: rx):- Read (
r): List directory contents - Execute (
x): Traverse the directory (required to access files inside)
- Read (
-
File ACL (
file_permissions: r):- Read (
r): Read file contents (execute bit NOT needed for files)
- Read (
-
Default ACL (
default_acl: true):- Applied to directories only
- New files/subdirectories inherit this ACL automatically
- Uses
file_permissions(notpermissions) to avoid execute bit on files
ACL Inheritance
When default_acl: true:
/var/log/audit/ # Access ACL: rx, Default ACL: r
├── audit.log # Inherits: r (from parent default ACL)
└── subdir/ # Inherits: r (from parent default ACL)
└── file.log # Inherits: r (from subdir's default ACL)
Troubleshooting
Logs Not Appearing in Splunk
-
Check Fluent Bit service status:
sudo systemctl status fluent-bit sudo journalctl -u fluent-bit -n 50 -
Verify path existence:
ls -la /var/log/audit/audit.log -
Check ACL permissions:
getfacl /var/log/audit/audit.log # Should show: user:svc_eoa_fluentbit:r-- -
Test pattern matching:
# For recursive: false find /var/log/audit -maxdepth 1 -name "audit.log" # For recursive: true find /var/log/azure -type f -name "*.log" -
Check Fluent Bit configuration:
sudo cat /etc/fluent-bit/99-eoa-fluentbit.conf # Verify INPUT blocks have correct Path directives
Permission Denied Errors
Symptom: journalctl -u fluent-bit shows "Permission denied" errors
Solution:
-
Verify ACL is set:
getfacl /var/log/audit/audit.log -
If missing, re-run Ansible playbook in AWX via the following template:
Install Fluentbit Logger
Recursive Pattern Not Matching
Symptom: recursive: true not matching expected files
Common Issue: /** pattern requires at least one subdirectory level.
Example:
/var/log/azure/**/file.logmatches/var/log/azure/subdir/file.log✅/var/log/azure/**/file.logdoes NOT match/var/log/azure/file.log❌
Solution: Use two categories (one with recursive: false for parent, one with recursive: true for subdirectories).
Best Practices
- Use descriptive category names:
audit,sssd,app_frontend(notlogs1,logs2) - Set
default_acl: trueon parent directories to ensure new subdirectories inherit ACLs - Use
recursive: falsefor parent directories to avoid missing direct children - Group related logs by sourcetype: One category per Splunk sourcetype for easier routing
- Test patterns locally with
findcommands before deploying - Monitor Fluent Bit logs after deployment to verify successful ingestion
Examples from Production
Audit Logs (Direct Children Only)
audit:
type: linux:audit
paths: [/var/log/audit]
patterns: ["audit.log"]
permissions: rx
file_permissions: r
recursive: false # audit.log is a direct child
default_acl: true
apply_to_existing_files: true
SSSD Logs (Multiple Patterns, Direct Children)
sssd:
type: linux:sssd
paths: [/var/log/sssd]
patterns: ["sssd.log", "sssd_*.log"]
permissions: rx
file_permissions: r
recursive: false # All SSSD logs are direct children
default_acl: true
apply_to_existing_files: true
System Logs (Specific Files in High-Volume Directory)
system:
type: linux:system
paths: [/var/log]
patterns: ["messages", "dnf.log"]
permissions: rx
file_permissions: r
recursive: false # Only these specific files, not all /var/log
default_acl: false # Don't set default ACL on /var/log
apply_to_existing_files: true