Architecture
Big picture
A running Fluentd is a supervisor process that manages one or more worker processes (lib/fluent/supervisor.rb:570). Each worker builds a tree of plugins from the configuration file and then runs it. At the root of that tree is the RootAgent (lib/fluent/root_agent.rb:48), which holds the <source>, <filter>, <match>, and <label> blocks. Events enter from input plugins, get a tag, flow through an EventRouter that matches the tag to a chain of filters and an output, and end up buffered for delivery.
Components
Supervisor and workers
Fluent::Supervisor (lib/fluent/supervisor.rb:570) owns process lifecycle, configuration reload, and socket inheritance. run_supervisor (lib/fluent/supervisor.rb:689) loads the configuration with Fluent::Engine.run_configure (lib/fluent/supervisor.rb:721), and each worker calls run_worker (lib/fluent/supervisor.rb:758), which configures and then calls Fluent::Engine.run (lib/fluent/supervisor.rb:783).
RootAgent and labels
RootAgent (lib/fluent/root_agent.rb:48) is the root of the plugin tree. It binds inputs, filters, and matches, and groups them under <label> blocks. Each label has its own independent EventRouter. A built-in @ERROR label (ERROR_LABEL, lib/fluent/root_agent.rb:49) receives events that failed downstream. SourceOnlyMode (lib/fluent/root_agent.rb:51) is an input-only buffering mode used for zero-downtime restarts.
EventRouter
EventRouter (lib/fluent/event_router.rb:44) is the routing core. It maps a tag to a collector, which can be an output, a filter pipeline, or another router. It keeps a Rule list (lib/fluent/event_router.rb:57), an LRU MatchCache (lib/fluent/event_router.rb:140), and builds a Pipeline (lib/fluent/event_router.rb:165) for each matched tag.
Plugins and buffer
Built-in plugins live under lib/fluent/plugin/ as in_*.rb, out_*.rb, filter_*.rb, parser_*.rb, formatter_*.rb, and buf_*.rb. Output buffering is handled by Buffer (lib/fluent/plugin/buffer.rb:26), which groups events into chunks keyed by Metadata (lib/fluent/plugin/buffer.rb:72).
How a request flows
- An input plugin emits.
in_tailcallsrouter.emit(tag, time, record)(lib/fluent/plugin/in_tail.rb:705);in_forwardcallsrouter.emit_stream(tag, es)(lib/fluent/plugin/in_forward.rb:322). EventRouter#emitwraps a single record in aOneEventStreamand delegates toemit_stream(lib/fluent/event_router.rb:104).emit_streamcallsmatch(tag).emit_events(tag, es)and routesPipeline::OutputErrorto the@ERRORhandler (lib/fluent/event_router.rb:114).match(tag)checks the LRUMatchCacheand on a miss runsfind(tag)(lib/fluent/event_router.rb:133), which scans the rules and builds aPipelineending in an output (lib/fluent/event_router.rb:287).Pipeline#emit_eventsruns the filter chain, then hands the result to the output'semit_events(lib/fluent/event_router.rb:192).Output#emit_events(lib/fluent/plugin/output.rb:876) branches on@buffering: non-buffered goes throughemit_sync(lib/fluent/plugin/output.rb:885), buffered throughemit_buffered(lib/fluent/plugin/output.rb:897).- Buffered output computes chunk keys with
metadata(tag, time, record)(lib/fluent/plugin/output.rb:912) and appends events to a chunk viaBuffer#write(lib/fluent/plugin/buffer.rb:330). A full chunk is enqueued byenqueue_chunk(lib/fluent/plugin/buffer.rb:482), and a flush thread dequeues it (lib/fluent/plugin/buffer.rb:559) to call the plugin'swrite(lib/fluent/plugin/output.rb:118).
Key design decisions
Tags drive everything. Routing, buffering chunk keys, and the error path all key off the event tag rather than message content, which keeps the hot path simple. Delivery is asynchronous by default: buffered outputs return as soon as the event is written to a chunk, and a separate flush thread handles delivery and retry with exponential backoff. Time is carried at nanosecond precision through a custom MessagePack extension type while staying backward compatible with integer-second timestamps (see Internals).
Extension points
Every category of behavior is a plugin: inputs, outputs, filters, parsers, formatters, and buffer backends, all under lib/fluent/plugin/. Plugin authors reuse common mixins from lib/fluent/plugin_helper/ (timer, server, socket, storage, thread, retry_state). Buffer backends ship as buf_memory, buf_file, and buf_file_single.