Add line protocol uint64 support (#3946)

This commit is contained in:
Matt
2018-03-28 19:43:25 -04:00
committed by Daniel Nelson
parent 741abbf590
commit 006ccbf05b
12 changed files with 8046 additions and 6754 deletions

View File

@@ -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)

View File

@@ -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

View File

@@ -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;

View File

@@ -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) {
}

View File

@@ -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)

View File

@@ -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"),

View File

@@ -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')
}

View File

@@ -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(