Converter processor: add support for large hexadecimal strings (#9160)
* add oauth2 to http input * reset not included changes * reset not included changes * reset not included changes * add hexadecimal parser changes * add linter changes * add documentation note
This commit is contained in:
parent
ba05724918
commit
79b1ac1f06
|
|
@ -9,6 +9,8 @@ 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.
|
||||||
|
|
||||||
|
**Note on large strings being converted to numeric types:** When converting a string value to a numeric type, precision may be lost if the number is too large. The largest numeric type this plugin supports is `float64`, and if a string 'number' exceeds its size limit, accuracy may be lost.
|
||||||
|
|
||||||
### Configuration
|
### Configuration
|
||||||
```toml
|
```toml
|
||||||
# Convert values to another metric value type
|
# Convert values to another metric value type
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,12 @@
|
||||||
package converter
|
package converter
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
|
"math/big"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/influxdata/telegraf"
|
"github.com/influxdata/telegraf"
|
||||||
"github.com/influxdata/telegraf/filter"
|
"github.com/influxdata/telegraf/filter"
|
||||||
|
|
@ -368,10 +371,19 @@ func toInteger(v interface{}) (int64, bool) {
|
||||||
result, err := strconv.ParseInt(value, 0, 64)
|
result, err := strconv.ParseInt(value, 0, 64)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
result, err := strconv.ParseFloat(value, 64)
|
var result float64
|
||||||
|
var err error
|
||||||
|
|
||||||
|
if isHexadecimal(value) {
|
||||||
|
result, err = parseHexadecimal(value)
|
||||||
|
} else {
|
||||||
|
result, err = strconv.ParseFloat(value, 64)
|
||||||
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, false
|
return 0, false
|
||||||
}
|
}
|
||||||
|
|
||||||
return toInteger(result)
|
return toInteger(result)
|
||||||
}
|
}
|
||||||
return result, true
|
return result, true
|
||||||
|
|
@ -405,10 +417,19 @@ func toUnsigned(v interface{}) (uint64, bool) {
|
||||||
result, err := strconv.ParseUint(value, 0, 64)
|
result, err := strconv.ParseUint(value, 0, 64)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
result, err := strconv.ParseFloat(value, 64)
|
var result float64
|
||||||
|
var err error
|
||||||
|
|
||||||
|
if isHexadecimal(value) {
|
||||||
|
result, err = parseHexadecimal(value)
|
||||||
|
} else {
|
||||||
|
result, err = strconv.ParseFloat(value, 64)
|
||||||
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, false
|
return 0, false
|
||||||
}
|
}
|
||||||
|
|
||||||
return toUnsigned(result)
|
return toUnsigned(result)
|
||||||
}
|
}
|
||||||
return result, true
|
return result, true
|
||||||
|
|
@ -430,6 +451,11 @@ func toFloat(v interface{}) (float64, bool) {
|
||||||
}
|
}
|
||||||
return 0.0, true
|
return 0.0, true
|
||||||
case string:
|
case string:
|
||||||
|
if isHexadecimal(value) {
|
||||||
|
result, err := parseHexadecimal(value)
|
||||||
|
return result, err == nil
|
||||||
|
}
|
||||||
|
|
||||||
result, err := strconv.ParseFloat(value, 64)
|
result, err := strconv.ParseFloat(value, 64)
|
||||||
return result, err == nil
|
return result, err == nil
|
||||||
}
|
}
|
||||||
|
|
@ -452,6 +478,24 @@ func toString(v interface{}) (string, bool) {
|
||||||
return "", false
|
return "", false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseHexadecimal(value string) (float64, error) {
|
||||||
|
i := new(big.Int)
|
||||||
|
|
||||||
|
_, success := i.SetString(value, 0)
|
||||||
|
if !success {
|
||||||
|
return 0, errors.New("unable to parse string to big int")
|
||||||
|
}
|
||||||
|
|
||||||
|
f := new(big.Float).SetInt(i)
|
||||||
|
result, _ := f.Float64()
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func isHexadecimal(value string) bool {
|
||||||
|
return len(value) >= 3 && strings.ToLower(value)[1] == 'x'
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
processors.Add("converter", func() telegraf.Processor {
|
processors.Add("converter", func() telegraf.Processor {
|
||||||
return &Converter{}
|
return &Converter{}
|
||||||
|
|
|
||||||
|
|
@ -432,6 +432,38 @@ func TestConverter(t *testing.T) {
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "from string field hexidecimal",
|
||||||
|
converter: &Converter{
|
||||||
|
Fields: &Conversion{
|
||||||
|
Integer: []string{"a"},
|
||||||
|
Unsigned: []string{"b"},
|
||||||
|
Float: []string{"c"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
input: testutil.MustMetric(
|
||||||
|
"cpu",
|
||||||
|
map[string]string{},
|
||||||
|
map[string]interface{}{
|
||||||
|
"a": "0x11826c",
|
||||||
|
"b": "0x11826c",
|
||||||
|
"c": "0x2139d19bb1c580ebe0",
|
||||||
|
},
|
||||||
|
time.Unix(0, 0),
|
||||||
|
),
|
||||||
|
expected: []telegraf.Metric{
|
||||||
|
testutil.MustMetric(
|
||||||
|
"cpu",
|
||||||
|
map[string]string{},
|
||||||
|
map[string]interface{}{
|
||||||
|
"a": int64(1147500),
|
||||||
|
"b": uint64(1147500),
|
||||||
|
"c": float64(612908836750534700000),
|
||||||
|
},
|
||||||
|
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) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue