Skip to main content
It’s 2:14 AM and Bob is staring at Kibana: something about logins is wrong. He searches for locked accounts and finds the line immediately: User 5 failed to log in, account locked. That tells Bob a problem exists, but not where it came from. Which pod wrote it? Production or a stray test cluster?
An infographic titled "Two in the Morning" showing a user labeled "Bob" and two server copies labeled "production" and "test." A notification points to the production box reading "USER5 failed to log in, account locked" above a small smiling robot, with the caption "Which copy?" below.
When Bob opens the raw record, all he finds is:
All the context—pod name, cluster, environment, team—existed briefly on the node but never made it into Elasticsearch. Why? Because Fluentd only forwards the fields it is told to keep. It reads the line, decomposes it into pieces, and forwards those pieces. If you want additional metadata (for example team or environment) attached to each record, something must add those fields while the record is passing through Fluentd.
A dark-themed diagram titled "Fluentd Stores What It's Told" showing node01 sending data to Fluentd, which forwards it to Elasticsearch. Tags like "team", "time", "stream", and "log" appear above and a user icon labeled "Bob" is shown at the end.

Log Enrichment: Filters and Plugins

Fluentd’s pipeline is normally: Read → (optional) Filter → Send. The filter stage is where you enrich, parse, or drop records. If you need extra context, the filter step is not optional.
A slide titled "A Step in the Middle" showing a simple person icon standing on a highlighted middle step. A dashed progress bar labeled Read — Filter — Send sits below, with tag-like buttons (record, time, stream, log, team) and a KodeKloud logo in the corner.
Think of a log line sliding under a stamp that adds the label environment: production before the line continues. Fluentd includes many built-in filters (for example record_transformer, parser, or kubernetes_metadata). When none of the built-in filters does exactly what you need, you can create a small custom filter plugin. A Fluentd plugin is a Ruby file that Fluentd loads at startup. A filter plugin receives each record, can mutate it, and returns it. For simple enrichment (add team and environment if missing), a custom plugin can be only a few lines. Example Fluentd config block that references a custom filter plugin:
Example custom Fluentd filter plugin (Ruby). This adds team and environment fields if they are missing:
Place the plugin file in Fluentd’s plugin directory (for example /etc/fluent/plugin) and enable it in your Fluentd config, passing desired parameters:
Remember to restart Fluentd after placing a plugin file so Fluentd loads it at startup.
Adding this context to each record is called log enrichment. With enrichment in place, Bob’s records will include the fields he needs to know which copy produced the locked-account message.

Index Lifecycle: Rollover and Retention

Even with enrichment solved, another operational problem remains: index growth and disk usage. By default Fluentd/ELK deployments commonly create a new index per day (for example fluentd-2026.10.13). A quiet day produces a small index; a busy month-end might create a very large one. If indices accumulate indefinitely, disk fills up.
A diagram titled "One New Index Every Day" showing the Fluentd logo on the left sending data (dashed arrow) to a dated index labeled "fluentd-2026.10.13" with a row of cylindrical database/storage icons below. It illustrates daily index creation/storage of incoming logs.
Bob has been deleting old indices manually on Fridays, but humans forget. When that happens, the disk fills and Elasticsearch can no longer accept new documents.
An infographic titled "The Friday He Forgets" showing several cylindrical disk/database icons with varying fill levels, a sad user icon labeled "Bob" next to a crossed-out "Friday" calendar, and a large "100% Disk" indicator. The bottom caption reads "Disk full."
The solution is to write rules that Elasticsearch enforces automatically: when an index reaches a size threshold or age, rollover to a fresh index; when older indices pass a retention period, delete them. Elasticsearch Index Lifecycle Management (ILM) does exactly this. A typical policy example:
  • Rollover when an index reaches 5 GB or 30 days (whichever comes first) — the “hot” phase.
  • Delete indices once they are 90 days old — the “delete” phase.
An infographic titled "Index Lifecycle Management" showing a lifecycle policy box that lists "Rollover – 5 GB" and "Delete – 90 days." Below it are three stacked cylinder icons grouped under "Delete phase" and "Hot phase" to illustrate changing index sizes.
Key ILM concepts:
  • Hot phase: the index is actively written to.
  • Rollover: switch from the current concrete index (e.g., fluentd-000001) to a new one when size/age limits are reached.
  • Delete phase: remove indices after retention expires.
  • Use a write alias (for example fluentd-write) that points to the current write index — ILM manages the concrete indices beneath that alias.
Two operational rules to remember:
  1. If you need context that isn’t in the original log line, add it in Fluentd while the event flows through the pipeline — you cannot reconstruct it reliably later.
  2. If data has a known shelf life, encode that shelf life in an ILM policy rather than relying on manual deletions.

Implementation: Enrichment + ILM (Step-by-step)

Below are the concrete steps and example snippets to implement both log enrichment (Fluentd filter plugin) and automated index lifecycle (Elasticsearch ILM and template).
  1. Create the Fluentd filter plugin and enable it
  • Place the Ruby plugin file (example above) into Fluentd’s plugin directory, for example /etc/fluent/plugin/my_custom_filter.rb.
  • Add a filter block to Fluentd config to enable the plugin and pass parameters:
  1. Create an ILM policy in Elasticsearch
  • Define a lifecycle policy that rollovers at 5 GB or 30 days and deletes at 90 days:
  1. Configure an index template and write alias for rollover
  • ILM rollovers work best when writing to an alias like fluentd-write. Attach the ILM policy via an index template and define the alias:
  • Create the initial concrete index and mark the alias as the write index:
  1. Point Fluentd at the write alias
  • Configure Fluentd’s Elasticsearch output to write to the alias name so ILM can rollover the underlying concrete indices:
With this configuration in place:
  • Fluentd enriches each record as it passes through the filter, so you can query by team or environment in Kibana and find which copy produced the locked-account message.
  • Elasticsearch ILM rollovers indices and deletes them after the retention period, preventing disk-full surprises and removing the need for manual index cleanup.

Quick reference

Summary

  • Use Fluentd filters or custom plugin filters to enrich logs as they pass through the pipeline — add team, environment, pod names, etc. at ingestion time.
  • Use Elasticsearch ILM (rollover + delete) to automate lifecycle management and avoid manual deletions and disk exhaustion.
  • Combine both: enrichment ensures logs have the context needed to answer operational questions; ILM ensures logs don’t consume unbounded storage.
Deploy the plugin and ILM changes, restart Fluentd and Elasticsearch where necessary, and Bob will be able to find which copy produced the locked-account message — and you will not need to remind anyone about Friday cleanups anymore.

Watch Video