1
0
Fork 0

Adding upstream version 1.34.4.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-05-24 07:26:29 +02:00
parent e393c3af3f
commit 4978089aab
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
4963 changed files with 677545 additions and 0 deletions

View file

@ -0,0 +1,65 @@
# Defaults Processor Plugin
The _Defaults_ processor allows you to ensure certain fields will always exist
with a specified default value on your metric(s).
There are three cases where this processor will insert a configured default
field.
1. The field is nil on the incoming metric
1. The field is not nil, but its value is an empty string.
1. The field is not nil, but its value is a string of one or more empty spaces.
Telegraf minimum version: Telegraf 1.15.0
## Global configuration options <!-- @/docs/includes/plugin_config.md -->
In addition to the plugin-specific configuration settings, plugins support
additional global and plugin configuration settings. These settings are used to
modify metrics, tags, and field or create aliases and configure ordering, etc.
See the [CONFIGURATION.md][CONFIGURATION.md] for more details.
[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins
## Configuration
```toml @sample.conf
## Set default fields on your metric(s) when they are nil or empty
[[processors.defaults]]
## Ensures a set of fields always exists on your metric(s) with their
## respective default value.
## For any given field pair (key = default), if it's not set, a field
## is set on the metric with the specified default.
##
## A field is considered not set if it is nil on the incoming metric;
## or it is not nil but its value is an empty string or is a string
## of one or more spaces.
## <target-field> = <value>
[processors.defaults.fields]
field_1 = "bar"
time_idle = 0
is_error = true
```
## Example
Ensure a _status\_code_ field with _N/A_ is inserted in the metric when one is
not set in the metric by default:
```toml
[[processors.defaults]]
[processors.defaults.fields]
status_code = "N/A"
```
```diff
- lb,http_method=GET cache_status=HIT,latency=230
+ lb,http_method=GET cache_status=HIT,latency=230,status_code="N/A"
```
Ensure an empty string gets replaced by a default:
```diff
- lb,http_method=GET cache_status=HIT,latency=230,status_code=""
+ lb,http_method=GET cache_status=HIT,latency=230,status_code="N/A"
```

View file

@ -0,0 +1,56 @@
//go:generate ../../../tools/readme_config_includer/generator
package defaults
import (
_ "embed"
"strings"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/plugins/processors"
)
//go:embed sample.conf
var sampleConfig string
// Defaults is a processor for ensuring certain fields always exist
// on your Metrics with at least a default value.
type Defaults struct {
DefaultFieldsSets map[string]interface{} `toml:"fields"`
}
func (*Defaults) SampleConfig() string {
return sampleConfig
}
// Apply contains the main implementation of this processor.
// For each metric in 'inputMetrics', it goes over each default pair.
// If the field in the pair does not exist on the metric, the associated default is added.
// If the field was found, then, if its value is the empty string or one or more spaces, it is replaced
// by the associated default.
func (def *Defaults) Apply(inputMetrics ...telegraf.Metric) []telegraf.Metric {
for _, metric := range inputMetrics {
for defField, defValue := range def.DefaultFieldsSets {
if maybeCurrent, isSet := metric.GetField(defField); !isSet {
metric.AddField(defField, defValue)
} else if trimmed, isStr := maybeTrimmedString(maybeCurrent); isStr && trimmed == "" {
metric.RemoveField(defField)
metric.AddField(defField, defValue)
}
}
}
return inputMetrics
}
func maybeTrimmedString(v interface{}) (string, bool) {
if value, ok := v.(string); ok {
return strings.TrimSpace(value), true
}
return "", false
}
func init() {
processors.Add("defaults", func() telegraf.Processor {
return &Defaults{}
})
}

View file

@ -0,0 +1,200 @@
package defaults
import (
"sync"
"testing"
"time"
"github.com/stretchr/testify/require"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/metric"
"github.com/influxdata/telegraf/testutil"
)
func TestDefaults(t *testing.T) {
scenarios := []struct {
name string
defaults *Defaults
input telegraf.Metric
expected []telegraf.Metric
}{
{
name: "Test that no values are changed since they are not nil or empty",
defaults: &Defaults{
DefaultFieldsSets: map[string]interface{}{
"usage": 30,
"wind_feel": "very chill",
"is_dead": true,
},
},
input: testutil.MustMetric(
"CPU metrics",
map[string]string{},
map[string]interface{}{
"usage": 45,
"wind_feel": "a dragon's breath",
"is_dead": false,
},
time.Unix(0, 0),
),
expected: []telegraf.Metric{
testutil.MustMetric(
"CPU metrics",
map[string]string{},
map[string]interface{}{
"usage": 45,
"wind_feel": "a dragon's breath",
"is_dead": false,
},
time.Unix(0, 0),
),
},
},
{
name: "Tests that the missing fields are set on the metric",
defaults: &Defaults{
DefaultFieldsSets: map[string]interface{}{
"max_clock_gz": 6,
"wind_feel": "Unknown",
"boost_enabled": false,
"variance": 1.2,
},
},
input: testutil.MustMetric(
"CPU metrics",
map[string]string{},
map[string]interface{}{
"usage": 45,
"temperature": 64,
},
time.Unix(0, 0),
),
expected: []telegraf.Metric{
testutil.MustMetric(
"CPU metrics",
map[string]string{},
map[string]interface{}{
"usage": 45,
"temperature": 64,
"max_clock_gz": 6,
"wind_feel": "Unknown",
"boost_enabled": false,
"variance": 1.2,
},
time.Unix(0, 0),
),
},
},
{
name: "Tests that set but empty fields are replaced by specified defaults",
defaults: &Defaults{
DefaultFieldsSets: map[string]interface{}{
"max_clock_gz": 6,
"wind_feel": "Unknown",
"fan_loudness": "Inaudible",
"boost_enabled": false,
},
},
input: testutil.MustMetric(
"CPU metrics",
map[string]string{},
map[string]interface{}{
"max_clock_gz": "",
"wind_feel": " ",
"fan_loudness": " ",
},
time.Unix(0, 0),
),
expected: []telegraf.Metric{
testutil.MustMetric(
"CPU metrics",
map[string]string{},
map[string]interface{}{
"max_clock_gz": 6,
"wind_feel": "Unknown",
"fan_loudness": "Inaudible",
"boost_enabled": false,
},
time.Unix(0, 0),
),
},
},
}
for _, scenario := range scenarios {
t.Run(scenario.name, func(t *testing.T) {
defaults := scenario.defaults
resultMetrics := defaults.Apply(scenario.input)
require.Len(t, resultMetrics, 1)
testutil.RequireMetricsEqual(t, scenario.expected, resultMetrics)
})
}
}
func TestTracking(t *testing.T) {
inputRaw := []telegraf.Metric{
metric.New("foo", map[string]string{}, map[string]interface{}{"value": 42, "topic": "telegraf"}, time.Unix(0, 0)),
metric.New("bar", map[string]string{}, map[string]interface{}{"hours": 23}, time.Unix(0, 0)),
metric.New("baz", map[string]string{}, map[string]interface{}{"status": "fixed"}, time.Unix(0, 0)),
}
var mu sync.Mutex
delivered := make([]telegraf.DeliveryInfo, 0, len(inputRaw))
notify := func(di telegraf.DeliveryInfo) {
mu.Lock()
defer mu.Unlock()
delivered = append(delivered, di)
}
input := make([]telegraf.Metric, 0, len(inputRaw))
for _, m := range inputRaw {
tm, _ := metric.WithTracking(m, notify)
input = append(input, tm)
}
expected := []telegraf.Metric{
metric.New(
"foo",
map[string]string{},
map[string]interface{}{"value": 42, "status": "unknown", "topic": "telegraf"},
time.Unix(0, 0),
),
metric.New(
"bar",
map[string]string{},
map[string]interface{}{"value": 6, "status": "unknown", "hours": 23},
time.Unix(0, 0),
),
metric.New(
"baz",
map[string]string{},
map[string]interface{}{"value": 6, "status": "fixed"},
time.Unix(0, 0),
),
}
plugin := &Defaults{
DefaultFieldsSets: map[string]interface{}{
"value": 6,
"status": "unknown",
},
}
// Process expected metrics and compare with resulting metrics
actual := plugin.Apply(input...)
testutil.RequireMetricsEqual(t, expected, actual)
// Simulate output acknowledging delivery
for _, m := range actual {
m.Accept()
}
// Check delivery
require.Eventuallyf(t, func() bool {
mu.Lock()
defer mu.Unlock()
return len(input) == len(delivered)
}, time.Second, 100*time.Millisecond, "%d delivered but %d expected", len(delivered), len(expected))
}

View file

@ -0,0 +1,15 @@
## Set default fields on your metric(s) when they are nil or empty
[[processors.defaults]]
## Ensures a set of fields always exists on your metric(s) with their
## respective default value.
## For any given field pair (key = default), if it's not set, a field
## is set on the metric with the specified default.
##
## A field is considered not set if it is nil on the incoming metric;
## or it is not nil but its value is an empty string or is a string
## of one or more spaces.
## <target-field> = <value>
[processors.defaults.fields]
field_1 = "bar"
time_idle = 0
is_error = true