Add custom metrics name builder in graphite output

This commit is contained in:
alexander akulov 2016-02-04 18:28:20 +05:00
parent 331b700d1b
commit 85f40ad742
2 changed files with 69 additions and 60 deletions

View File

@ -1,6 +1,7 @@
package graphite package graphite
import ( import (
"bytes"
"errors" "errors"
"fmt" "fmt"
"github.com/influxdata/telegraf" "github.com/influxdata/telegraf"
@ -15,10 +16,11 @@ import (
type Graphite struct { type Graphite struct {
// URL is only for backwards compatability // URL is only for backwards compatability
Servers []string Servers []string
Prefix string Prefix string
Timeout int Timeout int
conns []net.Conn MetricsNameBuilder map[string][]string
conns []net.Conn
} }
var sampleConfig = ` var sampleConfig = `
@ -28,6 +30,11 @@ var sampleConfig = `
prefix = "" prefix = ""
# timeout in seconds for the write connection to graphite # timeout in seconds for the write connection to graphite
timeout = 2 timeout = 2
# # Build custom metric name from tags for each plugins
# [graphite.metricsnamebuilder]
# # Igore unlisted tags and put metric name after disk name
# diskio = ["host","{{metric}}","name","{{field}}"]
# disk = ["host","{{metric}}","name","{{field}}"]
` `
func (g *Graphite) Connect() error { func (g *Graphite) Connect() error {
@ -72,34 +79,16 @@ func (g *Graphite) Write(metrics []telegraf.Metric) error {
// Prepare data // Prepare data
var bp []string var bp []string
for _, metric := range metrics { for _, metric := range metrics {
// Get name
name := metric.Name()
// Convert UnixNano to Unix timestamps // Convert UnixNano to Unix timestamps
timestamp := metric.UnixNano() / 1000000000 timestamp := metric.UnixNano() / 1000000000
tag_str := buildTags(metric)
for field_name, value := range metric.Fields() { for field_name, value := range metric.Fields() {
// Convert value // Convert value
value_str := fmt.Sprintf("%#v", value) value_str := fmt.Sprintf("%#v", value)
// Write graphite metric // Write graphite metric
var graphitePoint string graphitePoint := fmt.Sprintf("%s %s %d\n",
if name == field_name { g.buildMetricName(metric, field_name),
graphitePoint = fmt.Sprintf("%s.%s %s %d\n", value_str,
tag_str, timestamp)
strings.Replace(name, ".", "_", -1),
value_str,
timestamp)
} else {
graphitePoint = fmt.Sprintf("%s.%s.%s %s %d\n",
tag_str,
strings.Replace(name, ".", "_", -1),
strings.Replace(field_name, ".", "_", -1),
value_str,
timestamp)
}
if g.Prefix != "" {
graphitePoint = fmt.Sprintf("%s.%s", g.Prefix, graphitePoint)
}
bp = append(bp, graphitePoint) bp = append(bp, graphitePoint)
} }
} }
@ -107,7 +96,6 @@ func (g *Graphite) Write(metrics []telegraf.Metric) error {
// This will get set to nil if a successful write occurs // This will get set to nil if a successful write occurs
err := errors.New("Could not write to any Graphite server in cluster\n") err := errors.New("Could not write to any Graphite server in cluster\n")
// Send data to a random server // Send data to a random server
p := rand.Perm(len(g.conns)) p := rand.Perm(len(g.conns))
for _, n := range p { for _, n := range p {
@ -127,36 +115,35 @@ func (g *Graphite) Write(metrics []telegraf.Metric) error {
} }
return err return err
} }
func (g *Graphite) buildMetricName(metric telegraf.Metric, fieldName string) string {
func buildTags(metric telegraf.Metric) string { metricName := bytes.NewBufferString(g.Prefix)
var keys []string metricName.WriteString(".")
tags := metric.Tags() tags := metric.Tags()
for k := range tags { metricsTemplate, ok := g.MetricsNameBuilder[metric.Name()]
if k == "host" { if !ok {
metricsTemplate = []string{"host"}
for k := range tags {
if k != "host" {
metricsTemplate = append(metricsTemplate, k)
}
}
sort.Strings(metricsTemplate[1:])
if metric.Name() != fieldName {
metricsTemplate = append(metricsTemplate, "{{metric}}")
}
metricsTemplate = append(metricsTemplate, "{{field}}")
}
tags["{{metric}}"] = metric.Name()
tags["{{field}}"] = fieldName
for _, tagName := range metricsTemplate {
tagValue, ok := tags[tagName]
if !ok || tagValue == "" {
continue continue
} }
keys = append(keys, k) metricName.WriteString(strings.Replace(tagValue, ".", "_", -1))
metricName.WriteString(".")
} }
sort.Strings(keys) return strings.Trim(metricName.String(), ".")
var tag_str string
if host, ok := tags["host"]; ok {
if len(keys) > 0 {
tag_str = strings.Replace(host, ".", "_", -1) + "."
} else {
tag_str = strings.Replace(host, ".", "_", -1)
}
}
for i, k := range keys {
tag_value := strings.Replace(tags[k], ".", "_", -1)
if i == 0 {
tag_str += tag_value
} else {
tag_str += "." + tag_value
}
}
return tag_str
} }
func init() { func init() {

View File

@ -103,7 +103,7 @@ func TCPServer(t *testing.T, wg *sync.WaitGroup) {
wg.Done() wg.Done()
} }
func TestGraphiteTags(t *testing.T) { func TestGraphiteMetricName(t *testing.T) {
m1, _ := telegraf.NewMetric( m1, _ := telegraf.NewMetric(
"mymeasurement", "mymeasurement",
map[string]string{"host": "192.168.0.1"}, map[string]string{"host": "192.168.0.1"},
@ -122,12 +122,34 @@ func TestGraphiteTags(t *testing.T) {
map[string]interface{}{"value": float64(3.14)}, map[string]interface{}{"value": float64(3.14)},
time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC), time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC),
) )
m4, _ := telegraf.NewMetric(
"custom1",
map[string]string{"host": "192.168.0.1", "afoo": "first", "bfoo": "second"},
map[string]interface{}{"value": float64(3.14)},
time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC),
)
m5, _ := telegraf.NewMetric(
"custom.2",
map[string]string{"host": "192.168.0.1", "afoo": "first", "bfoo": "second"},
map[string]interface{}{"value": float64(3.14)},
time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC),
)
g := Graphite{
Prefix: "my.prefix",
MetricsNameBuilder: map[string][]string{
"custom1": []string{"host", "afoo", "bfoo"},
"custom.2": []string{"{{field}}", "bfoo", "{{metric}}"}},
}
metricName1 := g.buildMetricName(m1, "value")
metricName2 := g.buildMetricName(m2, "value")
metricName3 := g.buildMetricName(m3, "value")
metricName4 := g.buildMetricName(m4, "value")
metricName5 := g.buildMetricName(m5, "value")
tags1 := buildTags(m1) assert.Equal(t, "my.prefix.192_168_0_1.mymeasurement.value", metricName1)
tags2 := buildTags(m2) assert.Equal(t, "my.prefix.192_168_0_1.first.second.mymeasurement.value", metricName2)
tags3 := buildTags(m3) assert.Equal(t, "my.prefix.first.second.mymeasurement.value", metricName3)
assert.Equal(t, "my.prefix.192_168_0_1.first.second", metricName4)
assert.Equal(t, "my.prefix.value.second.custom_2", metricName5)
assert.Equal(t, "192_168_0_1", tags1)
assert.Equal(t, "192_168_0_1.first.second", tags2)
assert.Equal(t, "first.second", tags3)
} }