# How Metric Tagging and Global Tags Work in Telegraf: Complete Implementation Guide

> Learn how Telegraf implements metric tagging and global tags. Discover how Telegraf merges tags at runtime and resolves tag collisions with this implementation guide.

- Repository: [InfluxData/telegraf](https://github.com/influxdata/telegraf)
- Tags: how-to-guide
- Published: 2026-05-14

---

**Telegraf merges global tags with plugin-specific tags at runtime via the `makeMetric` function, giving precedence to plugin-level tags when keys collide.**

Telegraf, the open-source server agent from InfluxData, implements a sophisticated two-stage tagging system that automatically decorates every metric with configuration-wide metadata. Understanding how metric tagging and global tags work requires examining the internal pipeline where configuration settings transform into runtime tag maps. This guide analyzes the source code to explain exactly how tags propagate from your [`telegraf.conf`](https://github.com/influxdata/telegraf/blob/main/telegraf.conf) file to the final output.

## Parsing the Global Tags Configuration

Global tags originate in the `[global_tags]` section of your Telegraf configuration file. When Telegraf starts, the configuration parser extracts these key-value pairs and stores them in `Config.Tags`, a `map[string]string` defined in [`config/config.go`](https://github.com/influxdata/telegraf/blob/main/config/config.go) at line 289.

```toml

# telegraf.conf

[global_tags]
  env   = "production"
  owner = "platform-team"
  region = "us-east-1"

[agent]
  interval = "10s"

```

According to the `influxdata/telegraf` source code, this map remains in memory as part of the global configuration object until the agent initializes individual input plugins.

## Propagating Tags to Input Instances

During agent startup, Telegraf distributes global tags to each input through the `RunningInput.SetDefaultTags` method. This handshake occurs in [`models/running_input.go`](https://github.com/influxdata/telegraf/blob/main/models/running_input.go), where the method receives a copy of the global tag map and stores it in the `defaultTags` field:

```go
// models/running_input.go
func (r *RunningInput) SetDefaultTags(tags map[string]string) {
    r.defaultTags = tags
}

```

Each `RunningInput` instance maintains its own `defaultTags` map, ensuring that global tags are available during the metric gathering phase while isolating inputs from each other.

## Merging Tags During Metric Creation

The actual tagging logic executes when an input produces metrics. Every input's `Gather` method creates raw `telegraf.Metric` objects, but before these reach the output sinks, `RunningInput.MakeMetric` processes them through the `makeMetric` function in [`models/makemetric.go`](https://github.com/influxdata/telegraf/blob/main/models/makemetric.go) (lines 7-34).

This function receives both the plugin-specific tags (`r.Config.Tags`) and the global tags (`r.defaultTags`), applying them in two distinct phases:

```go
// models/makemetric.go – makeMetric (lines 7-34)
func makeMetric(metric telegraf.Metric,
    nameOverride, namePrefix, nameSuffix string,
    tags, globalTags map[string]string) telegraf.Metric {
    
    // Apply name overrides, prefixes, and suffixes...
    
    // Phase 1: Apply plugin-wide tags
    for k, v := range tags {
        if _, ok := metric.GetTag(k); !ok {
            metric.AddTag(k, v)
        }
    }
    
    // Phase 2: Apply global tags (only if key doesn't exist)
    for k, v := range globalTags {
        if _, ok := metric.GetTag(k); !ok {
            metric.AddTag(k, v)
        }
    }
    return metric
}

```

**Plugin tags take precedence**: The function checks `metric.GetTag(k)` before adding each tag, meaning plugin-specific tags override global tags when keys collide. This priority system allows inputs to enforce critical metadata while still inheriting default labels.

## Handling Empty Metrics with `always_include_global_tags`

By default, Telegraf only adds global tags to metrics that contain at least one field. However, the `[agent]` configuration section exposes the `always_include_global_tags` boolean flag to modify this behavior.

When set to `true`, the agent forces global tags onto every metric—even empty ones. This flag is read from `InputConfig.AlwaysIncludeGlobalTags` in [`config/config.go`](https://github.com/influxdata/telegraf/blob/main/config/config.go) and honored inside `RunningInput.MakeMetric` through a conditional block that re-invokes the tagging logic for metrics that would otherwise skip processing.

```toml
[agent]
  interval = "10s"
  always_include_global_tags = true

```

## Parser Integration for Line-Based Inputs

Many Telegraf inputs rely on parsers to convert raw bytes into structured metrics. These parsers implement a `SetDefaultTags` method that mirrors the input plugin behavior, storing a copy of the global tag map for use during the parsing phase.

As implemented in `plugins/parsers/*/*.go`, parsers merge global tags into each newly created metric during the parsing routine, ensuring that line-based protocols (such as JSON, CSV, or InfluxDB line protocol) receive the same metadata treatment as native plugin metrics.

## Complete Tagging Lifecycle Example

The following Go code demonstrates the tagging pipeline programmatically, simulating how `RunningInput.MakeMetric` processes a CPU metric:

```go
package main

import (
    "fmt"
    "time"
    
    "github.com/influxdata/telegraf"
    "github.com/influxdata/telegraf/models"
)

func main() {
    // Simulate an input creating a base metric
    m, _ := telegraf.NewMetric(
        "cpu",
        map[string]string{"cpu": "cpu-total"},
        map[string]interface{}{"usage_idle": 99.5},
        time.Now(),
    )
    
    // Global tags from [global_tags] configuration
    globalTags := map[string]string{
        "env":   "production",
        "owner": "platform-team",
    }
    
    // Plugin-specific tags from [[inputs.cpu]] configuration
    pluginTags := map[string]string{
        "datacenter": "ny1",
    }
    
    // Apply tags as RunningInput.MakeMetric does
    finalMetric := models.MakeMetric(
        m, "", "", "", pluginTags, globalTags,
    )
    
    fmt.Printf("Final tags: %v\n", finalMetric.Tags())
    // Output includes: cpu=cpu-total, datacenter=ny1, 
    //                  env=production, owner=platform-team
}

```

## Summary

- **Global tags** are defined in the `[global_tags]` configuration section and stored in `Config.Tags` within [`config/config.go`](https://github.com/influxdata/telegraf/blob/main/config/config.go).
- **Tag propagation** occurs via `RunningInput.SetDefaultTags`, which stores global tags in each input's `defaultTags` field.
- **Merge priority** follows a "plugin wins" rule: `makeMetric` in [`models/makemetric.go`](https://github.com/influxdata/telegraf/blob/main/models/makemetric.go) applies plugin tags first, then global tags only if the key does not already exist.
- **Empty metrics** skip global tagging by default, unless `always_include_global_tags = true` is set in the `[agent]` section.
- **Parsers** implement `SetDefaultTags` to ensure line-based inputs receive global metadata during the parsing phase.

## Frequently Asked Questions

### What happens when a plugin tag conflicts with a global tag?

Plugin tags take precedence over global tags. When `makeMetric` executes in [`models/makemetric.go`](https://github.com/influxdata/telegraf/blob/main/models/makemetric.go), it checks `metric.GetTag(k)` before adding any tag. If the metric already contains the key from the plugin's local configuration, the global tag value is skipped, ensuring input-specific metadata overrides configuration defaults.

### How do I force Telegraf to add global tags to metrics without fields?

Set `always_include_global_tags = true` in the `[agent]` section of your [`telegraf.conf`](https://github.com/influxdata/telegraf/blob/main/telegraf.conf). By default, Telegraf only decorates metrics that contain fields. Enabling this flag forces the agent to process global tags for every metric, including empty ones, by modifying the conditional logic in `RunningInput.MakeMetric`.

### Where does Telegraf store global tags in memory?

Global tags reside in the `Tags` field of the `Config` struct, defined as `map[string]string` in [`config/config.go`](https://github.com/influxdata/telegraf/blob/main/config/config.go) at line 289. During runtime, each `RunningInput` receives a copy of this map stored in its `defaultTags` field, as implemented in [`models/running_input.go`](https://github.com/influxdata/telegraf/blob/main/models/running_input.go).

### Do output plugins receive metrics with global tags already applied?

Yes. The tagging occurs in the input stage before metrics reach the agent's internal metric channel. When `RunningInput.MakeMetric` returns the processed metric, it already contains both plugin-specific and global tags merged into the internal tag map. Output plugins serialize these fully decorated metrics without additional tag manipulation.