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

feat: add new binary data parser #7030

Closed
wants to merge 64 commits into from
Closed
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
1a64cbe
Initial binary metric implementation
yolkhovyy Oct 13, 2019
2c1b466
Metric time
yolkhovyy Oct 13, 2019
72591fc
Metric time
yolkhovyy Oct 13, 2019
b76cea3
Added string type
yolkhovyy Oct 16, 2019
746e956
Re-factored and tests
yolkhovyy Oct 17, 2019
1365ce8
More tests
yolkhovyy Oct 17, 2019
bc81a4b
More tests
yolkhovyy Oct 18, 2019
7a511f2
Renamed to BinData
yolkhovyy Oct 18, 2019
5421933
Working bindata parser
yolkhovyy Oct 25, 2019
87ca271
Merge branch 'feature/fix_record_parser' into develop
yolkhovyy Oct 26, 2019
eda274e
Optional field size
yolkhovyy Nov 3, 2019
6f944e9
Added bindata parser description in README.md
yolkhovyy Nov 11, 2019
adfda86
README.md updated
yolkhovyy Dec 14, 2019
3e85c0b
Removed Protocol
yolkhovyy Dec 22, 2019
ec20ac2
Fixed typo
yolkhovyy Dec 22, 2019
c300d4f
Remove unused const
yolkhovyy Feb 2, 2020
7a79c8e
Merge branch 'master' into develop
yolkhovyy Feb 2, 2020
746ea4d
Updated README.md
yolkhovyy Feb 2, 2020
72f8137
Reworking string encoding
yolkhovyy Feb 5, 2020
4a1c812
Unit tests for string encoding
yolkhovyy Feb 5, 2020
7e9003c
Merge branch 'feature/new-string-encoding' into develop
yolkhovyy Feb 5, 2020
7b065d7
Padding test cleaned up
yolkhovyy Feb 6, 2020
e32d8a1
UTF-8 unit test
yolkhovyy Feb 6, 2020
ef749af
Unit tests cleaned up
yolkhovyy Feb 8, 2020
eb77521
Merge branch 'feature/utf8-encoding-test' into develop
yolkhovyy Feb 8, 2020
0a30031
Comments and commented out code
yolkhovyy Feb 8, 2020
c49fc04
README.md updated
yolkhovyy Feb 8, 2020
54a0cc8
../registry.go
yolkhovyy Feb 8, 2020
1ad2998
Added bindata factory, reworked unit tests
yolkhovyy Feb 8, 2020
b040ed3
Comments, etc
yolkhovyy Feb 8, 2020
7bdb452
Added unit test for default tags
yolkhovyy Feb 8, 2020
730f08d
Merge branch 'feature/bindata-factory' into develop
yolkhovyy Feb 8, 2020
5a2aee4
README.md updated
yolkhovyy Feb 8, 2020
e7c23c7
Duplicate field names check
yolkhovyy Feb 15, 2020
5b380cd
Merge branch 'develop'
yolkhovyy Feb 15, 2020
094174c
Removed bindata fields in config.go
yolkhovyy Feb 15, 2020
ccd4320
Merge branch 'master' into develop
yolkhovyy Feb 15, 2020
09622b4
Field removal
yolkhovyy Feb 15, 2020
4d3d355
Removed temporary Dockerfile
yolkhovyy Feb 15, 2020
984d7c6
Removed .vscode, reverted README.md
yolkhovyy Feb 16, 2020
2f222d5
Removed unnecassary change
yolkhovyy Feb 16, 2020
3fc716c
Formatting in bindata/paresr_test.go
yolkhovyy Feb 16, 2020
415e3cd
Merge branch 'master' of https://github.com/influxdata/telegraf
yolkhovyy Jun 20, 2020
499e9c3
Review remarks
yolkhovyy Dec 16, 2021
a31907b
Update plugins/parsers/bindata/README.md
yolkhovyy Jan 9, 2022
715a5d1
Update plugins/parsers/bindata/parser.go
yolkhovyy Jan 9, 2022
52e27b8
Update plugins/parsers/bindata/parser.go
yolkhovyy Jan 9, 2022
2abe97d
Update plugins/parsers/bindata/parser.go
yolkhovyy Jan 9, 2022
7fc1ba1
Removed new line
yolkhovyy Jan 9, 2022
f71923f
Removed new line
yolkhovyy Jan 9, 2022
f0c98e1
Update plugins/parsers/bindata/parser.go
yolkhovyy Jan 9, 2022
275858d
Update plugins/parsers/bindata/parser_test.go
yolkhovyy Jan 9, 2022
313c538
Update plugins/parsers/bindata/parser_test.go
yolkhovyy Jan 9, 2022
6be9cc2
Fixed unit test
yolkhovyy Jan 9, 2022
52a45a6
Removed new lines in tests
yolkhovyy Jan 9, 2022
016372b
Default endiannes
yolkhovyy Jan 9, 2022
013c539
Resolved merge conflicts
yolkhovyy Jan 23, 2022
d110b54
Compilation error fixe
yolkhovyy Jan 23, 2022
9ab9d4f
Reworked getParserConfig in config/config.go
yolkhovyy Jan 23, 2022
a8185c4
Lint errors fixed
yolkhovyy Jan 23, 2022
d127f83
Lint errors fixed
yolkhovyy Jan 23, 2022
0b154c2
Lint errors fixed
yolkhovyy Jan 23, 2022
9a93ace
Review comments addressed
yolkhovyy Jan 23, 2022
e5ad2d1
Review comments addressed
yolkhovyy Jan 23, 2022
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
33 changes: 33 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Dockerfile References: https://docs.docker.com/engine/reference/builder/

