Add line protocol uint64 support (#3946)
This commit is contained in:
parent
ef112e6ee7
commit
a320f91516
8
Makefile
8
Makefile
|
@ -4,6 +4,7 @@ BRANCH := $(shell git rev-parse --abbrev-ref HEAD)
|
|||
COMMIT := $(shell git rev-parse --short HEAD)
|
||||
GOFILES ?= $(shell git ls-files '*.go')
|
||||
GOFMT ?= $(shell gofmt -l $(filter-out plugins/parsers/influx/machine.go, $(GOFILES)))
|
||||
BUILDFLAGS ?=
|
||||
|
||||
ifdef GOBIN
|
||||
PATH := $(GOBIN):$(PATH)
|
||||
|
@ -35,7 +36,7 @@ deps:
|
|||
gdm restore
|
||||
|
||||
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 -ldflags "-w -s $(LDFLAGS)" ./cmd/telegraf
|
||||
|
@ -61,6 +62,9 @@ fmtcheck:
|
|||
fi
|
||||
@echo '[INFO] done.'
|
||||
|
||||
uint64:
|
||||
BUILDFLAGS="-tags uint64" $(MAKE) all
|
||||
|
||||
lint:
|
||||
golint ./...
|
||||
|
||||
|
@ -99,4 +103,4 @@ docker-image:
|
|||
plugins/parsers/influx/machine.go: plugins/parsers/influx/machine.go.rl
|
||||
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)
|
||||
|
||||
// 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 {
|
||||
name string
|
||||
tags []*telegraf.Tag
|
||||
|
@ -265,11 +275,14 @@ func convertField(v interface{}) interface{} {
|
|||
return int64(MaxInt)
|
||||
}
|
||||
case uint64:
|
||||
if enableUint64Support == false {
|
||||
if v <= uint64(MaxInt) {
|
||||
return int64(v)
|
||||
} else {
|
||||
return int64(MaxInt)
|
||||
}
|
||||
}
|
||||
return uint64(v)
|
||||
case []byte:
|
||||
return string(v)
|
||||
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)
|
||||
}
|
||||
|
||||
// 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.
|
||||
func parseFloatBytes(b []byte, bitSize int) (float64, error) {
|
||||
s := unsafeBytesToString(b)
|
||||
|
|
|
@ -54,6 +54,16 @@ func (h *MetricHandler) AddInt(key []byte, value []byte) {
|
|||
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) {
|
||||
fk := unescape(key)
|
||||
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())
|
||||
}
|
||||
|
||||
action unsigned {
|
||||
m.handler.AddUint(key, m.text())
|
||||
}
|
||||
|
||||
action float {
|
||||
m.handler.AddFloat(key, m.text())
|
||||
}
|
||||
|
@ -114,6 +118,9 @@ non_zero_digit =
|
|||
integer =
|
||||
'-'? ( digit | ( non_zero_digit digit* ) );
|
||||
|
||||
unsigned =
|
||||
( digit | ( non_zero_digit digit* ) );
|
||||
|
||||
number =
|
||||
( integer ( '.' digit* )? ) | ( '.' digit* );
|
||||
|
||||
|
@ -135,6 +142,9 @@ fieldfloat =
|
|||
fieldinteger =
|
||||
(integer 'i') >begin %integer;
|
||||
|
||||
fieldunsigned =
|
||||
(unsigned 'u') >begin %unsigned;
|
||||
|
||||
false =
|
||||
"false" | "FALSE" | "False" | "F" | "f";
|
||||
|
||||
|
@ -153,7 +163,7 @@ fieldstring =
|
|||
fieldstringquoted =
|
||||
'"' fieldstring '"';
|
||||
|
||||
fieldvalue = fieldinteger | fieldfloat | fieldstringquoted | fieldbool;
|
||||
fieldvalue = fieldinteger | fieldunsigned | fieldfloat | fieldstringquoted | fieldbool;
|
||||
|
||||
field =
|
||||
fieldkey '=' fieldvalue;
|
||||
|
|
|
@ -43,6 +43,18 @@ func (h *TestingHandler) AddInt(key []byte, value []byte) {
|
|||
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) {
|
||||
fieldkey := Result{
|
||||
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) AddUint(key []byte, value []byte) {
|
||||
}
|
||||
|
||||
func (h *BenchmarkingHandler) AddFloat(key []byte, value []byte) {
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ type Handler interface {
|
|||
SetMeasurement(name []byte)
|
||||
AddTag(key []byte, value []byte)
|
||||
AddInt(key []byte, value []byte)
|
||||
AddUint(key []byte, value []byte)
|
||||
AddFloat(key []byte, value []byte)
|
||||
AddString(key []byte, value []byte)
|
||||
AddBool(key []byte, value []byte)
|
||||
|
|
|
@ -16,6 +16,12 @@ func Metric(v telegraf.Metric, err error) telegraf.Metric {
|
|||
return v
|
||||
}
|
||||
|
||||
const (
|
||||
Uint64Overflow uint64 = 9223372036854775808
|
||||
Uint64Max uint64 = 18446744073709551615
|
||||
Uint64Test uint64 = 42
|
||||
)
|
||||
|
||||
var DefaultTime = func() time.Time {
|
||||
return time.Unix(42, 0)
|
||||
}
|
||||
|
@ -256,6 +262,57 @@ var ptests = []struct {
|
|||
},
|
||||
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",
|
||||
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) {
|
||||
switch v := value.(type) {
|
||||
case uint64:
|
||||
return appendUintField(buf, v), nil
|
||||
case int64:
|
||||
return appendIntField(buf, v), nil
|
||||
case float64:
|
||||
|
@ -257,6 +259,10 @@ func appendFieldValue(buf []byte, value interface{}) ([]byte, error) {
|
|||
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 {
|
||||
return append(strconv.AppendInt(buf, value, 10), 'i')
|
||||
}
|
||||
|
|
|
@ -11,12 +11,20 @@ import (
|
|||
)
|
||||
|
||||
func MustMetric(v telegraf.Metric, err error) telegraf.Metric {
|
||||
// Force uint support to be enabled for testing.
|
||||
metric.EnableUintSupport()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
const (
|
||||
Uint64Overflow uint64 = 9223372036854775808
|
||||
Uint64Max uint64 = 18446744073709551615
|
||||
Uint64Test uint64 = 42
|
||||
)
|
||||
|
||||
var tests = []struct {
|
||||
name string
|
||||
maxBytes int
|
||||
|
@ -128,6 +136,48 @@ var tests = []struct {
|
|||
),
|
||||
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",
|
||||
input: MustMetric(
|
||||
|
|
Loading…
Reference in New Issue