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:
David Bennett 2021-04-28 12:31:48 -04:00 committed by GitHub
parent ba05724918
commit 79b1ac1f06
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 80 additions and 2 deletions

View File

@ -9,6 +9,8 @@ Values that cannot be converted are dropped.
uniquely identifiable. Fields with the same series key (measurement + tags)
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
```toml
# Convert values to another metric value type

View File

@ -1,9 +1,12 @@
package converter
import (
"errors"
"fmt"
"math"
"math/big"
"strconv"
"strings"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/filter"
@ -368,10 +371,19 @@ func toInteger(v interface{}) (int64, bool) {
result, err := strconv.ParseInt(value, 0, 64)
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 {
return 0, false
}
return toInteger(result)
}
return result, true
@ -405,10 +417,19 @@ func toUnsigned(v interface{}) (uint64, bool) {
result, err := strconv.ParseUint(value, 0, 64)
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 {
return 0, false
}
return toUnsigned(result)
}
return result, true
@ -430,6 +451,11 @@ func toFloat(v interface{}) (float64, bool) {
}
return 0.0, true
case string:
if isHexadecimal(value) {
result, err := parseHexadecimal(value)
return result, err == nil
}
result, err := strconv.ParseFloat(value, 64)
return result, err == nil
}
@ -452,6 +478,24 @@ func toString(v interface{}) (string, bool) {
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() {
processors.Add("converter", func() telegraf.Processor {
return &Converter{}

View File

@ -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 {
t.Run(tt.name, func(t *testing.T) {