# Start from the latest golang base image
FROM golang:latest

# Add Maintainer Info
LABEL maintainer="Yuriy Olkhovyy <y.olkhovyy@gmail.com>"

ENV GOPATH /go

# Set the Current Working Directory inside the container
WORKDIR /go/src/github.com/influxdata/telegraf


# Copy go mod and sum files
# COPY go.mod go.sum ./

# Download all dependencies. Dependencies will be cached if the go.mod and go.sum files are not changed
# RUN go mod download

# Copy the source from the current directory to the Working Directory inside the container
COPY . /go/src/github.com/influxdata/telegraf

# Build the Go app
RUN go get -u github.com/golang/dep/cmd/dep
RUN go get ./...
RUN make

# Expose port 8080 to the outside world
# EXPOSE 8080

# Command to run the executable
CMD ["./telegraf"]
66 changes: 66 additions & 0 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import (
"strings"
"time"

"github.com/influxdata/telegraf/plugins/parsers/bindata"

"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/internal"
"github.com/influxdata/telegraf/internal/models"
Expand Down Expand Up @@ -1450,6 +1452,66 @@ func getParserConfig(name string, tbl *ast.Table) (*parsers.Config, error) {
}
}

if node, ok := tbl.Fields["bindata_protocol"]; ok {
if kv, ok := node.(*ast.KeyValue); ok {
if str, ok := kv.Value.(*ast.String); ok {
c.BinDataProtocol = str.Value
}
}
}

if node, ok := tbl.Fields["bindata_endiannes"]; ok {
if kv, ok := node.(*ast.KeyValue); ok {
if str, ok := kv.Value.(*ast.String); ok {
c.BinDataEndiannes = str.Value
}
}
}

if node, ok := tbl.Fields["bindata_time_format"]; ok {
if kv, ok := node.(*ast.KeyValue); ok {
if str, ok := kv.Value.(*ast.String); ok {
c.BinDataTimeFormat = str.Value
}
}
}

