-
Notifications
You must be signed in to change notification settings - Fork 13
/
Copy pathstorage_dogstatsd.go
140 lines (111 loc) · 3.63 KB
/
storage_dogstatsd.go
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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
package main
import (
"context"
"fmt"
"log"
"sync"
"github.com/DataDog/datadog-go/statsd"
)
// DogstatsdConfig describes the YAML-provided configuration for a Datadog
// DogstatsD storage backend
type DogstatsdConfig struct {
Host string `yaml:"host"`
Port int `yaml:"port"`
Namespace string `yaml:"metric-namespace"`
}
// DogstatsdStorage holds the configuration for a DogstatsD storage backend
type DogstatsdStorage struct {
DogstatsdConn *statsd.Client
Namespace string
}
// StartStorageEngine creates a goroutine loop to receive metrics and send
// them off to dogstatsd
func (d DogstatsdStorage) StartStorageEngine(ctx context.Context, wg *sync.WaitGroup) (chan<- Metric, chan<- Event) {
// Datadog storage supports both metrics and events, so we'll initialize both channels
metricChan := make(chan Metric, 10)
eventChan := make(chan Event, 10)
go d.processMetricsAndEvents(ctx, wg, metricChan, eventChan)
return metricChan, eventChan
}
func (d DogstatsdStorage) processMetricsAndEvents(ctx context.Context, wg *sync.WaitGroup, mchan <-chan Metric, echan <-chan Event) {
wg.Add(1)
defer wg.Done()
for {
select {
case m := <-mchan:
err := d.sendMetric(m)
if err != nil {
log.Println(err)
}
case e := <-echan:
err := d.sendEvent(e)
if err != nil {
log.Println(err)
}
case <-ctx.Done():
log.Println("Cancellation request recieved. Cancelling metrics processor.")
return
}
}
}
// sendMetric sends a metric value to dogstatsd
func (d DogstatsdStorage) sendMetric(m Metric) error {
var metricName string
if d.Namespace == "" {
metricName = fmt.Sprintf("crabby.%v.%v", m.Job, m.Timing)
} else {
metricName = fmt.Sprintf("%v.%v.%v", d.Namespace, m.Job, m.Timing)
}
dogTags := makeDogstatsdTagsFromTagsMap(m.Tags)
err := d.DogstatsdConn.TimeInMilliseconds(metricName, m.Value, dogTags, 1)
if err != nil {
log.Printf("Could not send metric %v: %v\n", metricName, err)
return err
}
return nil
}
// sendEvent sends an event (as a service check) to the Datadog API endpoint
func (d DogstatsdStorage) sendEvent(e Event) error {
var eventName string
if d.Namespace == "" {
eventName = fmt.Sprintf("crabby.%v", e.Name)
} else {
eventName = fmt.Sprintf("%v.%v", d.Namespace, e.Name)
}
// While Crabby calls this an "event", it's really a "service check" in
// Datadog parlance. Datadog does have the concept of "events" but it's
// more difficult to set up monitoring for events than it is service checks.
// With service checks, we can send the status with every check. We just
// set the Status field to indicate whether things are OK (response code 1xx/2xx/3xx)
// or are failing (response code 4xx/5xx)
sc := &statsd.ServiceCheck{
Name: eventName,
Message: fmt.Sprintf("%v is returning a HTTP status code of %v", e.Name, e.ServerStatus),
}
if (e.ServerStatus < 400) && (e.ServerStatus > 0) {
sc.Status = statsd.Ok
} else {
sc.Status = statsd.Critical
}
sc.Tags = makeDogstatsdTagsFromTagsMap(e.Tags)
err := d.DogstatsdConn.ServiceCheck(sc)
return err
}
// NewDogstatsdStorage sets up a new Dogstatsd storage backend
func NewDogstatsdStorage(c ServiceConfig) DogstatsdStorage {
var err error
d := DogstatsdStorage{}
d.Namespace = c.Storage.Dogstatsd.Namespace
d.DogstatsdConn, err = statsd.New(fmt.Sprint(c.Storage.Dogstatsd.Host, ":", c.Storage.Dogstatsd.Port))
if err != nil {
log.Println("Warning: could not create dogstatsd connection", err)
}
return d
}
func makeDogstatsdTagsFromTagsMap(tags map[string]string) []string {
var dogTags []string
for k, v := range tags {
dogTags = append(dogTags, fmt.Sprintf("%v=%v", k, v))
}
return dogTags
}