File: graphite.go

package info (click to toggle)
golang-collectd 0.5.0%2Bgit20240104.26404de-1
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 468 kB
  • sloc: ansic: 324; sh: 7; makefile: 3
file content (103 lines) | stat: -rw-r--r-- 2,191 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
package format // import "collectd.org/format"

import (
	"context"
	"fmt"
	"io"
	"strings"
	"time"

	"collectd.org/api"
)

// Graphite implements the Writer interface and writes ValueLists in Graphite
// format to W.
type Graphite struct {
	W                 io.Writer
	Prefix, Suffix    string
	EscapeChar        string
	SeparateInstances bool
	AlwaysAppendDS    bool // TODO(octo): Implement support.
	replacer          *strings.Replacer
}

func (g *Graphite) escape(in string) string {
	if g.replacer == nil {
		g.replacer = strings.NewReplacer(
			".", g.EscapeChar,
			"\t", g.EscapeChar,
			"\"", g.EscapeChar,
			"\\", g.EscapeChar,
			":", g.EscapeChar,
			"!", g.EscapeChar,
			"/", g.EscapeChar,
			"(", g.EscapeChar,
			")", g.EscapeChar,
			"\n", g.EscapeChar,
			"\r", g.EscapeChar)
	}
	return g.replacer.Replace(in)
}

func (g *Graphite) formatName(id api.Identifier, dsName string) string {
	var instanceSeparator = "-"
	if g.SeparateInstances {
		instanceSeparator = "."
	}

	host := g.escape(id.Host)
	plugin := g.escape(id.Plugin)
	if id.PluginInstance != "" {
		plugin += instanceSeparator + g.escape(id.PluginInstance)
	}

	typ := id.Type
	if id.TypeInstance != "" {
		typ += instanceSeparator + g.escape(id.TypeInstance)
	}

	name := g.Prefix + host + g.Suffix + "." + plugin + "." + typ
	if dsName != "" {
		name += "." + g.escape(dsName)
	}

	return name
}

func (g *Graphite) formatValue(v api.Value) (string, error) {
	switch v := v.(type) {
	case api.Gauge:
		return fmt.Sprintf("%.15g", v), nil
	case api.Derive, api.Counter:
		return fmt.Sprintf("%v", v), nil
	default:
		return "", fmt.Errorf("unexpected type %T", v)
	}
}

// Write formats the ValueList in the PUTVAL format and writes it to the
// assiciated io.Writer.
func (g *Graphite) Write(_ context.Context, vl *api.ValueList) error {
	for i, v := range vl.Values {
		dsName := ""
		if g.AlwaysAppendDS || len(vl.Values) != 1 {
			dsName = vl.DSName(i)
		}

		name := g.formatName(vl.Identifier, dsName)

		val, err := g.formatValue(v)
		if err != nil {
			return err
		}

		t := vl.Time
		if t.IsZero() {
			t = time.Now()
		}

		fmt.Fprintf(g.W, "%s %s %d\r\n", name, val, t.Unix())
	}

	return nil
}