From dd2c60e6208602bc2024c6c10f81d7bc32d2eeba Mon Sep 17 00:00:00 2001
From: Daniel Nelson <daniel@wavesofdawn.com>
Date: Wed, 18 Apr 2018 12:13:25 -0700
Subject: [PATCH] Fix graphite serialization of unsigned ints (#4033)

---
 plugins/serializers/graphite/graphite.go      | 44 ++++++++++++++-----
 plugins/serializers/graphite/graphite_test.go | 16 +++++++
 2 files changed, 50 insertions(+), 10 deletions(-)

diff --git a/plugins/serializers/graphite/graphite.go b/plugins/serializers/graphite/graphite.go
index ee390d17..0f7fcd8f 100644
--- a/plugins/serializers/graphite/graphite.go
+++ b/plugins/serializers/graphite/graphite.go
@@ -2,8 +2,10 @@ package graphite
 
 import (
 	"fmt"
+	"math"
 	"regexp"
 	"sort"
+	"strconv"
 	"strings"
 
 	"github.com/influxdata/telegraf"
@@ -43,20 +45,14 @@ func (s *GraphiteSerializer) Serialize(metric telegraf.Metric) ([]byte, error) {
 	}
 
 	for fieldName, value := range metric.Fields() {
-		switch v := value.(type) {
-		case string:
+		fieldValue := formatValue(value)
+		if fieldValue == "" {
 			continue
-		case bool:
-			if v {
-				value = 1
-			} else {
-				value = 0
-			}
 		}
-		metricString := fmt.Sprintf("%s %#v %d\n",
+		metricString := fmt.Sprintf("%s %s %d\n",
 			// insert "field" section of template
 			sanitize(InsertField(bucket, fieldName)),
-			value,
+			fieldValue,
 			timestamp)
 		point := []byte(metricString)
 		out = append(out, point...)
@@ -64,6 +60,34 @@ func (s *GraphiteSerializer) Serialize(metric telegraf.Metric) ([]byte, error) {
 	return out, nil
 }
 
+func formatValue(value interface{}) string {
+	switch v := value.(type) {
+	case string:
+		return ""
+	case bool:
+		if v {
+			return "1"
+		} else {
+			return "0"
+		}
+	case uint64:
+		return strconv.FormatUint(v, 10)
+	case int64:
+		return strconv.FormatInt(v, 10)
+	case float64:
+		if math.IsNaN(v) {
+			return ""
+		}
+
+		if math.IsInf(v, 0) {
+			return ""
+		}
+		return strconv.FormatFloat(v, 'f', -1, 64)
+	}
+
+	return ""
+}
+
 // SerializeBucketName will take the given measurement name and tags and
 // produce a graphite bucket. It will use the GraphiteSerializer.Template
 // to generate this, or DEFAULT_TEMPLATE.
diff --git a/plugins/serializers/graphite/graphite_test.go b/plugins/serializers/graphite/graphite_test.go
index 94792112..e08f4759 100644
--- a/plugins/serializers/graphite/graphite_test.go
+++ b/plugins/serializers/graphite/graphite_test.go
@@ -218,6 +218,22 @@ func TestSerializeValueBoolean(t *testing.T) {
 	assert.Equal(t, expS, mS)
 }
 
+func TestSerializeValueUnsigned(t *testing.T) {
+	now := time.Unix(0, 0)
+	tags := map[string]string{}
+	fields := map[string]interface{}{
+		"free": uint64(42),
+	}
+	m, err := metric.New("mem", tags, fields, now)
+	require.NoError(t, err)
+
+	s := GraphiteSerializer{}
+	buf, err := s.Serialize(m)
+	require.NoError(t, err)
+
+	require.Equal(t, buf, []byte(".mem.free 42 0\n"))
+}
+
 // test that fields with spaces get fixed.
 func TestSerializeFieldWithSpaces(t *testing.T) {
 	now := time.Now()
-- 
GitLab