if node, ok := tbl.Fields["bindata_fields"]; ok {
if bindataFields, ok := node.([]*ast.Table); ok {
for _, bindataField := range bindataFields {
var field bindata.Field
fmt.Printf("D! FIELD ------\n")
for _, prop := range bindataField.Fields {
if kv, ok := prop.(*ast.KeyValue); ok {
if str, ok := kv.Value.(*ast.String); ok {
fmt.Printf("D! %s %s\n", kv.Key, str.Value)
switch kv.Key {
case "name":
field.Name = str.Value
case "type":
field.Type = str.Value
default:
}
} else if integer, ok := kv.Value.(*ast.Integer); ok {
v, err := strconv.Atoi(integer.Value)
if err == nil {
fmt.Printf("D! %s %d\n", kv.Key, v)
switch kv.Key {
case "offset":
field.Offset = v
case "size":
field.Size = v
default:
}
}
}
}
}
c.BinDataFields = append(c.BinDataFields, field)
}
}
}

if node, ok := tbl.Fields["json_string_fields"]; ok {
if kv, ok := node.(*ast.KeyValue); ok {
if ary, ok := kv.Value.(*ast.Array); ok {
Expand Down Expand Up @@ -1792,6 +1854,10 @@ func getParserConfig(name string, tbl *ast.Table) (*parsers.Config, error) {
delete(tbl.Fields, "separator")
delete(tbl.Fields, "templates")
delete(tbl.Fields, "tag_keys")
delete(tbl.Fields, "bindata_protocol")
delete(tbl.Fields, "bindata_endiannes")
delete(tbl.Fields, "bindata_time_format")
delete(tbl.Fields, "bindata_fields")
delete(tbl.Fields, "json_name_key")
delete(tbl.Fields, "json_query")
delete(tbl.Fields, "json_string_fields")
Expand Down
21 changes: 21 additions & 0 deletions plugins/parsers/bindata/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@



[IBM ZID file](https://www.ibm.com/support/knowledgecenter/en/SSVRGU_8.5.3/com.ibm.designer.domino.main.doc/H_FIELD_OPTIONS_AND_TEXT_INFORMATION_DEFINITION_SYNTAX_2922_OVER.html)

[IBM ZID Example](https://www.ibm.com/support/knowledgecenter/en/SSVRGU_10.0.0/basic/H_BINARY_INPUT_FILES_USING_FIXED_LENGTH_RECORDS_6416_OVER.html)



```toml
[fixed_record]
metric_name = "drone_status"
endiannes = "be"

fields = [
{name="version",type="uint16",offset=0},
{name="time",type="int32",offset=2},
]

```

Binary file added plugins/parsers/bindata/all_types.bin
Binary file not shown.
3 changes: 3 additions & 0 deletions plugins/parsers/bindata/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[fixed_record]
metric_name = "drone_status"
endiannes = "be"
163 changes: 163 additions & 0 deletions plugins/parsers/bindata/parser.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
package bindata

import (
"bytes"
"encoding/binary"
"fmt"
"io"
"reflect"
"strings"
"time"

"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/internal"
"github.com/influxdata/telegraf/metric"
)

const timeKey = "time"
const timezone = "UTC"
const defaultProtocol = "raw"

// Field is ...
type Field struct {
Name string
Type string
Offset int
Size int
}

// BinData is ...
type BinData struct {
MetricName string
Protocol string
TimeFormat string
Endiannes string
Fields []Field
// TagKeys []string
DefaultTags map[string]string
}

// Parse is ...
func (binData *BinData) Parse(data []byte) ([]telegraf.Metric, error) {

if _, err := binData.getProtocol(); err != nil {
return nil, err
}

endiannes, err := binData.getEndiannes()
if err != nil {
return nil, err
}

fields := make(map[string]interface{})
reader := io.NewSectionReader(bytes.NewReader(data), 0, int64(len(data)))

for _, field := range binData.Fields {
fieldBuffer := make([]byte, field.Size)

if _, err := reader.ReadAt(fieldBuffer, int64(field.Offset)); err != nil {
return nil, err
}

fieldType := fieldTypes[strings.ToLower(field.Type)]
if fieldType == nil {
return nil, fmt.Errorf(`invalid field type "%s""`, field.Type)
}

if fieldType.Name() == "string" {
fields[field.Name] = string(fieldBuffer)
} else {
fieldValue := reflect.New(fieldType)
byteReader := bytes.NewReader(fieldBuffer)
binary.Read(byteReader, endiannes, fieldValue.Interface())
fields[field.Name] = fieldValue.Elem().Interface()
}
}

metricTime, err := binData.getTime(fields)
if err != nil {
return nil, err
}

metric, err := metric.New(binData.MetricName, nil, fields, metricTime)
if err != nil {
return nil, err
}

// metricTags := make(map[string]string)
// for _, tagKey := range binData.BinData.TagKeys {
// metricTags[tagKey] = ""
// }

return []telegraf.Metric{metric}, err
}

// ParseLine is ...
func (binData *BinData) ParseLine(line string) (telegraf.Metric, error) {
fmt.Println("BinData.ParseLine() not supported")
return nil, nil
}

// SetDefaultTags is ...
func (binData *BinData) SetDefaultTags(tags map[string]string) {
fmt.Println("BinData.SetDefaultTags() not supported")
}

var fieldTypes = map[string]reflect.Type{
"bool": reflect.TypeOf((*bool)(nil)).Elem(),
"uint8": reflect.TypeOf((*uint8)(nil)).Elem(),
"int8": reflect.TypeOf((*int8)(nil)).Elem(),
"uint16": reflect.TypeOf((*uint16)(nil)).Elem(),
"int16": reflect.TypeOf((*int16)(nil)).Elem(),
"uint32": reflect.TypeOf((*uint32)(nil)).Elem(),
"int32": reflect.TypeOf((*int32)(nil)).Elem(),
"uint64": reflect.TypeOf((*uint64)(nil)).Elem(),
"int64": reflect.TypeOf((*int64)(nil)).Elem(),
"float32": reflect.TypeOf((*float32)(nil)).Elem(),
"float64": reflect.TypeOf((*float64)(nil)).Elem(),
"string": reflect.TypeOf((*string)(nil)).Elem(),
}

func (binData BinData) getProtocol() (string, error) {
protocol := strings.ToLower(binData.Protocol)
if protocol == "" {
} else if protocol != defaultProtocol {
return defaultProtocol, fmt.Errorf("only protocol %s is supported", defaultProtocol)
}
return defaultProtocol, nil
}

func (binData BinData) getEndiannes() (binary.ByteOrder, error) {
var endiannes binary.ByteOrder
cfgEndiannes := strings.ToLower(binData.Endiannes)
if cfgEndiannes == "" || cfgEndiannes == "be" {
endiannes = binary.BigEndian
} else if cfgEndiannes == "le" {
endiannes = binary.LittleEndian
} else {
return nil, fmt.Errorf("invalid binmetric_endiannes %s", cfgEndiannes)
}
return endiannes, nil
}

func (binData BinData) getTime(fields map[string]interface{}) (time.Time, error) {
nilTime := new(time.Time)
metricTime := time.Now()
timeValue := fields[timeKey]
if timeValue != nil {
var err error
switch binData.TimeFormat {
case "unix":
metricTime, err = internal.ParseTimestamp(binData.TimeFormat, int64(timeValue.(int32)), timezone)
srebhan marked this conversation as resolved.
Show resolved Hide resolved
case "unix_ms", "unix_us", "unix_ns":
metricTime, err = internal.ParseTimestamp(binData.TimeFormat, int64(timeValue.(int64)), timezone)
default:
return *nilTime, fmt.Errorf("invalid time format %s", binData.TimeFormat)
srebhan marked this conversation as resolved.
Show resolved Hide resolved
}
if err != nil {
return *nilTime, err
}
delete(fields, timeKey)
}
return metricTime, nil
}
Loading