Add support for converting tag or field to measurement in converter processor (#7049)
This commit is contained in:
parent
898487b2da
commit
ca65d52c9a
|
@ -9,7 +9,7 @@ Values that cannot be converted are dropped.
|
||||||
uniquely identifiable. Fields with the same series key (measurement + tags)
|
uniquely identifiable. Fields with the same series key (measurement + tags)
|
||||||
will overwrite one another.
|
will overwrite one another.
|
||||||
|
|
||||||
### Configuration:
|
### Configuration
|
||||||
```toml
|
```toml
|
||||||
# Convert values to another metric value type
|
# Convert values to another metric value type
|
||||||
[[processors.converter]]
|
[[processors.converter]]
|
||||||
|
@ -19,6 +19,7 @@ will overwrite one another.
|
||||||
## select the keys to convert. The array may contain globs.
|
## select the keys to convert. The array may contain globs.
|
||||||
## <target-type> = [<tag-key>...]
|
## <target-type> = [<tag-key>...]
|
||||||
[processors.converter.tags]
|
[processors.converter.tags]
|
||||||
|
measurement = []
|
||||||
string = []
|
string = []
|
||||||
integer = []
|
integer = []
|
||||||
unsigned = []
|
unsigned = []
|
||||||
|
@ -31,6 +32,7 @@ will overwrite one another.
|
||||||
## select the keys to convert. The array may contain globs.
|
## select the keys to convert. The array may contain globs.
|
||||||
## <target-type> = [<field-key>...]
|
## <target-type> = [<field-key>...]
|
||||||
[processors.converter.fields]
|
[processors.converter.fields]
|
||||||
|
measurement = []
|
||||||
tag = []
|
tag = []
|
||||||
string = []
|
string = []
|
||||||
integer = []
|
integer = []
|
||||||
|
@ -39,19 +41,40 @@ will overwrite one another.
|
||||||
float = []
|
float = []
|
||||||
```
|
```
|
||||||
|
|
||||||
### Examples:
|
### Example
|
||||||
|
|
||||||
|
Convert `port` tag to a string field:
|
||||||
```toml
|
```toml
|
||||||
[[processors.converter]]
|
[[processors.converter]]
|
||||||
[processors.converter.tags]
|
[processors.converter.tags]
|
||||||
string = ["port"]
|
string = ["port"]
|
||||||
|
|
||||||
[processors.converter.fields]
|
|
||||||
integer = ["scboard_*"]
|
|
||||||
tag = ["ParentServerConfigGeneration"]
|
|
||||||
```
|
```
|
||||||
|
|
||||||
```diff
|
```diff
|
||||||
- apache,port=80,server=debian-stretch-apache BusyWorkers=1,BytesPerReq=0,BytesPerSec=0,CPUChildrenSystem=0,CPUChildrenUser=0,CPULoad=0.00995025,CPUSystem=0.01,CPUUser=0.01,ConnsAsyncClosing=0,ConnsAsyncKeepAlive=0,ConnsAsyncWriting=0,ConnsTotal=0,IdleWorkers=49,Load1=0.01,Load15=0,Load5=0,ParentServerConfigGeneration=3,ParentServerMPMGeneration=2,ReqPerSec=0.00497512,ServerUptimeSeconds=201,TotalAccesses=1,TotalkBytes=0,Uptime=201,scboard_closing=0,scboard_dnslookup=0,scboard_finishing=0,scboard_idle_cleanup=0,scboard_keepalive=0,scboard_logging=0,scboard_open=100,scboard_reading=0,scboard_sending=1,scboard_starting=0,scboard_waiting=49 1502489900000000000
|
- apache,port=80,server=debian-stretch-apache BusyWorkers=1,BytesPerReq=0
|
||||||
+ apache,server=debian-stretch-apache,ParentServerConfigGeneration=3 port="80",BusyWorkers=1,BytesPerReq=0,BytesPerSec=0,CPUChildrenSystem=0,CPUChildrenUser=0,CPULoad=0.00995025,CPUSystem=0.01,CPUUser=0.01,ConnsAsyncClosing=0,ConnsAsyncKeepAlive=0,ConnsAsyncWriting=0,ConnsTotal=0,IdleWorkers=49,Load1=0.01,Load15=0,Load5=0,ParentServerMPMGeneration=2,ReqPerSec=0.00497512,ServerUptimeSeconds=201,TotalAccesses=1,TotalkBytes=0,Uptime=201,scboard_closing=0i,scboard_dnslookup=0i,scboard_finishing=0i,scboard_idle_cleanup=0i,scboard_keepalive=0i,scboard_logging=0i,scboard_open=100i,scboard_reading=0i,scboard_sending=1i,scboard_starting=0i,scboard_waiting=49i 1502489900000000000
|
+ apache,server=debian-stretch-apache port="80",BusyWorkers=1,BytesPerReq=0
|
||||||
|
```
|
||||||
|
|
||||||
|
Convert all `scboard_*` fields to an integer:
|
||||||
|
```toml
|
||||||
|
[[processors.converter]]
|
||||||
|
[processors.converter.fields]
|
||||||
|
integer = ["scboard_*"]
|
||||||
|
```
|
||||||
|
|
||||||
|
```diff
|
||||||
|
- apache scboard_closing=0,scboard_dnslookup=0,scboard_finishing=0,scboard_idle_cleanup=0,scboard_keepalive=0,scboard_logging=0,scboard_open=100,scboard_reading=0,scboard_sending=1,scboard_starting=0,scboard_waiting=49
|
||||||
|
+ apache scboard_closing=0i,scboard_dnslookup=0i,scboard_finishing=0i,scboard_idle_cleanup=0i,scboard_keepalive=0i,scboard_logging=0i,scboard_open=100i,scboard_reading=0i,scboard_sending=1i,scboard_starting=0i,scboard_waiting=49i
|
||||||
|
```
|
||||||
|
|
||||||
|
Rename the measurement from a tag value:
|
||||||
|
```toml
|
||||||
|
[[processors.converter]]
|
||||||
|
[processors.converter.tags]
|
||||||
|
measurement = ["topic"]
|
||||||
|
```
|
||||||
|
|
||||||
|
```diff
|
||||||
|
- mqtt_consumer,topic=sensor temp=42
|
||||||
|
+ sensor temp=42
|
||||||
```
|
```
|
||||||
|
|
|
@ -2,7 +2,6 @@ package converter
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
|
||||||
"math"
|
"math"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
@ -18,6 +17,7 @@ var sampleConfig = `
|
||||||
## select the keys to convert. The array may contain globs.
|
## select the keys to convert. The array may contain globs.
|
||||||
## <target-type> = [<tag-key>...]
|
## <target-type> = [<tag-key>...]
|
||||||
[processors.converter.tags]
|
[processors.converter.tags]
|
||||||
|
measurement = []
|
||||||
string = []
|
string = []
|
||||||
integer = []
|
integer = []
|
||||||
unsigned = []
|
unsigned = []
|
||||||
|
@ -30,6 +30,7 @@ var sampleConfig = `
|
||||||
## select the keys to convert. The array may contain globs.
|
## select the keys to convert. The array may contain globs.
|
||||||
## <target-type> = [<field-key>...]
|
## <target-type> = [<field-key>...]
|
||||||
[processors.converter.fields]
|
[processors.converter.fields]
|
||||||
|
measurement = []
|
||||||
tag = []
|
tag = []
|
||||||
string = []
|
string = []
|
||||||
integer = []
|
integer = []
|
||||||
|
@ -39,30 +40,32 @@ var sampleConfig = `
|
||||||
`
|
`
|
||||||
|
|
||||||
type Conversion struct {
|
type Conversion struct {
|
||||||
Tag []string `toml:"tag"`
|
Measurement []string `toml:"measurement"`
|
||||||
String []string `toml:"string"`
|
Tag []string `toml:"tag"`
|
||||||
Integer []string `toml:"integer"`
|
String []string `toml:"string"`
|
||||||
Unsigned []string `toml:"unsigned"`
|
Integer []string `toml:"integer"`
|
||||||
Boolean []string `toml:"boolean"`
|
Unsigned []string `toml:"unsigned"`
|
||||||
Float []string `toml:"float"`
|
Boolean []string `toml:"boolean"`
|
||||||
|
Float []string `toml:"float"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Converter struct {
|
type Converter struct {
|
||||||
Tags *Conversion `toml:"tags"`
|
Tags *Conversion `toml:"tags"`
|
||||||
Fields *Conversion `toml:"fields"`
|
Fields *Conversion `toml:"fields"`
|
||||||
|
Log telegraf.Logger `toml:"-"`
|
||||||
|
|
||||||
initialized bool
|
|
||||||
tagConversions *ConversionFilter
|
tagConversions *ConversionFilter
|
||||||
fieldConversions *ConversionFilter
|
fieldConversions *ConversionFilter
|
||||||
}
|
}
|
||||||
|
|
||||||
type ConversionFilter struct {
|
type ConversionFilter struct {
|
||||||
Tag filter.Filter
|
Measurement filter.Filter
|
||||||
String filter.Filter
|
Tag filter.Filter
|
||||||
Integer filter.Filter
|
String filter.Filter
|
||||||
Unsigned filter.Filter
|
Integer filter.Filter
|
||||||
Boolean filter.Filter
|
Unsigned filter.Filter
|
||||||
Float filter.Filter
|
Boolean filter.Filter
|
||||||
|
Float filter.Filter
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Converter) SampleConfig() string {
|
func (p *Converter) SampleConfig() string {
|
||||||
|
@ -73,15 +76,11 @@ func (p *Converter) Description() string {
|
||||||
return "Convert values to another metric value type"
|
return "Convert values to another metric value type"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Converter) Apply(metrics ...telegraf.Metric) []telegraf.Metric {
|
func (p *Converter) Init() error {
|
||||||
if !p.initialized {
|
return p.compile()
|
||||||
err := p.compile()
|
}
|
||||||
if err != nil {
|
|
||||||
logPrintf("initialization error: %v\n", err)
|
|
||||||
return metrics
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
func (p *Converter) Apply(metrics ...telegraf.Metric) []telegraf.Metric {
|
||||||
for _, metric := range metrics {
|
for _, metric := range metrics {
|
||||||
p.convertTags(metric)
|
p.convertTags(metric)
|
||||||
p.convertFields(metric)
|
p.convertFields(metric)
|
||||||
|
@ -106,7 +105,6 @@ func (p *Converter) compile() error {
|
||||||
|
|
||||||
p.tagConversions = tf
|
p.tagConversions = tf
|
||||||
p.fieldConversions = ff
|
p.fieldConversions = ff
|
||||||
p.initialized = true
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,6 +115,11 @@ func compileFilter(conv *Conversion) (*ConversionFilter, error) {
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
cf := &ConversionFilter{}
|
cf := &ConversionFilter{}
|
||||||
|
cf.Measurement, err = filter.Compile(conv.Measurement)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
cf.Tag, err = filter.Compile(conv.Tag)
|
cf.Tag, err = filter.Compile(conv.Tag)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -150,13 +153,19 @@ func compileFilter(conv *Conversion) (*ConversionFilter, error) {
|
||||||
return cf, nil
|
return cf, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// convertTags converts tags into fields
|
// convertTags converts tags into measurements or fields.
|
||||||
func (p *Converter) convertTags(metric telegraf.Metric) {
|
func (p *Converter) convertTags(metric telegraf.Metric) {
|
||||||
if p.tagConversions == nil {
|
if p.tagConversions == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for key, value := range metric.Tags() {
|
for key, value := range metric.Tags() {
|
||||||
|
if p.tagConversions.Measurement != nil && p.tagConversions.Measurement.Match(key) {
|
||||||
|
metric.RemoveTag(key)
|
||||||
|
metric.SetName(value)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
if p.tagConversions.String != nil && p.tagConversions.String.Match(key) {
|
if p.tagConversions.String != nil && p.tagConversions.String.Match(key) {
|
||||||
metric.RemoveTag(key)
|
metric.RemoveTag(key)
|
||||||
metric.AddField(key, value)
|
metric.AddField(key, value)
|
||||||
|
@ -167,7 +176,7 @@ func (p *Converter) convertTags(metric telegraf.Metric) {
|
||||||
v, ok := toInteger(value)
|
v, ok := toInteger(value)
|
||||||
if !ok {
|
if !ok {
|
||||||
metric.RemoveTag(key)
|
metric.RemoveTag(key)
|
||||||
logPrintf("error converting to integer [%T]: %v\n", value, value)
|
p.Log.Errorf("error converting to integer [%T]: %v", value, value)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,7 +188,7 @@ func (p *Converter) convertTags(metric telegraf.Metric) {
|
||||||
v, ok := toUnsigned(value)
|
v, ok := toUnsigned(value)
|
||||||
if !ok {
|
if !ok {
|
||||||
metric.RemoveTag(key)
|
metric.RemoveTag(key)
|
||||||
logPrintf("error converting to unsigned [%T]: %v\n", value, value)
|
p.Log.Errorf("error converting to unsigned [%T]: %v", value, value)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -192,7 +201,7 @@ func (p *Converter) convertTags(metric telegraf.Metric) {
|
||||||
v, ok := toBool(value)
|
v, ok := toBool(value)
|
||||||
if !ok {
|
if !ok {
|
||||||
metric.RemoveTag(key)
|
metric.RemoveTag(key)
|
||||||
logPrintf("error converting to boolean [%T]: %v\n", value, value)
|
p.Log.Errorf("error converting to boolean [%T]: %v", value, value)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -205,7 +214,7 @@ func (p *Converter) convertTags(metric telegraf.Metric) {
|
||||||
v, ok := toFloat(value)
|
v, ok := toFloat(value)
|
||||||
if !ok {
|
if !ok {
|
||||||
metric.RemoveTag(key)
|
metric.RemoveTag(key)
|
||||||
logPrintf("error converting to float [%T]: %v\n", value, value)
|
p.Log.Errorf("error converting to float [%T]: %v", value, value)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -216,18 +225,31 @@ func (p *Converter) convertTags(metric telegraf.Metric) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// convertFields converts fields into tags or other field types
|
// convertFields converts fields into measurements, tags, or other field types.
|
||||||
func (p *Converter) convertFields(metric telegraf.Metric) {
|
func (p *Converter) convertFields(metric telegraf.Metric) {
|
||||||
if p.fieldConversions == nil {
|
if p.fieldConversions == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for key, value := range metric.Fields() {
|
for key, value := range metric.Fields() {
|
||||||
|
if p.fieldConversions.Measurement != nil && p.fieldConversions.Measurement.Match(key) {
|
||||||
|
v, ok := toString(value)
|
||||||
|
if !ok {
|
||||||
|
metric.RemoveField(key)
|
||||||
|
p.Log.Errorf("error converting to measurement [%T]: %v", value, value)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
metric.RemoveField(key)
|
||||||
|
metric.SetName(v)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
if p.fieldConversions.Tag != nil && p.fieldConversions.Tag.Match(key) {
|
if p.fieldConversions.Tag != nil && p.fieldConversions.Tag.Match(key) {
|
||||||
v, ok := toString(value)
|
v, ok := toString(value)
|
||||||
if !ok {
|
if !ok {
|
||||||
metric.RemoveField(key)
|
metric.RemoveField(key)
|
||||||
logPrintf("error converting to tag [%T]: %v\n", value, value)
|
p.Log.Errorf("error converting to tag [%T]: %v", value, value)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -240,7 +262,7 @@ func (p *Converter) convertFields(metric telegraf.Metric) {
|
||||||
v, ok := toFloat(value)
|
v, ok := toFloat(value)
|
||||||
if !ok {
|
if !ok {
|
||||||
metric.RemoveField(key)
|
metric.RemoveField(key)
|
||||||
logPrintf("error converting to float [%T]: %v\n", value, value)
|
p.Log.Errorf("error converting to float [%T]: %v", value, value)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,7 +275,7 @@ func (p *Converter) convertFields(metric telegraf.Metric) {
|
||||||
v, ok := toInteger(value)
|
v, ok := toInteger(value)
|
||||||
if !ok {
|
if !ok {
|
||||||
metric.RemoveField(key)
|
metric.RemoveField(key)
|
||||||
logPrintf("error converting to integer [%T]: %v\n", value, value)
|
p.Log.Errorf("error converting to integer [%T]: %v", value, value)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -266,7 +288,7 @@ func (p *Converter) convertFields(metric telegraf.Metric) {
|
||||||
v, ok := toUnsigned(value)
|
v, ok := toUnsigned(value)
|
||||||
if !ok {
|
if !ok {
|
||||||
metric.RemoveField(key)
|
metric.RemoveField(key)
|
||||||
logPrintf("error converting to unsigned [%T]: %v\n", value, value)
|
p.Log.Errorf("error converting to unsigned [%T]: %v", value, value)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,7 +301,7 @@ func (p *Converter) convertFields(metric telegraf.Metric) {
|
||||||
v, ok := toBool(value)
|
v, ok := toBool(value)
|
||||||
if !ok {
|
if !ok {
|
||||||
metric.RemoveField(key)
|
metric.RemoveField(key)
|
||||||
logPrintf("error converting to bool [%T]: %v\n", value, value)
|
p.Log.Errorf("error converting to bool [%T]: %v", value, value)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -292,7 +314,7 @@ func (p *Converter) convertFields(metric telegraf.Metric) {
|
||||||
v, ok := toString(value)
|
v, ok := toString(value)
|
||||||
if !ok {
|
if !ok {
|
||||||
metric.RemoveField(key)
|
metric.RemoveField(key)
|
||||||
logPrintf("error converting to string [%T]: %v\n", value, value)
|
p.Log.Errorf("Error converting to string [%T]: %v", value, value)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -336,7 +358,7 @@ func toInteger(v interface{}) (int64, bool) {
|
||||||
} else if value > float64(math.MaxInt64) {
|
} else if value > float64(math.MaxInt64) {
|
||||||
return math.MaxInt64, true
|
return math.MaxInt64, true
|
||||||
} else {
|
} else {
|
||||||
return int64(Round(value)), true
|
return int64(math.Round(value)), true
|
||||||
}
|
}
|
||||||
case bool:
|
case bool:
|
||||||
if value {
|
if value {
|
||||||
|
@ -375,7 +397,7 @@ func toUnsigned(v interface{}) (uint64, bool) {
|
||||||
} else if value > float64(math.MaxUint64) {
|
} else if value > float64(math.MaxUint64) {
|
||||||
return math.MaxUint64, true
|
return math.MaxUint64, true
|
||||||
} else {
|
} else {
|
||||||
return uint64(Round(value)), true
|
return uint64(math.Round(value)), true
|
||||||
}
|
}
|
||||||
case bool:
|
case bool:
|
||||||
if value {
|
if value {
|
||||||
|
@ -435,20 +457,6 @@ func toString(v interface{}) (string, bool) {
|
||||||
return "", false
|
return "", false
|
||||||
}
|
}
|
||||||
|
|
||||||
// math.Round was not added until Go 1.10, can be removed when support for Go
|
|
||||||
// 1.9 is dropped.
|
|
||||||
func Round(x float64) float64 {
|
|
||||||
t := math.Trunc(x)
|
|
||||||
if math.Abs(x-t) >= 0.5 {
|
|
||||||
return t + math.Copysign(1, x)
|
|
||||||
}
|
|
||||||
return t
|
|
||||||
}
|
|
||||||
|
|
||||||
func logPrintf(format string, v ...interface{}) {
|
|
||||||
log.Printf("D! [processors.converter] "+format, v...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
processors.Add("converter", func() telegraf.Processor {
|
processors.Add("converter", func() telegraf.Processor {
|
||||||
return &Converter{}
|
return &Converter{}
|
||||||
|
|
|
@ -6,48 +6,17 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/influxdata/telegraf"
|
"github.com/influxdata/telegraf"
|
||||||
"github.com/influxdata/telegraf/metric"
|
"github.com/influxdata/telegraf/testutil"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Metric(v telegraf.Metric, err error) telegraf.Metric {
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestConverter(t *testing.T) {
|
func TestConverter(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
converter *Converter
|
converter *Converter
|
||||||
input telegraf.Metric
|
input telegraf.Metric
|
||||||
expected telegraf.Metric
|
expected []telegraf.Metric
|
||||||
}{
|
}{
|
||||||
{
|
|
||||||
name: "empty",
|
|
||||||
converter: &Converter{},
|
|
||||||
input: Metric(
|
|
||||||
metric.New(
|
|
||||||
"cpu",
|
|
||||||
map[string]string{},
|
|
||||||
map[string]interface{}{
|
|
||||||
"value": 42.0,
|
|
||||||
},
|
|
||||||
time.Unix(0, 0),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
expected: Metric(
|
|
||||||
metric.New(
|
|
||||||
"cpu",
|
|
||||||
map[string]string{},
|
|
||||||
map[string]interface{}{
|
|
||||||
"value": 42.0,
|
|
||||||
},
|
|
||||||
time.Unix(0, 0),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: "from tag",
|
name: "from tag",
|
||||||
converter: &Converter{
|
converter: &Converter{
|
||||||
|
@ -60,23 +29,21 @@ func TestConverter(t *testing.T) {
|
||||||
Tag: []string{"tag"},
|
Tag: []string{"tag"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
input: Metric(
|
input: testutil.MustMetric(
|
||||||
metric.New(
|
"cpu",
|
||||||
"cpu",
|
map[string]string{
|
||||||
map[string]string{
|
"float": "42",
|
||||||
"float": "42",
|
"int": "42",
|
||||||
"int": "42",
|
"uint": "42",
|
||||||
"uint": "42",
|
"bool": "true",
|
||||||
"bool": "true",
|
"string": "howdy",
|
||||||
"string": "howdy",
|
"tag": "tag",
|
||||||
"tag": "tag",
|
},
|
||||||
},
|
map[string]interface{}{},
|
||||||
map[string]interface{}{},
|
time.Unix(0, 0),
|
||||||
time.Unix(0, 0),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
expected: Metric(
|
expected: []telegraf.Metric{
|
||||||
metric.New(
|
testutil.MustMetric(
|
||||||
"cpu",
|
"cpu",
|
||||||
map[string]string{
|
map[string]string{
|
||||||
"tag": "tag",
|
"tag": "tag",
|
||||||
|
@ -90,7 +57,7 @@ func TestConverter(t *testing.T) {
|
||||||
},
|
},
|
||||||
time.Unix(0, 0),
|
time.Unix(0, 0),
|
||||||
),
|
),
|
||||||
),
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "from tag unconvertible",
|
name: "from tag unconvertible",
|
||||||
|
@ -102,27 +69,25 @@ func TestConverter(t *testing.T) {
|
||||||
Float: []string{"float"},
|
Float: []string{"float"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
input: Metric(
|
input: testutil.MustMetric(
|
||||||
metric.New(
|
"cpu",
|
||||||
"cpu",
|
map[string]string{
|
||||||
map[string]string{
|
"float": "a",
|
||||||
"float": "a",
|
"int": "b",
|
||||||
"int": "b",
|
"uint": "c",
|
||||||
"uint": "c",
|
"bool": "maybe",
|
||||||
"bool": "maybe",
|
},
|
||||||
},
|
map[string]interface{}{},
|
||||||
map[string]interface{}{},
|
time.Unix(0, 0),
|
||||||
time.Unix(0, 0),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
expected: Metric(
|
expected: []telegraf.Metric{
|
||||||
metric.New(
|
testutil.MustMetric(
|
||||||
"cpu",
|
"cpu",
|
||||||
map[string]string{},
|
map[string]string{},
|
||||||
map[string]interface{}{},
|
map[string]interface{}{},
|
||||||
time.Unix(0, 0),
|
time.Unix(0, 0),
|
||||||
),
|
),
|
||||||
),
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "from string field",
|
name: "from string field",
|
||||||
|
@ -136,29 +101,27 @@ func TestConverter(t *testing.T) {
|
||||||
Tag: []string{"f"},
|
Tag: []string{"f"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
input: Metric(
|
input: testutil.MustMetric(
|
||||||
metric.New(
|
"cpu",
|
||||||
"cpu",
|
map[string]string{},
|
||||||
map[string]string{},
|
map[string]interface{}{
|
||||||
map[string]interface{}{
|
"a": "howdy",
|
||||||
"a": "howdy",
|
"b": "42",
|
||||||
"b": "42",
|
"b1": "42.2",
|
||||||
"b1": "42.2",
|
"b2": "42.5",
|
||||||
"b2": "42.5",
|
"b3": "0x2A",
|
||||||
"b3": "0x2A",
|
"c": "42",
|
||||||
"c": "42",
|
"c1": "42.2",
|
||||||
"c1": "42.2",
|
"c2": "42.5",
|
||||||
"c2": "42.5",
|
"c3": "0x2A",
|
||||||
"c3": "0x2A",
|
"d": "true",
|
||||||
"d": "true",
|
"e": "42.0",
|
||||||
"e": "42.0",
|
"f": "foo",
|
||||||
"f": "foo",
|
},
|
||||||
},
|
time.Unix(0, 0),
|
||||||
time.Unix(0, 0),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
expected: Metric(
|
expected: []telegraf.Metric{
|
||||||
metric.New(
|
testutil.MustMetric(
|
||||||
"cpu",
|
"cpu",
|
||||||
map[string]string{
|
map[string]string{
|
||||||
"f": "foo",
|
"f": "foo",
|
||||||
|
@ -178,7 +141,7 @@ func TestConverter(t *testing.T) {
|
||||||
},
|
},
|
||||||
time.Unix(0, 0),
|
time.Unix(0, 0),
|
||||||
),
|
),
|
||||||
),
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "from string field unconvertible",
|
name: "from string field unconvertible",
|
||||||
|
@ -190,27 +153,25 @@ func TestConverter(t *testing.T) {
|
||||||
Float: []string{"d"},
|
Float: []string{"d"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
input: Metric(
|
input: testutil.MustMetric(
|
||||||
metric.New(
|
"cpu",
|
||||||
"cpu",
|
map[string]string{},
|
||||||
map[string]string{},
|
map[string]interface{}{
|
||||||
map[string]interface{}{
|
"a": "a",
|
||||||
"a": "a",
|
"b": "b",
|
||||||
"b": "b",
|
"c": "c",
|
||||||
"c": "c",
|
"d": "d",
|
||||||
"d": "d",
|
},
|
||||||
},
|
time.Unix(0, 0),
|
||||||
time.Unix(0, 0),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
expected: Metric(
|
expected: []telegraf.Metric{
|
||||||
metric.New(
|
testutil.MustMetric(
|
||||||
"cpu",
|
"cpu",
|
||||||
map[string]string{},
|
map[string]string{},
|
||||||
map[string]interface{}{},
|
map[string]interface{}{},
|
||||||
time.Unix(0, 0),
|
time.Unix(0, 0),
|
||||||
),
|
),
|
||||||
),
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "from integer field",
|
name: "from integer field",
|
||||||
|
@ -224,24 +185,22 @@ func TestConverter(t *testing.T) {
|
||||||
Tag: []string{"f"},
|
Tag: []string{"f"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
input: Metric(
|
input: testutil.MustMetric(
|
||||||
metric.New(
|
"cpu",
|
||||||
"cpu",
|
map[string]string{},
|
||||||
map[string]string{},
|
map[string]interface{}{
|
||||||
map[string]interface{}{
|
"a": int64(42),
|
||||||
"a": int64(42),
|
"b": int64(42),
|
||||||
"b": int64(42),
|
"c": int64(42),
|
||||||
"c": int64(42),
|
"d": int64(42),
|
||||||
"d": int64(42),
|
"e": int64(42),
|
||||||
"e": int64(42),
|
"f": int64(42),
|
||||||
"f": int64(42),
|
"negative_uint": int64(-42),
|
||||||
"negative_uint": int64(-42),
|
},
|
||||||
},
|
time.Unix(0, 0),
|
||||||
time.Unix(0, 0),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
expected: Metric(
|
expected: []telegraf.Metric{
|
||||||
metric.New(
|
testutil.MustMetric(
|
||||||
"cpu",
|
"cpu",
|
||||||
map[string]string{
|
map[string]string{
|
||||||
"f": "42",
|
"f": "42",
|
||||||
|
@ -256,7 +215,7 @@ func TestConverter(t *testing.T) {
|
||||||
},
|
},
|
||||||
time.Unix(0, 0),
|
time.Unix(0, 0),
|
||||||
),
|
),
|
||||||
),
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "from unsigned field",
|
name: "from unsigned field",
|
||||||
|
@ -270,24 +229,22 @@ func TestConverter(t *testing.T) {
|
||||||
Tag: []string{"f"},
|
Tag: []string{"f"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
input: Metric(
|
input: testutil.MustMetric(
|
||||||
metric.New(
|
"cpu",
|
||||||
"cpu",
|
map[string]string{},
|
||||||
map[string]string{},
|
map[string]interface{}{
|
||||||
map[string]interface{}{
|
"a": uint64(42),
|
||||||
"a": uint64(42),
|
"b": uint64(42),
|
||||||
"b": uint64(42),
|
"c": uint64(42),
|
||||||
"c": uint64(42),
|
"d": uint64(42),
|
||||||
"d": uint64(42),
|
"e": uint64(42),
|
||||||
"e": uint64(42),
|
"f": uint64(42),
|
||||||
"f": uint64(42),
|
"overflow_int": uint64(math.MaxUint64),
|
||||||
"overflow_int": uint64(math.MaxUint64),
|
},
|
||||||
},
|
time.Unix(0, 0),
|
||||||
time.Unix(0, 0),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
expected: Metric(
|
expected: []telegraf.Metric{
|
||||||
metric.New(
|
testutil.MustMetric(
|
||||||
"cpu",
|
"cpu",
|
||||||
map[string]string{
|
map[string]string{
|
||||||
"f": "42",
|
"f": "42",
|
||||||
|
@ -302,7 +259,7 @@ func TestConverter(t *testing.T) {
|
||||||
},
|
},
|
||||||
time.Unix(0, 0),
|
time.Unix(0, 0),
|
||||||
),
|
),
|
||||||
),
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "out of range for unsigned",
|
name: "out of range for unsigned",
|
||||||
|
@ -311,19 +268,17 @@ func TestConverter(t *testing.T) {
|
||||||
Unsigned: []string{"a", "b"},
|
Unsigned: []string{"a", "b"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
input: Metric(
|
input: testutil.MustMetric(
|
||||||
metric.New(
|
"cpu",
|
||||||
"cpu",
|
map[string]string{},
|
||||||
map[string]string{},
|
map[string]interface{}{
|
||||||
map[string]interface{}{
|
"a": int64(-42),
|
||||||
"a": int64(-42),
|
"b": math.MaxFloat64,
|
||||||
"b": math.MaxFloat64,
|
},
|
||||||
},
|
time.Unix(0, 0),
|
||||||
time.Unix(0, 0),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
expected: Metric(
|
expected: []telegraf.Metric{
|
||||||
metric.New(
|
testutil.MustMetric(
|
||||||
"cpu",
|
"cpu",
|
||||||
map[string]string{},
|
map[string]string{},
|
||||||
map[string]interface{}{
|
map[string]interface{}{
|
||||||
|
@ -332,7 +287,7 @@ func TestConverter(t *testing.T) {
|
||||||
},
|
},
|
||||||
time.Unix(0, 0),
|
time.Unix(0, 0),
|
||||||
),
|
),
|
||||||
),
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "boolean field",
|
name: "boolean field",
|
||||||
|
@ -346,29 +301,27 @@ func TestConverter(t *testing.T) {
|
||||||
Tag: []string{"f", "ff"},
|
Tag: []string{"f", "ff"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
input: Metric(
|
input: testutil.MustMetric(
|
||||||
metric.New(
|
"cpu",
|
||||||
"cpu",
|
map[string]string{},
|
||||||
map[string]string{},
|
map[string]interface{}{
|
||||||
map[string]interface{}{
|
"a": true,
|
||||||
"a": true,
|
"b": true,
|
||||||
"b": true,
|
"c": true,
|
||||||
"c": true,
|
"d": true,
|
||||||
"d": true,
|
"e": true,
|
||||||
"e": true,
|
"f": true,
|
||||||
"f": true,
|
"af": false,
|
||||||
"af": false,
|
"bf": false,
|
||||||
"bf": false,
|
"cf": false,
|
||||||
"cf": false,
|
"df": false,
|
||||||
"df": false,
|
"ef": false,
|
||||||
"ef": false,
|
"ff": false,
|
||||||
"ff": false,
|
},
|
||||||
},
|
time.Unix(0, 0),
|
||||||
time.Unix(0, 0),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
expected: Metric(
|
expected: []telegraf.Metric{
|
||||||
metric.New(
|
testutil.MustMetric(
|
||||||
"cpu",
|
"cpu",
|
||||||
map[string]string{
|
map[string]string{
|
||||||
"f": "true",
|
"f": "true",
|
||||||
|
@ -388,7 +341,7 @@ func TestConverter(t *testing.T) {
|
||||||
},
|
},
|
||||||
time.Unix(0, 0),
|
time.Unix(0, 0),
|
||||||
),
|
),
|
||||||
),
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "from float field",
|
name: "from float field",
|
||||||
|
@ -402,28 +355,26 @@ func TestConverter(t *testing.T) {
|
||||||
Tag: []string{"f"},
|
Tag: []string{"f"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
input: Metric(
|
input: testutil.MustMetric(
|
||||||
metric.New(
|
"cpu",
|
||||||
"cpu",
|
map[string]string{},
|
||||||
map[string]string{},
|
map[string]interface{}{
|
||||||
map[string]interface{}{
|
"a": 42.0,
|
||||||
"a": 42.0,
|
"b": 42.0,
|
||||||
"b": 42.0,
|
"c": 42.0,
|
||||||
"c": 42.0,
|
"d": 42.0,
|
||||||
"d": 42.0,
|
"e": 42.0,
|
||||||
"e": 42.0,
|
"f": 42.0,
|
||||||
"f": 42.0,
|
"too_large_int": math.MaxFloat64,
|
||||||
"too_large_int": math.MaxFloat64,
|
"too_large_uint": math.MaxFloat64,
|
||||||
"too_large_uint": math.MaxFloat64,
|
"too_small_int": -math.MaxFloat64,
|
||||||
"too_small_int": -math.MaxFloat64,
|
"too_small_uint": -math.MaxFloat64,
|
||||||
"too_small_uint": -math.MaxFloat64,
|
"negative_uint": -42.0,
|
||||||
"negative_uint": -42.0,
|
},
|
||||||
},
|
time.Unix(0, 0),
|
||||||
time.Unix(0, 0),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
expected: Metric(
|
expected: []telegraf.Metric{
|
||||||
metric.New(
|
testutil.MustMetric(
|
||||||
"cpu",
|
"cpu",
|
||||||
map[string]string{
|
map[string]string{
|
||||||
"f": "42",
|
"f": "42",
|
||||||
|
@ -442,7 +393,7 @@ func TestConverter(t *testing.T) {
|
||||||
},
|
},
|
||||||
time.Unix(0, 0),
|
time.Unix(0, 0),
|
||||||
),
|
),
|
||||||
),
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "globbing",
|
name: "globbing",
|
||||||
|
@ -451,20 +402,18 @@ func TestConverter(t *testing.T) {
|
||||||
Integer: []string{"int_*"},
|
Integer: []string{"int_*"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
input: Metric(
|
input: testutil.MustMetric(
|
||||||
metric.New(
|
"cpu",
|
||||||
"cpu",
|
map[string]string{},
|
||||||
map[string]string{},
|
map[string]interface{}{
|
||||||
map[string]interface{}{
|
"int_a": "1",
|
||||||
"int_a": "1",
|
"int_b": "2",
|
||||||
"int_b": "2",
|
"float_a": 1.0,
|
||||||
"float_a": 1.0,
|
},
|
||||||
},
|
time.Unix(0, 0),
|
||||||
time.Unix(0, 0),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
expected: Metric(
|
expected: []telegraf.Metric{
|
||||||
metric.New(
|
testutil.MustMetric(
|
||||||
"cpu",
|
"cpu",
|
||||||
map[string]string{},
|
map[string]string{},
|
||||||
map[string]interface{}{
|
map[string]interface{}{
|
||||||
|
@ -474,18 +423,102 @@ func TestConverter(t *testing.T) {
|
||||||
},
|
},
|
||||||
time.Unix(0, 0),
|
time.Unix(0, 0),
|
||||||
),
|
),
|
||||||
),
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
metrics := tt.converter.Apply(tt.input)
|
tt.converter.Log = testutil.Logger{}
|
||||||
|
|
||||||
require.Equal(t, 1, len(metrics))
|
err := tt.converter.Init()
|
||||||
require.Equal(t, tt.expected.Name(), metrics[0].Name())
|
require.NoError(t, err)
|
||||||
require.Equal(t, tt.expected.Tags(), metrics[0].Tags())
|
actual := tt.converter.Apply(tt.input)
|
||||||
require.Equal(t, tt.expected.Fields(), metrics[0].Fields())
|
|
||||||
require.Equal(t, tt.expected.Time(), metrics[0].Time())
|
testutil.RequireMetricsEqual(t, tt.expected, actual)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestMeasurement(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
converter *Converter
|
||||||
|
input telegraf.Metric
|
||||||
|
expected []telegraf.Metric
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "measurement from tag",
|
||||||
|
converter: &Converter{
|
||||||
|
Tags: &Conversion{
|
||||||
|
Measurement: []string{"filepath"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
input: testutil.MustMetric(
|
||||||
|
"file",
|
||||||
|
map[string]string{
|
||||||
|
"filepath": "/var/log/syslog",
|
||||||
|
},
|
||||||
|
map[string]interface{}{
|
||||||
|
"msg": "howdy",
|
||||||
|
},
|
||||||
|
time.Unix(0, 0),
|
||||||
|
),
|
||||||
|
expected: []telegraf.Metric{
|
||||||
|
testutil.MustMetric(
|
||||||
|
"/var/log/syslog",
|
||||||
|
map[string]string{},
|
||||||
|
map[string]interface{}{
|
||||||
|
"msg": "howdy",
|
||||||
|
},
|
||||||
|
time.Unix(0, 0),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "measurement from field",
|
||||||
|
converter: &Converter{
|
||||||
|
Fields: &Conversion{
|
||||||
|
Measurement: []string{"topic"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
input: testutil.MustMetric(
|
||||||
|
"file",
|
||||||
|
map[string]string{},
|
||||||
|
map[string]interface{}{
|
||||||
|
"v": 1,
|
||||||
|
"topic": "telegraf",
|
||||||
|
},
|
||||||
|
time.Unix(0, 0),
|
||||||
|
),
|
||||||
|
expected: []telegraf.Metric{
|
||||||
|
testutil.MustMetric(
|
||||||
|
"telegraf",
|
||||||
|
map[string]string{},
|
||||||
|
map[string]interface{}{
|
||||||
|
"v": 1,
|
||||||
|
},
|
||||||
|
time.Unix(0, 0),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
tt.converter.Log = testutil.Logger{}
|
||||||
|
err := tt.converter.Init()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
actual := tt.converter.Apply(tt.input)
|
||||||
|
|
||||||
|
testutil.RequireMetricsEqual(t, tt.expected, actual)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEmptyConfigInitError(t *testing.T) {
|
||||||
|
converter := &Converter{
|
||||||
|
Log: testutil.Logger{},
|
||||||
|
}
|
||||||
|
err := converter.Init()
|
||||||
|
require.Error(t, err)
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue