Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add date offset option to date processor #6886

Merged
merged 4 commits into from
Jan 14, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
renamed to `sqlserver_azure_db_resource_stats` due to an issue where numeric
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

- [warp10](/plugins/outputs/warp10/README.md) - Contributed by @aurrelhebert
Expand Down
19 changes: 19 additions & 0 deletions plugins/processors/date/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,23 @@ A few example usecases include:
## 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"

## 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
Expand All @@ -27,3 +44,5 @@ A few example usecases include:
- 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
35 changes: 31 additions & 4 deletions plugins/processors/date/date.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package date

import (
"time"

"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/internal"
"github.com/influxdata/telegraf/plugins/processors"
)

Expand All @@ -12,11 +15,25 @@ const sampleConfig = `
## 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"

## 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 {
TagKey string `toml:"tag_key"`
DateFormat string `toml:"date_format"`
TagKey string `toml:"tag_key"`
DateFormat string `toml:"date_format"`
DateOffset internal.Duration `toml:"date_offset"`
Timezone string `toml:"timezone"`

location *time.Location
}

func (d *Date) SampleConfig() string {
Expand All @@ -27,16 +44,26 @@ func (d *Date) Description() string {
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 {
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
}

func init() {
processors.Add("date", func() telegraf.Processor {
return &Date{}
return &Date{
Timezone: defaultTimezone,
}
})
}
48 changes: 48 additions & 0 deletions plugins/processors/date/date_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@ import (
"time"

"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/internal"
"github.com/influxdata/telegraf/metric"
"github.com/influxdata/telegraf/testutil"
"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 {
Expand All @@ -25,6 +28,8 @@ func TestMonthTag(t *testing.T) {
TagKey: "month",
DateFormat: "Jan",
}
err := dateFormatMonth.Init()
require.NoError(t, err)

currentTime := time.Now()
month := currentTime.Format("Jan")
Expand All @@ -43,6 +48,10 @@ func TestYearTag(t *testing.T) {
TagKey: "year",
DateFormat: "2006",
}

err := dateFormatYear.Init()
require.NoError(t, err)

currentTime := time.Now()
year := currentTime.Format("2006")

Expand All @@ -61,7 +70,46 @@ func TestOldDateTag(t *testing.T) {
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))
customDateApply := dateFormatYear.Apply(m7)
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)
}