Add line protocol uint64 support (#3946)
This commit is contained in:
parent
741abbf590
commit
006ccbf05b
8
Makefile
8
Makefile
|
@ -4,6 +4,7 @@ BRANCH := $(shell git rev-parse --abbrev-ref HEAD)
|
||||||
COMMIT := $(shell git rev-parse --short HEAD)
|
COMMIT := $(shell git rev-parse --short HEAD)
|
||||||
GOFILES ?= $(shell git ls-files '*.go')
|
GOFILES ?= $(shell git ls-files '*.go')
|
||||||
GOFMT ?= $(shell gofmt -l $(filter-out plugins/parsers/influx/machine.go, $(GOFILES)))
|
GOFMT ?= $(shell gofmt -l $(filter-out plugins/parsers/influx/machine.go, $(GOFILES)))
|
||||||
|
BUILDFLAGS ?=
|
||||||
|
|
||||||
ifdef GOBIN
|
ifdef GOBIN
|
||||||
PATH := $(GOBIN):$(PATH)
|
PATH := $(GOBIN):$(PATH)
|
||||||
|
@ -35,7 +36,7 @@ deps:
|
||||||
gdm restore
|
gdm restore
|
||||||
|
|
||||||
telegraf:
|
telegraf:
|
||||||
go build -i -o $(TELEGRAF) -ldflags "$(LDFLAGS)" ./cmd/telegraf/telegraf.go
|
go build -i -o $(TELEGRAF) -ldflags "$(LDFLAGS)" $(BUILDFLAGS) ./cmd/telegraf/telegraf.go
|
||||||
|
|
||||||
go-install:
|
go-install:
|
||||||
go install -ldflags "-w -s $(LDFLAGS)" ./cmd/telegraf
|
go install -ldflags "-w -s $(LDFLAGS)" ./cmd/telegraf
|
||||||
|
@ -61,6 +62,9 @@ fmtcheck:
|
||||||
fi
|
fi
|
||||||
@echo '[INFO] done.'
|
@echo '[INFO] done.'
|
||||||
|
|
||||||
|
uint64:
|
||||||
|
BUILDFLAGS="-tags uint64" $(MAKE) all
|
||||||
|
|
||||||
lint:
|
lint:
|
||||||
golint ./...
|
golint ./...
|
||||||
|
|
||||||
|
@ -99,4 +103,4 @@ docker-image:
|
||||||
plugins/parsers/influx/machine.go: plugins/parsers/influx/machine.go.rl
|
plugins/parsers/influx/machine.go: plugins/parsers/influx/machine.go.rl
|
||||||
ragel -Z -G2 $^ -o $@
|
ragel -Z -G2 $^ -o $@
|
||||||
|
|
||||||
.PHONY: deps telegraf install test test-windows lint vet test-all package clean docker-image fmtcheck
|
.PHONY: deps telegraf install test test-windows lint vet test-all package clean docker-image fmtcheck uint64
|
||||||
|
|
|
@ -11,6 +11,16 @@ import (
|
||||||
|
|
||||||
const MaxInt = int(^uint(0) >> 1)
|
const MaxInt = int(^uint(0) >> 1)
|
||||||
|
|
||||||
|
// enableUint64Support will enable uint64 support if set to true.
|
||||||
|
var enableUint64Support = false
|
||||||
|
|
||||||
|
// EnableUintSupport manually enables uint support for convertValue.
|
||||||
|
// This function will be removed in the future and only exists for unit tests during the
|
||||||
|
// transition.
|
||||||
|
func EnableUintSupport() {
|
||||||
|
enableUint64Support = true
|
||||||
|
}
|
||||||
|
|
||||||
type metric struct {
|
type metric struct {
|
||||||
name string
|
name string
|
||||||
tags []*telegraf.Tag
|
tags []*telegraf.Tag
|
||||||
|
@ -265,11 +275,14 @@ func convertField(v interface{}) interface{} {
|
||||||
return int64(MaxInt)
|
return int64(MaxInt)
|
||||||
}
|
}
|
||||||
case uint64:
|
case uint64:
|
||||||
if v <= uint64(MaxInt) {
|
if enableUint64Support == false {
|
||||||
return int64(v)
|
if v <= uint64(MaxInt) {
|
||||||
} else {
|
return int64(v)
|
||||||
return int64(MaxInt)
|
} else {
|
||||||
|
return int64(MaxInt)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return uint64(v)
|
||||||
case []byte:
|
case []byte:
|
||||||
return string(v)
|
return string(v)
|
||||||
case int32:
|
case int32:
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
// +build uint64
|
||||||
|
|
||||||
|
package metric
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
EnableUintSupport()
|
||||||
|
}
|
|
@ -63,6 +63,12 @@ func parseIntBytes(b []byte, base int, bitSize int) (i int64, err error) {
|
||||||
return strconv.ParseInt(s, base, bitSize)
|
return strconv.ParseInt(s, base, bitSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// parseUintBytes is a zero-alloc wrapper around strconv.ParseUint.
|
||||||
|
func parseUintBytes(b []byte, base int, bitSize int) (i uint64, err error) {
|
||||||
|
s := unsafeBytesToString(b)
|
||||||
|
return strconv.ParseUint(s, base, bitSize)
|
||||||
|
}
|
||||||
|
|
||||||
// parseFloatBytes is a zero-alloc wrapper around strconv.ParseFloat.
|
// parseFloatBytes is a zero-alloc wrapper around strconv.ParseFloat.
|
||||||
func parseFloatBytes(b []byte, bitSize int) (float64, error) {
|
func parseFloatBytes(b []byte, bitSize int) (float64, error) {
|
||||||
s := unsafeBytesToString(b)
|
s := unsafeBytesToString(b)
|
||||||
|
|
|
@ -54,6 +54,16 @@ func (h *MetricHandler) AddInt(key []byte, value []byte) {
|
||||||
h.builder.AddField(fk, fv)
|
h.builder.AddField(fk, fv)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *MetricHandler) AddUint(key []byte, value []byte) {
|
||||||
|
fk := unescape(key)
|
||||||
|
fv, err := parseUintBytes(bytes.TrimSuffix(value, []byte("u")), 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("E! Received unparseable uint value: %q", value)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
h.builder.AddField(fk, fv)
|
||||||
|
}
|
||||||
|
|
||||||
func (h *MetricHandler) AddFloat(key []byte, value []byte) {
|
func (h *MetricHandler) AddFloat(key []byte, value []byte) {
|
||||||
fk := unescape(key)
|
fk := unescape(key)
|
||||||
fv, err := parseFloatBytes(value, 64)
|
fv, err := parseFloatBytes(value, 64)
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -89,6 +89,10 @@ action integer {
|
||||||
m.handler.AddInt(key, m.text())
|
m.handler.AddInt(key, m.text())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
action unsigned {
|
||||||
|
m.handler.AddUint(key, m.text())
|
||||||
|
}
|
||||||
|
|
||||||
action float {
|
action float {
|
||||||
m.handler.AddFloat(key, m.text())
|
m.handler.AddFloat(key, m.text())
|
||||||
}
|
}
|
||||||
|
@ -114,6 +118,9 @@ non_zero_digit =
|
||||||
integer =
|
integer =
|
||||||
'-'? ( digit | ( non_zero_digit digit* ) );
|
'-'? ( digit | ( non_zero_digit digit* ) );
|
||||||
|
|
||||||
|
unsigned =
|
||||||
|
( digit | ( non_zero_digit digit* ) );
|
||||||
|
|
||||||
number =
|
number =
|
||||||
( integer ( '.' digit* )? ) | ( '.' digit* );
|
( integer ( '.' digit* )? ) | ( '.' digit* );
|
||||||
|
|
||||||
|
@ -135,6 +142,9 @@ fieldfloat =
|
||||||
fieldinteger =
|
fieldinteger =
|
||||||
(integer 'i') >begin %integer;
|
(integer 'i') >begin %integer;
|
||||||
|
|
||||||
|
fieldunsigned =
|
||||||
|
(unsigned 'u') >begin %unsigned;
|
||||||
|
|
||||||
false =
|
false =
|
||||||
"false" | "FALSE" | "False" | "F" | "f";
|
"false" | "FALSE" | "False" | "F" | "f";
|
||||||
|
|
||||||
|
@ -153,7 +163,7 @@ fieldstring =
|
||||||
fieldstringquoted =
|
fieldstringquoted =
|
||||||
'"' fieldstring '"';
|
'"' fieldstring '"';
|
||||||
|
|
||||||
fieldvalue = fieldinteger | fieldfloat | fieldstringquoted | fieldbool;
|
fieldvalue = fieldinteger | fieldunsigned | fieldfloat | fieldstringquoted | fieldbool;
|
||||||
|
|
||||||
field =
|
field =
|
||||||
fieldkey '=' fieldvalue;
|
fieldkey '=' fieldvalue;
|
||||||
|
|
|
@ -43,6 +43,18 @@ func (h *TestingHandler) AddInt(key []byte, value []byte) {
|
||||||
h.results = append(h.results, fieldkey, fieldvalue)
|
h.results = append(h.results, fieldkey, fieldvalue)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *TestingHandler) AddUint(key []byte, value []byte) {
|
||||||
|
fieldkey := Result{
|
||||||
|
Name: FieldKey,
|
||||||
|
Value: key,
|
||||||
|
}
|
||||||
|
fieldvalue := Result{
|
||||||
|
Name: FieldUint,
|
||||||
|
Value: value,
|
||||||
|
}
|
||||||
|
h.results = append(h.results, fieldkey, fieldvalue)
|
||||||
|
}
|
||||||
|
|
||||||
func (h *TestingHandler) AddFloat(key []byte, value []byte) {
|
func (h *TestingHandler) AddFloat(key []byte, value []byte) {
|
||||||
fieldkey := Result{
|
fieldkey := Result{
|
||||||
Name: FieldKey,
|
Name: FieldKey,
|
||||||
|
@ -113,6 +125,9 @@ func (h *BenchmarkingHandler) AddTag(key []byte, value []byte) {
|
||||||
func (h *BenchmarkingHandler) AddInt(key []byte, value []byte) {
|
func (h *BenchmarkingHandler) AddInt(key []byte, value []byte) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *BenchmarkingHandler) AddUint(key []byte, value []byte) {
|
||||||
|
}
|
||||||
|
|
||||||
func (h *BenchmarkingHandler) AddFloat(key []byte, value []byte) {
|
func (h *BenchmarkingHandler) AddFloat(key []byte, value []byte) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ type Handler interface {
|
||||||
SetMeasurement(name []byte)
|
SetMeasurement(name []byte)
|
||||||
AddTag(key []byte, value []byte)
|
AddTag(key []byte, value []byte)
|
||||||
AddInt(key []byte, value []byte)
|
AddInt(key []byte, value []byte)
|
||||||
|
AddUint(key []byte, value []byte)
|
||||||
AddFloat(key []byte, value []byte)
|
AddFloat(key []byte, value []byte)
|
||||||
AddString(key []byte, value []byte)
|
AddString(key []byte, value []byte)
|
||||||
AddBool(key []byte, value []byte)
|
AddBool(key []byte, value []byte)
|
||||||
|
|
|
@ -16,6 +16,12 @@ func Metric(v telegraf.Metric, err error) telegraf.Metric {
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
Uint64Overflow uint64 = 9223372036854775808
|
||||||
|
Uint64Max uint64 = 18446744073709551615
|
||||||
|
Uint64Test uint64 = 42
|
||||||
|
)
|
||||||
|
|
||||||
var DefaultTime = func() time.Time {
|
var DefaultTime = func() time.Time {
|
||||||
return time.Unix(42, 0)
|
return time.Unix(42, 0)
|
||||||
}
|
}
|
||||||
|
@ -256,6 +262,57 @@ var ptests = []struct {
|
||||||
},
|
},
|
||||||
err: nil,
|
err: nil,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "field uint",
|
||||||
|
input: []byte("cpu value=42u"),
|
||||||
|
metrics: []telegraf.Metric{
|
||||||
|
Metric(
|
||||||
|
metric.New(
|
||||||
|
"cpu",
|
||||||
|
map[string]string{},
|
||||||
|
map[string]interface{}{
|
||||||
|
"value": Uint64Test,
|
||||||
|
},
|
||||||
|
time.Unix(42, 0),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
err: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "field uint int overflow",
|
||||||
|
input: []byte("cpu value=9223372036854775808u"),
|
||||||
|
metrics: []telegraf.Metric{
|
||||||
|
Metric(
|
||||||
|
metric.New(
|
||||||
|
"cpu",
|
||||||
|
map[string]string{},
|
||||||
|
map[string]interface{}{
|
||||||
|
"value": Uint64Overflow,
|
||||||
|
},
|
||||||
|
time.Unix(42, 0),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
err: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "field uint maximum",
|
||||||
|
input: []byte("cpu value=18446744073709551615u"),
|
||||||
|
metrics: []telegraf.Metric{
|
||||||
|
Metric(
|
||||||
|
metric.New(
|
||||||
|
"cpu",
|
||||||
|
map[string]string{},
|
||||||
|
map[string]interface{}{
|
||||||
|
"value": Uint64Max,
|
||||||
|
},
|
||||||
|
time.Unix(42, 0),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
err: nil,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "field boolean",
|
name: "field boolean",
|
||||||
input: []byte("cpu value=true"),
|
input: []byte("cpu value=true"),
|
||||||
|
|
|
@ -237,6 +237,8 @@ func (s *Serializer) writeMetric(w io.Writer, m telegraf.Metric) error {
|
||||||
|
|
||||||
func appendFieldValue(buf []byte, value interface{}) ([]byte, error) {
|
func appendFieldValue(buf []byte, value interface{}) ([]byte, error) {
|
||||||
switch v := value.(type) {
|
switch v := value.(type) {
|
||||||
|
case uint64:
|
||||||
|
return appendUintField(buf, v), nil
|
||||||
case int64:
|
case int64:
|
||||||
return appendIntField(buf, v), nil
|
return appendIntField(buf, v), nil
|
||||||
case float64:
|
case float64:
|
||||||
|
@ -257,6 +259,10 @@ func appendFieldValue(buf []byte, value interface{}) ([]byte, error) {
|
||||||
return buf, ErrInvalidFieldType
|
return buf, ErrInvalidFieldType
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func appendUintField(buf []byte, value uint64) []byte {
|
||||||
|
return append(strconv.AppendUint(buf, value, 10), 'u')
|
||||||
|
}
|
||||||
|
|
||||||
func appendIntField(buf []byte, value int64) []byte {
|
func appendIntField(buf []byte, value int64) []byte {
|
||||||
return append(strconv.AppendInt(buf, value, 10), 'i')
|
return append(strconv.AppendInt(buf, value, 10), 'i')
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,12 +11,20 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func MustMetric(v telegraf.Metric, err error) telegraf.Metric {
|
func MustMetric(v telegraf.Metric, err error) telegraf.Metric {
|
||||||
|
// Force uint support to be enabled for testing.
|
||||||
|
metric.EnableUintSupport()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
Uint64Overflow uint64 = 9223372036854775808
|
||||||
|
Uint64Max uint64 = 18446744073709551615
|
||||||
|
Uint64Test uint64 = 42
|
||||||
|
)
|
||||||
|
|
||||||
var tests = []struct {
|
var tests = []struct {
|
||||||
name string
|
name string
|
||||||
maxBytes int
|
maxBytes int
|
||||||
|
@ -128,6 +136,48 @@ var tests = []struct {
|
||||||
),
|
),
|
||||||
output: []byte("cpu value=42i 0\n"),
|
output: []byte("cpu value=42i 0\n"),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "uint field",
|
||||||
|
input: MustMetric(
|
||||||
|
metric.New(
|
||||||
|
"cpu",
|
||||||
|
map[string]string{},
|
||||||
|
map[string]interface{}{
|
||||||
|
"value": Uint64Test,
|
||||||
|
},
|
||||||
|
time.Unix(0, 0),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
output: []byte("cpu value=42u 0\n"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "uint field int64 overflow",
|
||||||
|
input: MustMetric(
|
||||||
|
metric.New(
|
||||||
|
"cpu",
|
||||||
|
map[string]string{},
|
||||||
|
map[string]interface{}{
|
||||||
|
"value": Uint64Overflow,
|
||||||
|
},
|
||||||
|
time.Unix(0, 0),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
output: []byte("cpu value=9223372036854775808u 0\n"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "uint field uint64 max",
|
||||||
|
input: MustMetric(
|
||||||
|
metric.New(
|
||||||
|
"cpu",
|
||||||
|
map[string]string{},
|
||||||
|
map[string]interface{}{
|
||||||
|
"value": Uint64Max,
|
||||||
|
},
|
||||||
|
time.Unix(0, 0),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
output: []byte("cpu value=18446744073709551615u 0\n"),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "bool field",
|
name: "bool field",
|
||||||
input: MustMetric(
|
input: MustMetric(
|
||||||
|
|
Loading…
Reference in New Issue