Telegraf Agent Interval and Flush Interval Configuration: A Complete Guide

Telegraf separates data collection from data transmission using two distinct timers: agent.interval controls how often inputs gather metrics (default 10s), while flush_interval controls how often outputs send buffered metrics to destinations (default 10s), each configurable globally or per-plugin.

The influxdata/telegraf repository implements these dual timers to give operators fine-grained control over resource utilization and data latency. Understanding the distinction between the agent interval and flush interval is essential for tuning performance, as the settings control different stages of the metric pipeline and interact with internal buffering mechanisms defined in config/config.go and agent/agent.go.

What Are Agent Interval and Flush Interval?

Telegraf’s runtime relies on two independent timing configurations that govern distinct phases of the metric lifecycle.

Agent Interval (Collection Timing)

The agent interval defines the period between successive gather cycles of input plugins. Located in the AgentConfig struct in config/config.go, the Interval field sets the global default for how frequently inputs produce metrics.

When the agent starts, the Agent.runInputs method sleeps for Agent.Config.Interval (plus any configured jitter or offset) before invoking each input’s Gather method. This determines how often raw metrics are generated from system sources.

Flush Interval (Output Timing)

The flush interval controls when buffered metrics are written to output plugins. Defined in AgentConfig.FlushInterval in config/config.go, this setting initializes the global timer used in agent/agent.go within the runOutputs function.

Each output plugin runs its own flush loop. If an output defines its own flush_interval in its TOML configuration block, that value overrides the global default. The timer also respects flush_jitter, which introduces random delay to prevent thundering herd problems when multiple agents flush simultaneously.

How the Intervals Work in the Telegraf Source Code

The separation of concerns is enforced at the architectural level through distinct Go structs and control loops.

Configuration Structure

In config/config.go, the AgentConfig struct stores both timing values alongside related jitter fields:

type AgentConfig struct {
    Interval      internal.Duration `toml:"interval"`
    FlushInterval internal.Duration `toml:"flush_interval"`
    FlushJitter   internal.Duration `toml:"flush_jitter"`
    // ... additional fields
}

This struct is populated when Telegraf parses telegraf.conf at startup.

Collection Loop Implementation

The Agent.runInputs function manages the input side of the pipeline. It sleeps for Agent.Config.Interval between gather cycles, creating a steady cadence of metric generation independent of downstream transmission.

Flush Loop Implementation

The output logic resides in agent/agent.go (around lines 331-447). Here, the runOutputs function initializes per-output timers using the global FlushInterval unless overridden:

interval := time.Duration(a.Config.Agent.FlushInterval)
jitter   := time.Duration(a.Config.Agent.FlushJitter)

for _, output := range unit.outputs {
    // Per-output overrides
    if output.Config.FlushInterval != 0 {
        interval = output.Config.FlushInterval
    }
    if output.Config.FlushJitter != 0 {
        jitter = output.Config.FlushJitter
    }

    go func(o *models.RunningOutput) {
        timer := clock.NewTimer(interval, jitter)
        a.flushLoop(ctx, o, timer)
    }(output)
}

While the flush timer waits, metrics accumulate in a per-output buffer up to MetricBufferLimit. When the timer fires, the buffer flushes in batches sized by MetricBatchSize.

Configuring Intervals in telegraf.conf

Both intervals accept Go duration strings (e.g., "10s", "1m", "500ms").

Global Defaults

Set application-wide defaults in the [agent] section:

[agent]
  ## Default collection interval for all inputs

  interval = "10s"

  ## Default flushing interval for all outputs

  flush_interval = "10s"
  flush_jitter = "0s"

These values are defined as defaults in cmd/telegraf/telegraf.go and loaded into the AgentConfig struct during initialization.

Per-Output Override

Individual outputs can override the global flush interval:

[[outputs.influxdb]]
  urls = ["http://localhost:8086"]
  ## Flush every 30 seconds for this output only

  flush_interval = "30s"

When Telegraf builds the output unit, the code in agent/agent.go (lines 40-44) detects the non-zero output.Config.FlushInterval and substitutes it for the global value.

Programmatic Inspection

You can inspect these values at runtime:

cfg, _ := config.NewConfig()
cfg.LoadConfig("telegraf.conf")
agent := agent.NewAgent(cfg)

fmt.Println("Global interval:", cfg.Agent.Interval)
fmt.Println("Global flush:", cfg.Agent.FlushInterval)

for _, out := range agent.Config.Outputs {
    if out.FlushInterval != 0 {
        fmt.Printf("Output %s uses custom flush: %s\n", out.Name, out.FlushInterval)
    }
}

Interaction Between Collection and Flush Cycles

The relationship between these timers affects memory usage and data freshness.

  • Agent Interval drives metric generation (input side).
  • Flush Interval drives metric transmission (output side).

If flush_interval is shorter than agent.interval, the output may flush empty buffers or partial data more frequently than new metrics arrive. Conversely, a longer flush_interval causes metrics to accumulate in memory, increasing batch sizes but reducing write-frequency overhead.

On graceful shutdown, the agent executes flushOnce in agent/agent.go to ensure all buffered metrics reach their destinations regardless of remaining timer duration.

Summary

  • Agent interval (agent.interval) controls input collection cadence and is defined in config/config.go as AgentConfig.Interval.
  • Flush interval (flush_interval) controls output transmission timing, defined in config/config.go as AgentConfig.FlushInterval and implemented in agent/agent.go.
  • Both default to 10s but can be tuned independently to balance latency against resource overhead.
  • Per-output flush_interval overrides in TOML configuration take precedence over global settings.
  • flush_jitter adds randomization to prevent synchronized flush spikes across agent fleets.

Frequently Asked Questions

What happens if flush_interval is shorter than agent.interval?

When the flush timer fires more frequently than inputs produce data, the output may transmit empty buffers or small batches. This increases network overhead without improving data freshness, as the flush cycle will simply export whatever has accumulated since the last gather cycle.

Can I set different flush intervals for different outputs?

Yes. Each output plugin can define its own flush_interval in its TOML configuration block. The agent logic in agent/agent.go checks if output.Config.FlushInterval != 0 and uses that value instead of the global AgentConfig.FlushInterval, allowing you to batch high-volume outputs frequently while sending low-priority outputs less often.

How does flush_jitter affect the flush interval?

flush_jitter adds a random duration between zero and the specified jitter value to each flush interval. According to the source in agent/agent.go, the actual sleep duration becomes flush_interval + random(0, flush_jitter). This prevents multiple Telegraf instances from synchronizing their flush operations and overwhelming downstream systems with simultaneous write spikes.

Where are the default interval values defined in the source code?

The default values of 10s for both intervals are established in cmd/telegraf/telegraf.go within the default agent configuration constants. These populate the AgentConfig struct in config/config.go when no explicit value is provided in the configuration file.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →