From 9f8bdb4963150d3538dec63fb89c0c862d451b43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patryk=20Ma=C5=82ek?= Date: Mon, 21 Sep 2020 18:48:27 +0200 Subject: [PATCH] Fix bool serialization when using carbon2 --- plugins/serializers/carbon2/carbon2.go | 32 ++++++++++-- plugins/serializers/carbon2/carbon2_test.go | 57 +++++++++++++++++++++ 2 files changed, 84 insertions(+), 5 deletions(-) diff --git a/plugins/serializers/carbon2/carbon2.go b/plugins/serializers/carbon2/carbon2.go index 4267bfe710c16..2d3fa52171c33 100644 --- a/plugins/serializers/carbon2/carbon2.go +++ b/plugins/serializers/carbon2/carbon2.go @@ -57,7 +57,7 @@ func (s *Serializer) createObject(metric telegraf.Metric) []byte { metricsFormat := s.getMetricsFormat() for fieldName, fieldValue := range metric.Fields() { - if !isNumeric(fieldValue) { + if isString(fieldValue) { continue } @@ -86,7 +86,7 @@ func (s *Serializer) createObject(metric telegraf.Metric) []byte { m.WriteString(" ") } m.WriteString(" ") - m.WriteString(fmt.Sprintf("%v", fieldValue)) + m.WriteString(formatValue(fieldValue)) m.WriteString(" ") m.WriteString(strconv.FormatInt(metric.Time().Unix(), 10)) m.WriteString("\n") @@ -126,11 +126,33 @@ func serializeMetricIncludeField(name, fieldName string) string { ) } -func isNumeric(v interface{}) bool { +func formatValue(fieldValue interface{}) string { + switch v := fieldValue.(type) { + case bool: + // Print bools as 0s and 1s + return fmt.Sprintf("%d", bool2int(v)) + default: + return fmt.Sprintf("%v", v) + } +} + +func isString(v interface{}) bool { switch v.(type) { case string: - return false - default: return true + default: + return false + } +} + +func bool2int(b bool) int { + // Slightly more optimized than a usual if ... return ... else return ... . + // See: https://0x0f.me/blog/golang-compiler-optimization/ + var i int + if b { + i = 1 + } else { + i = 0 } + return i } diff --git a/plugins/serializers/carbon2/carbon2_test.go b/plugins/serializers/carbon2/carbon2_test.go index 64f621875c35d..45a0b71140730 100644 --- a/plugins/serializers/carbon2/carbon2_test.go +++ b/plugins/serializers/carbon2/carbon2_test.go @@ -209,6 +209,63 @@ func TestSerializeMetricString(t *testing.T) { } } +func TestSerializeMetricBool(t *testing.T) { + requireMetric := func(t *testing.T, tim time.Time, value bool) telegraf.Metric { + tags := map[string]string{ + "tag_name": "tag_value", + } + fields := map[string]interface{}{ + "java_lang_GarbageCollector_Valid": value, + } + + m, err := metric.New("cpu", tags, fields, tim) + require.NoError(t, err) + + return m + } + + now := time.Now() + + testcases := []struct { + metric telegraf.Metric + format string + expected string + }{ + { + metric: requireMetric(t, now, false), + format: Carbon2FormatFieldSeparate, + expected: fmt.Sprintf("metric=cpu field=java_lang_GarbageCollector_Valid tag_name=tag_value 0 %d\n", now.Unix()), + }, + { + metric: requireMetric(t, now, false), + format: Carbon2FormatMetricIncludesField, + expected: fmt.Sprintf("metric=cpu_java_lang_GarbageCollector_Valid tag_name=tag_value 0 %d\n", now.Unix()), + }, + { + metric: requireMetric(t, now, true), + format: Carbon2FormatFieldSeparate, + expected: fmt.Sprintf("metric=cpu field=java_lang_GarbageCollector_Valid tag_name=tag_value 1 %d\n", now.Unix()), + }, + { + metric: requireMetric(t, now, true), + format: Carbon2FormatMetricIncludesField, + expected: fmt.Sprintf("metric=cpu_java_lang_GarbageCollector_Valid tag_name=tag_value 1 %d\n", now.Unix()), + }, + } + + for _, tc := range testcases { + t.Run(tc.format, func(t *testing.T) { + s, err := NewSerializer(tc.format) + require.NoError(t, err) + + buf, err := s.Serialize(tc.metric) + require.NoError(t, err) + + assert.Equal(t, tc.expected, string(buf)) + }) + } +} + func TestSerializeBatch(t *testing.T) { m := MustMetric( metric.New(