feat(parsers.binary): handle hex-encoded inputs (#12232)
This commit is contained in:
parent
58d7dfc43f
commit
d2268f04d0
|
|
@ -18,11 +18,14 @@ user-specified configurations.
|
|||
## Do not error-out if none of the filter expressions below matches.
|
||||
# allow_no_match = false
|
||||
|
||||
## Specify the endianess of the data.
|
||||
## Specify the endianness of the data.
|
||||
## Available values are "be" (big-endian), "le" (little-endian) and "host",
|
||||
## where "host" means the same endianess as the machine running Telegraf.
|
||||
## where "host" means the same endianness as the machine running Telegraf.
|
||||
# endianess = "host"
|
||||
|
||||
## Interpret input as string containing hex-encoded data.
|
||||
# hex_encoding = false
|
||||
|
||||
## Multiple parsing sections are allowed
|
||||
[[inputs.file.binary]]
|
||||
## Optional: Metric (measurement) name to use if not extracted from the data.
|
||||
|
|
@ -30,7 +33,7 @@ user-specified configurations.
|
|||
|
||||
## Definition of the message format and the extracted data.
|
||||
## Please note that you need to define all elements of the data in the
|
||||
## correct order with the correct length as the data is parsed in the order
|
||||
## correct order with the correct length as the data is parsed in the order
|
||||
## given.
|
||||
## An entry can have the following properties:
|
||||
## name -- Name of the element (e.g. field or tag). Can be omitted
|
||||
|
|
@ -59,7 +62,7 @@ user-specified configurations.
|
|||
{ name = "address", type = "uint16", assignment = "tag" },
|
||||
{ name = "value", type = "float64" },
|
||||
{ type = "unix", assignment = "time" },
|
||||
]
|
||||
]
|
||||
|
||||
## Optional: Filter evaluated before applying the configuration.
|
||||
## This option can be used to mange multiple configuration specific for
|
||||
|
|
@ -101,14 +104,20 @@ By specifying `allow_no_match` you allow the parser to silently ignore data
|
|||
that does not match _any_ given configuration filter. This can be useful if
|
||||
you only want to collect a subset of the available messages.
|
||||
|
||||
#### `endianess` (optional)
|
||||
#### `endianness` (optional)
|
||||
|
||||
This specifies the endianess of the data. If not specified, the parser will
|
||||
fallback to the "host" endianess, assuming that the message and Telegraf
|
||||
machine share the same endianess.
|
||||
This specifies the endianness of the data. If not specified, the parser will
|
||||
fallback to the "host" endianness, assuming that the message and Telegraf
|
||||
machine share the same endianness.
|
||||
Alternatively, you can explicitly specify big-endian format (`"be"`) or
|
||||
little-endian format (`"le"`).
|
||||
|
||||
#### `hex_encoding` (optional)
|
||||
|
||||
If `true`, the input data is interpreted as a string containing hex-encoded
|
||||
data like `C0 C7 21 A9`. The value is _case insensitive_ and can handle spaces,
|
||||
however prefixes like `0x` or `x` are _not_ allowed.
|
||||
|
||||
### Non-byte aligned value extraction
|
||||
|
||||
In both, `filter` and `entries` definitions, values can be extracted at non-byte
|
||||
|
|
|
|||
|
|
@ -2,8 +2,10 @@ package binary
|
|||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/influxdata/telegraf"
|
||||
|
|
@ -14,6 +16,7 @@ type Parser struct {
|
|||
AllowNoMatch bool `toml:"allow_no_match"`
|
||||
Endianess string `toml:"endianess"`
|
||||
Configs []Config `toml:"binary"`
|
||||
HexEncoding bool `toml:"hex_encoding"`
|
||||
Log telegraf.Logger `toml:"-"`
|
||||
|
||||
metricName string
|
||||
|
|
@ -47,9 +50,21 @@ func (p *Parser) Init() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (p *Parser) Parse(buf []byte) ([]telegraf.Metric, error) {
|
||||
func (p *Parser) Parse(data []byte) ([]telegraf.Metric, error) {
|
||||
t := time.Now()
|
||||
|
||||
// If the data is encoded in HEX, we need to decode it first
|
||||
buf := data
|
||||
if p.HexEncoding {
|
||||
s := strings.ReplaceAll(string(data), " ", "")
|
||||
s = strings.ReplaceAll(s, "\t", "")
|
||||
var err error
|
||||
buf, err = hex.DecodeString(s)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("decoding hex failed: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
matches := 0
|
||||
metrics := make([]telegraf.Metric, 0)
|
||||
for i, cfg := range p.Configs {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package binary
|
|||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
|
@ -1465,3 +1466,35 @@ func TestCases(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestHexEncoding(t *testing.T) {
|
||||
testdata := []interface{}{
|
||||
uint64(0x01020304050607),
|
||||
uint64(0x08090A0B0C0D0E),
|
||||
uint64(0x0F101213141516),
|
||||
uint64(0x1718191A1B1C1D),
|
||||
uint64(0x1E1F2021222324),
|
||||
}
|
||||
|
||||
parser := &Parser{
|
||||
Endianess: "be",
|
||||
HexEncoding: true,
|
||||
Configs: []Config{
|
||||
{
|
||||
Entries: []Entry{dummyEntry},
|
||||
},
|
||||
},
|
||||
Log: testutil.Logger{Name: "parsers.binary"},
|
||||
metricName: "binary",
|
||||
}
|
||||
require.NoError(t, parser.Init())
|
||||
|
||||
// Generate the binary data and encode it to HEX
|
||||
data, err := generateBinary(testdata, binary.BigEndian)
|
||||
require.NoError(t, err)
|
||||
encoded := hex.EncodeToString(data)
|
||||
|
||||
metrics, err := parser.Parse([]byte(encoded))
|
||||
require.NoError(t, err)
|
||||
require.NotEmpty(t, metrics)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue