Adding upstream version 1.34.4.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
e393c3af3f
commit
4978089aab
4963 changed files with 677545 additions and 0 deletions
68
plugins/processors/date/README.md
Normal file
68
plugins/processors/date/README.md
Normal file
|
@ -0,0 +1,68 @@
|
|||
# Date Processor Plugin
|
||||
|
||||
Use the `date` processor to add the metric timestamp as a human readable tag.
|
||||
|
||||
A common use is to add a tag that can be used to group by month or year.
|
||||
|
||||
A few example usecases include:
|
||||
|
||||
1) consumption data for utilities on per month basis
|
||||
2) bandwidth capacity per month
|
||||
3) compare energy production or sales on a yearly or monthly basis
|
||||
|
||||
## 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
|
||||
# Dates measurements, tags, and fields that pass through this filter.
|
||||
[[processors.date]]
|
||||
## New tag to create
|
||||
tag_key = "month"
|
||||
|
||||
## New field to create (cannot set both field_key and tag_key)
|
||||
# field_key = "month"
|
||||
|
||||
## Date format string, must be a representation of the Go "reference time"
|
||||
## which is "Mon Jan 2 15:04:05 -0700 MST 2006".
|
||||
date_format = "Jan"
|
||||
|
||||
## If destination is a field, date format can also be one of
|
||||
## "unix", "unix_ms", "unix_us", or "unix_ns", which will insert an integer field.
|
||||
# date_format = "unix"
|
||||
|
||||
## Offset duration added to the date string when writing the new tag.
|
||||
# date_offset = "0s"
|
||||
|
||||
## Timezone to use when creating the tag or field using a reference time
|
||||
## string. This can be set to one of "UTC", "Local", or to a location name
|
||||
## in the IANA Time Zone database.
|
||||
## example: timezone = "America/Los_Angeles"
|
||||
# timezone = "UTC"
|
||||
```
|
||||
|
||||
### timezone
|
||||
|
||||
On Windows, only the `Local` and `UTC` zones are available by default. To use
|
||||
other timezones, set the `ZONEINFO` environment variable to the location of
|
||||
[`zoneinfo.zip`][zoneinfo]:
|
||||
|
||||
```text
|
||||
set ZONEINFO=C:\zoneinfo.zip
|
||||
```
|
||||
|
||||
## Example
|
||||
|
||||
```diff
|
||||
- throughput lower=10i,upper=1000i,mean=500i 1560540094000000000
|
||||
+ throughput,month=Jun lower=10i,upper=1000i,mean=500i 1560540094000000000
|
||||
```
|
||||
|
||||
[zoneinfo]: https://github.com/golang/go/raw/50bd1c4d4eb4fac8ddeb5f063c099daccfb71b26/lib/time/zoneinfo.zip
|
77
plugins/processors/date/date.go
Normal file
77
plugins/processors/date/date.go
Normal file
|
@ -0,0 +1,77 @@
|
|||
//go:generate ../../../tools/readme_config_includer/generator
|
||||
package date
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/influxdata/telegraf"
|
||||
"github.com/influxdata/telegraf/config"
|
||||
"github.com/influxdata/telegraf/plugins/processors"
|
||||
)
|
||||
|
||||
//go:embed sample.conf
|
||||
var sampleConfig string
|
||||
|
||||
const defaultTimezone = "UTC"
|
||||
|
||||
type Date struct {
|
||||
TagKey string `toml:"tag_key"`
|
||||
FieldKey string `toml:"field_key"`
|
||||
DateFormat string `toml:"date_format"`
|
||||
DateOffset config.Duration `toml:"date_offset"`
|
||||
Timezone string `toml:"timezone"`
|
||||
|
||||
location *time.Location
|
||||
}
|
||||
|
||||
func (*Date) SampleConfig() string {
|
||||
return sampleConfig
|
||||
}
|
||||
|
||||
func (d *Date) Init() error {
|
||||
// Check either TagKey or FieldKey specified
|
||||
if len(d.FieldKey) > 0 && len(d.TagKey) > 0 {
|
||||
return errors.New("field_key and tag_key cannot be specified at the same time")
|
||||
} else if len(d.FieldKey) == 0 && len(d.TagKey) == 0 {
|
||||
return errors.New("at least one of field_key or tag_key must be specified")
|
||||
}
|
||||
|
||||
// LoadLocation returns UTC if timezone is the empty string.
|
||||
var err error
|
||||
d.location, err = time.LoadLocation(d.Timezone)
|
||||
return err
|
||||
}
|
||||
|
||||
func (d *Date) Apply(in ...telegraf.Metric) []telegraf.Metric {
|
||||
for _, point := range in {
|
||||
tm := point.Time().In(d.location).Add(time.Duration(d.DateOffset))
|
||||
if len(d.TagKey) > 0 {
|
||||
point.AddTag(d.TagKey, tm.Format(d.DateFormat))
|
||||
} else if len(d.FieldKey) > 0 {
|
||||
switch d.DateFormat {
|
||||
case "unix":
|
||||
point.AddField(d.FieldKey, tm.Unix())
|
||||
case "unix_ms":
|
||||
point.AddField(d.FieldKey, tm.UnixNano()/1000000)
|
||||
case "unix_us":
|
||||
point.AddField(d.FieldKey, tm.UnixNano()/1000)
|
||||
case "unix_ns":
|
||||
point.AddField(d.FieldKey, tm.UnixNano())
|
||||
default:
|
||||
point.AddField(d.FieldKey, tm.Format(d.DateFormat))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return in
|
||||
}
|
||||
|
||||
func init() {
|
||||
processors.Add("date", func() telegraf.Processor {
|
||||
return &Date{
|
||||
Timezone: defaultTimezone,
|
||||
}
|
||||
})
|
||||
}
|
294
plugins/processors/date/date_test.go
Normal file
294
plugins/processors/date/date_test.go
Normal file
|
@ -0,0 +1,294 @@
|
|||
package date
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/influxdata/telegraf"
|
||||
"github.com/influxdata/telegraf/config"
|
||||
"github.com/influxdata/telegraf/metric"
|
||||
"github.com/influxdata/telegraf/testutil"
|
||||
)
|
||||
|
||||
func TestTagAndField(t *testing.T) {
|
||||
plugin := &Date{
|
||||
TagKey: "month",
|
||||
FieldKey: "month",
|
||||
}
|
||||
require.Error(t, plugin.Init())
|
||||
}
|
||||
|
||||
func TestNoOutputSpecified(t *testing.T) {
|
||||
plugin := &Date{}
|
||||
require.Error(t, plugin.Init())
|
||||
}
|
||||
|
||||
func TestMonthTag(t *testing.T) {
|
||||
now := time.Now()
|
||||
month := now.Format("Jan")
|
||||
|
||||
input := []telegraf.Metric{
|
||||
metric.New("foo", map[string]string{}, map[string]interface{}{"value": 42}, now),
|
||||
metric.New("bar", map[string]string{}, map[string]interface{}{"value": 42}, now),
|
||||
metric.New("baz", map[string]string{}, map[string]interface{}{"value": 42}, now),
|
||||
}
|
||||
|
||||
expected := []telegraf.Metric{
|
||||
metric.New("foo", map[string]string{"month": month}, map[string]interface{}{"value": 42}, now),
|
||||
metric.New("bar", map[string]string{"month": month}, map[string]interface{}{"value": 42}, now),
|
||||
metric.New("baz", map[string]string{"month": month}, map[string]interface{}{"value": 42}, now),
|
||||
}
|
||||
|
||||
plugin := &Date{
|
||||
TagKey: "month",
|
||||
DateFormat: "Jan",
|
||||
}
|
||||
require.NoError(t, plugin.Init())
|
||||
|
||||
actual := plugin.Apply(input...)
|
||||
testutil.RequireMetricsEqual(t, expected, actual)
|
||||
}
|
||||
|
||||
func TestMonthField(t *testing.T) {
|
||||
now := time.Now()
|
||||
month := now.Format("Jan")
|
||||
|
||||
input := []telegraf.Metric{
|
||||
metric.New("foo", map[string]string{}, map[string]interface{}{"value": 42}, now),
|
||||
metric.New("bar", map[string]string{}, map[string]interface{}{"value": 42}, now),
|
||||
metric.New("baz", map[string]string{}, map[string]interface{}{"value": 42}, now),
|
||||
}
|
||||
|
||||
expected := []telegraf.Metric{
|
||||
metric.New("foo", map[string]string{}, map[string]interface{}{"value": 42, "month": month}, now),
|
||||
metric.New("bar", map[string]string{}, map[string]interface{}{"value": 42, "month": month}, now),
|
||||
metric.New("baz", map[string]string{}, map[string]interface{}{"value": 42, "month": month}, now),
|
||||
}
|
||||
|
||||
plugin := &Date{
|
||||
FieldKey: "month",
|
||||
DateFormat: "Jan",
|
||||
}
|
||||
require.NoError(t, plugin.Init())
|
||||
|
||||
actual := plugin.Apply(input...)
|
||||
testutil.RequireMetricsEqual(t, expected, actual)
|
||||
}
|
||||
|
||||
func TestOldDateTag(t *testing.T) {
|
||||
now := time.Date(1993, 05, 27, 0, 0, 0, 0, time.UTC)
|
||||
|
||||
input := []telegraf.Metric{
|
||||
metric.New("foo", map[string]string{}, map[string]interface{}{"value": 42}, now),
|
||||
metric.New("bar", map[string]string{}, map[string]interface{}{"value": 42}, now),
|
||||
metric.New("baz", map[string]string{}, map[string]interface{}{"value": 42}, now),
|
||||
}
|
||||
|
||||
expected := []telegraf.Metric{
|
||||
metric.New("foo", map[string]string{"year": "1993"}, map[string]interface{}{"value": 42}, now),
|
||||
metric.New("bar", map[string]string{"year": "1993"}, map[string]interface{}{"value": 42}, now),
|
||||
metric.New("baz", map[string]string{"year": "1993"}, map[string]interface{}{"value": 42}, now),
|
||||
}
|
||||
|
||||
plugin := &Date{
|
||||
TagKey: "year",
|
||||
DateFormat: "2006",
|
||||
}
|
||||
require.NoError(t, plugin.Init())
|
||||
|
||||
actual := plugin.Apply(input...)
|
||||
testutil.RequireMetricsEqual(t, expected, actual)
|
||||
}
|
||||
|
||||
func TestFieldUnix(t *testing.T) {
|
||||
now := time.Now()
|
||||
ts := now.Unix()
|
||||
|
||||
input := []telegraf.Metric{
|
||||
metric.New("foo", map[string]string{}, map[string]interface{}{"value": 42}, now),
|
||||
metric.New("bar", map[string]string{}, map[string]interface{}{"value": 42}, now),
|
||||
metric.New("baz", map[string]string{}, map[string]interface{}{"value": 42}, now),
|
||||
}
|
||||
|
||||
expected := []telegraf.Metric{
|
||||
metric.New("foo", map[string]string{}, map[string]interface{}{"value": 42, "unix": ts}, now),
|
||||
metric.New("bar", map[string]string{}, map[string]interface{}{"value": 42, "unix": ts}, now),
|
||||
metric.New("baz", map[string]string{}, map[string]interface{}{"value": 42, "unix": ts}, now),
|
||||
}
|
||||
|
||||
plugin := &Date{
|
||||
FieldKey: "unix",
|
||||
DateFormat: "unix",
|
||||
}
|
||||
require.NoError(t, plugin.Init())
|
||||
|
||||
actual := plugin.Apply(input...)
|
||||
testutil.RequireMetricsEqual(t, expected, actual)
|
||||
}
|
||||
|
||||
func TestFieldUnixNano(t *testing.T) {
|
||||
now := time.Now()
|
||||
ts := now.UnixNano()
|
||||
|
||||
input := []telegraf.Metric{
|
||||
metric.New("foo", map[string]string{}, map[string]interface{}{"value": 42}, now),
|
||||
metric.New("bar", map[string]string{}, map[string]interface{}{"value": 42}, now),
|
||||
metric.New("baz", map[string]string{}, map[string]interface{}{"value": 42}, now),
|
||||
}
|
||||
|
||||
expected := []telegraf.Metric{
|
||||
metric.New("foo", map[string]string{}, map[string]interface{}{"value": 42, "unix_ns": ts}, now),
|
||||
metric.New("bar", map[string]string{}, map[string]interface{}{"value": 42, "unix_ns": ts}, now),
|
||||
metric.New("baz", map[string]string{}, map[string]interface{}{"value": 42, "unix_ns": ts}, now),
|
||||
}
|
||||
|
||||
plugin := &Date{
|
||||
FieldKey: "unix_ns",
|
||||
DateFormat: "unix_ns",
|
||||
}
|
||||
require.NoError(t, plugin.Init())
|
||||
|
||||
actual := plugin.Apply(input...)
|
||||
testutil.RequireMetricsEqual(t, expected, actual)
|
||||
}
|
||||
|
||||
func TestFieldUnixMillis(t *testing.T) {
|
||||
now := time.Now()
|
||||
ts := now.UnixMilli()
|
||||
|
||||
input := []telegraf.Metric{
|
||||
metric.New("foo", map[string]string{}, map[string]interface{}{"value": 42}, now),
|
||||
metric.New("bar", map[string]string{}, map[string]interface{}{"value": 42}, now),
|
||||
metric.New("baz", map[string]string{}, map[string]interface{}{"value": 42}, now),
|
||||
}
|
||||
|
||||
expected := []telegraf.Metric{
|
||||
metric.New("foo", map[string]string{}, map[string]interface{}{"value": 42, "unix_ms": ts}, now),
|
||||
metric.New("bar", map[string]string{}, map[string]interface{}{"value": 42, "unix_ms": ts}, now),
|
||||
metric.New("baz", map[string]string{}, map[string]interface{}{"value": 42, "unix_ms": ts}, now),
|
||||
}
|
||||
|
||||
plugin := &Date{
|
||||
FieldKey: "unix_ms",
|
||||
DateFormat: "unix_ms",
|
||||
}
|
||||
require.NoError(t, plugin.Init())
|
||||
|
||||
actual := plugin.Apply(input...)
|
||||
testutil.RequireMetricsEqual(t, expected, actual)
|
||||
}
|
||||
|
||||
func TestFieldUnixMicros(t *testing.T) {
|
||||
now := time.Now()
|
||||
ts := now.UnixMicro()
|
||||
|
||||
input := []telegraf.Metric{
|
||||
metric.New("foo", map[string]string{}, map[string]interface{}{"value": 42}, now),
|
||||
metric.New("bar", map[string]string{}, map[string]interface{}{"value": 42}, now),
|
||||
metric.New("baz", map[string]string{}, map[string]interface{}{"value": 42}, now),
|
||||
}
|
||||
|
||||
expected := []telegraf.Metric{
|
||||
metric.New("foo", map[string]string{}, map[string]interface{}{"value": 42, "unix_us": ts}, now),
|
||||
metric.New("bar", map[string]string{}, map[string]interface{}{"value": 42, "unix_us": ts}, now),
|
||||
metric.New("baz", map[string]string{}, map[string]interface{}{"value": 42, "unix_us": ts}, now),
|
||||
}
|
||||
|
||||
plugin := &Date{
|
||||
FieldKey: "unix_us",
|
||||
DateFormat: "unix_us",
|
||||
}
|
||||
require.NoError(t, plugin.Init())
|
||||
|
||||
actual := plugin.Apply(input...)
|
||||
testutil.RequireMetricsEqual(t, expected, actual)
|
||||
}
|
||||
|
||||
func TestDateOffset(t *testing.T) {
|
||||
plugin := &Date{
|
||||
TagKey: "hour",
|
||||
DateFormat: "15",
|
||||
DateOffset: config.Duration(2 * time.Hour),
|
||||
}
|
||||
require.NoError(t, plugin.Init())
|
||||
|
||||
input := testutil.MustMetric(
|
||||
"cpu",
|
||||
map[string]string{},
|
||||
map[string]interface{}{
|
||||
"time_idle": 42.0,
|
||||
},
|
||||
time.Unix(1578603600, 0),
|
||||
)
|
||||
|
||||
expected := []telegraf.Metric{
|
||||
testutil.MustMetric(
|
||||
"cpu",
|
||||
map[string]string{
|
||||
"hour": "23",
|
||||
},
|
||||
map[string]interface{}{
|
||||
"time_idle": 42.0,
|
||||
},
|
||||
time.Unix(1578603600, 0),
|
||||
),
|
||||
}
|
||||
|
||||
actual := plugin.Apply(input)
|
||||
testutil.RequireMetricsEqual(t, expected, actual)
|
||||
}
|
||||
|
||||
func TestTracking(t *testing.T) {
|
||||
now := time.Now()
|
||||
ts := now.UnixMicro()
|
||||
|
||||
inputRaw := []telegraf.Metric{
|
||||
metric.New("foo", map[string]string{}, map[string]interface{}{"value": 42}, now),
|
||||
metric.New("bar", map[string]string{}, map[string]interface{}{"value": 42}, now),
|
||||
metric.New("baz", map[string]string{}, map[string]interface{}{"value": 42}, now),
|
||||
}
|
||||
|
||||
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))
|
||||
expected := make([]telegraf.Metric, 0, len(input))
|
||||
for _, m := range inputRaw {
|
||||
tm, _ := metric.WithTracking(m, notify)
|
||||
input = append(input, tm)
|
||||
|
||||
em := m.Copy()
|
||||
em.AddField("unix_us", ts)
|
||||
expected = append(expected, m)
|
||||
}
|
||||
|
||||
plugin := &Date{
|
||||
FieldKey: "unix_us",
|
||||
DateFormat: "unix_us",
|
||||
}
|
||||
require.NoError(t, plugin.Init())
|
||||
|
||||
// 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))
|
||||
}
|
24
plugins/processors/date/sample.conf
Normal file
24
plugins/processors/date/sample.conf
Normal file
|
@ -0,0 +1,24 @@
|
|||
# Dates measurements, tags, and fields that pass through this filter.
|
||||
[[processors.date]]
|
||||
## New tag to create
|
||||
tag_key = "month"
|
||||
|
||||
## New field to create (cannot set both field_key and tag_key)
|
||||
# field_key = "month"
|
||||
|
||||
## Date format string, must be a representation of the Go "reference time"
|
||||
## which is "Mon Jan 2 15:04:05 -0700 MST 2006".
|
||||
date_format = "Jan"
|
||||
|
||||
## If destination is a field, date format can also be one of
|
||||
## "unix", "unix_ms", "unix_us", or "unix_ns", which will insert an integer field.
|
||||
# date_format = "unix"
|
||||
|
||||
## Offset duration added to the date string when writing the new tag.
|
||||
# date_offset = "0s"
|
||||
|
||||
## Timezone to use when creating the tag or field using a reference time
|
||||
## string. This can be set to one of "UTC", "Local", or to a location name
|
||||
## in the IANA Time Zone database.
|
||||
## example: timezone = "America/Los_Angeles"
|
||||
# timezone = "UTC"
|
Loading…
Add table
Add a link
Reference in a new issue