Add date offset and timezone options to date processor (#6886)

This commit is contained in:
Daniel Nelson 2020-01-14 15:16:27 -08:00 committed by GitHub
parent 5f2ed4ce4f
commit e8c4efb572
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 101 additions and 4 deletions

View File

@ -6,6 +6,9 @@
renamed to `sqlserver_azure_db_resource_stats` due to an issue where numeric renamed to `sqlserver_azure_db_resource_stats` due to an issue where numeric
metrics were previously being reported incorrectly as strings. metrics were previously being reported incorrectly as strings.
- The `date` processor now uses the UTC timezone when creating its tag. In
previous versions the local time was used.
#### New Outputs #### New Outputs
- [warp10](/plugins/outputs/warp10/README.md) - Contributed by @aurrelhebert - [warp10](/plugins/outputs/warp10/README.md) - Contributed by @aurrelhebert

View File

@ -19,6 +19,23 @@ A few example usecases include:
## Date format string, must be a representation of the Go "reference time" ## Date format string, must be a representation of the Go "reference time"
## which is "Mon Jan 2 15:04:05 -0700 MST 2006". ## which is "Mon Jan 2 15:04:05 -0700 MST 2006".
date_format = "Jan" date_format = "Jan"
## Offset duration added to the date string when writing the new tag.
# date_offset = "0s"
## Timezone to use when generating the date. This can be set to one of
## "Local", "UTC", 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]:
```
set ZONEINFO=C:\zoneinfo.zip
``` ```
### Example ### Example
@ -27,3 +44,5 @@ A few example usecases include:
- throughput lower=10i,upper=1000i,mean=500i 1560540094000000000 - throughput lower=10i,upper=1000i,mean=500i 1560540094000000000
+ throughput,month=Jun 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

View File

@ -1,7 +1,10 @@
package date package date
import ( import (
"time"
"github.com/influxdata/telegraf" "github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/internal"
"github.com/influxdata/telegraf/plugins/processors" "github.com/influxdata/telegraf/plugins/processors"
) )
@ -12,11 +15,25 @@ const sampleConfig = `
## Date format string, must be a representation of the Go "reference time" ## Date format string, must be a representation of the Go "reference time"
## which is "Mon Jan 2 15:04:05 -0700 MST 2006". ## which is "Mon Jan 2 15:04:05 -0700 MST 2006".
date_format = "Jan" date_format = "Jan"
## Offset duration added to the date string when writing the new tag.
# date_offset = "0s"
## Timezone to use when creating the tag. 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"
` `
const defaultTimezone = "UTC"
type Date struct { type Date struct {
TagKey string `toml:"tag_key"` TagKey string `toml:"tag_key"`
DateFormat string `toml:"date_format"` DateFormat string `toml:"date_format"`
DateOffset internal.Duration `toml:"date_offset"`
Timezone string `toml:"timezone"`
location *time.Location
} }
func (d *Date) SampleConfig() string { func (d *Date) SampleConfig() string {
@ -27,9 +44,17 @@ func (d *Date) Description() string {
return "Dates measurements, tags, and fields that pass through this filter." return "Dates measurements, tags, and fields that pass through this filter."
} }
func (d *Date) Init() error {
var err error
// LoadLocation returns UTC if timezone is the empty string.
d.location, err = time.LoadLocation(d.Timezone)
return err
}
func (d *Date) Apply(in ...telegraf.Metric) []telegraf.Metric { func (d *Date) Apply(in ...telegraf.Metric) []telegraf.Metric {
for _, point := range in { for _, point := range in {
point.AddTag(d.TagKey, point.Time().Format(d.DateFormat)) tm := point.Time().In(d.location).Add(d.DateOffset.Duration)
point.AddTag(d.TagKey, tm.Format(d.DateFormat))
} }
return in return in
@ -37,6 +62,8 @@ func (d *Date) Apply(in ...telegraf.Metric) []telegraf.Metric {
func init() { func init() {
processors.Add("date", func() telegraf.Processor { processors.Add("date", func() telegraf.Processor {
return &Date{} return &Date{
Timezone: defaultTimezone,
}
}) })
} }

View File

@ -5,8 +5,11 @@ import (
"time" "time"
"github.com/influxdata/telegraf" "github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/internal"
"github.com/influxdata/telegraf/metric" "github.com/influxdata/telegraf/metric"
"github.com/influxdata/telegraf/testutil"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
) )
func MustMetric(name string, tags map[string]string, fields map[string]interface{}, metricTime time.Time) telegraf.Metric { func MustMetric(name string, tags map[string]string, fields map[string]interface{}, metricTime time.Time) telegraf.Metric {
@ -25,6 +28,8 @@ func TestMonthTag(t *testing.T) {
TagKey: "month", TagKey: "month",
DateFormat: "Jan", DateFormat: "Jan",
} }
err := dateFormatMonth.Init()
require.NoError(t, err)
currentTime := time.Now() currentTime := time.Now()
month := currentTime.Format("Jan") month := currentTime.Format("Jan")
@ -43,6 +48,10 @@ func TestYearTag(t *testing.T) {
TagKey: "year", TagKey: "year",
DateFormat: "2006", DateFormat: "2006",
} }
err := dateFormatYear.Init()
require.NoError(t, err)
currentTime := time.Now() currentTime := time.Now()
year := currentTime.Format("2006") year := currentTime.Format("2006")
@ -61,7 +70,46 @@ func TestOldDateTag(t *testing.T) {
DateFormat: "2006", DateFormat: "2006",
} }
err := dateFormatYear.Init()
require.NoError(t, err)
m7 := MustMetric("foo", nil, nil, time.Date(1993, 05, 27, 0, 0, 0, 0, time.UTC)) m7 := MustMetric("foo", nil, nil, time.Date(1993, 05, 27, 0, 0, 0, 0, time.UTC))
customDateApply := dateFormatYear.Apply(m7) customDateApply := dateFormatYear.Apply(m7)
assert.Equal(t, map[string]string{"year": "1993"}, customDateApply[0].Tags(), "should add tag 'year'") assert.Equal(t, map[string]string{"year": "1993"}, customDateApply[0].Tags(), "should add tag 'year'")
} }
func TestDateOffset(t *testing.T) {
plugin := &Date{
TagKey: "hour",
DateFormat: "15",
DateOffset: internal.Duration{Duration: 2 * time.Hour},
}
err := plugin.Init()
require.NoError(t, err)
metric := 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(metric)
testutil.RequireMetricsEqual(t, expected, actual)
}