This repository has been archived by the owner on Mar 8, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 140
/
collector.go
137 lines (115 loc) · 3.58 KB
/
collector.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
package main
import (
"errors"
"github.com/Technofy/cloudwatch_exporter/config"
"github.com/prometheus/client_golang/prometheus"
"time"
)
var (
templates = map[string]*cwCollectorTemplate{}
)
type cwMetric struct {
Desc *prometheus.Desc
ValType prometheus.ValueType
ConfMetric *config.Metric
LabelNames []string
LabelValues []string
}
type cwCollectorTemplate struct {
Metrics []cwMetric
Task *config.Task
}
type cwCollector struct {
Region string
Target string
ScrapeTime prometheus.Gauge
ErroneousRequests prometheus.Counter
Template *cwCollectorTemplate
}
// generateTemplates creates pre-generated metrics descriptions so that only the metrics are created from them during a scrape.
func generateTemplates(cfg *config.Settings) {
for t := range cfg.Tasks {
var template = new(cwCollectorTemplate)
//Save the task it belongs to
template.Task = &cfg.Tasks[t]
//Pre-allocate at least a few metrics
template.Metrics = make([]cwMetric, 0, len(cfg.Tasks[t].Metrics))
for m := range cfg.Tasks[t].Metrics {
metric := &cfg.Tasks[t].Metrics[m]
labels := make([]string, len(metric.Dimensions))
for i := range metric.Dimensions {
labels[i] = toSnakeCase(metric.Dimensions[i])
}
labels = append(labels, "task")
for s := range metric.Statistics {
template.Metrics = append(template.Metrics, cwMetric{
Desc: prometheus.NewDesc(
safeName(toSnakeCase(metric.Namespace)+"_"+toSnakeCase(metric.Name)+"_"+toSnakeCase(metric.Statistics[s])),
metric.Name,
labels,
nil),
ValType: prometheus.GaugeValue,
ConfMetric: metric,
LabelNames: labels,
})
}
for s := range metric.ExtendedStatistics {
template.Metrics = append(template.Metrics, cwMetric{
Desc: prometheus.NewDesc(
safeName(toSnakeCase(metric.Namespace)+"_"+toSnakeCase(metric.Name)+"_"+toSnakeCase(metric.ExtendedStatistics[s])),
metric.Name,
labels,
nil),
ValType: prometheus.GaugeValue,
ConfMetric: metric,
LabelNames: labels,
})
}
}
templates[cfg.Tasks[t].Name] = template
}
}
// NewCwCollector creates a new instance of a CwCollector for a specific task
// The newly created instance will reference its parent template so that metric descriptions are not recreated on every call.
// It returns either a pointer to a new instance of cwCollector or an error.
func NewCwCollector(target string, taskName string, region string) (*cwCollector, error) {
// Check if task exists
task, err := settings.GetTask(taskName)
if err != nil {
return nil, err
}
if region == "" {
if task.DefaultRegion == "" {
return nil, errors.New("No region or default region set requested task")
} else {
region = task.DefaultRegion
}
}
return &cwCollector{
Region: region,
Target: target,
ScrapeTime: prometheus.NewGauge(prometheus.GaugeOpts{
Name: "cloudwatch_exporter_scrape_duration_seconds",
Help: "Time this CloudWatch scrape took, in seconds.",
}),
ErroneousRequests: prometheus.NewGauge(prometheus.GaugeOpts{
Name: "cloudwatch_exporter_erroneous_requests",
Help: "The number of erroneous request made by this scrape.",
}),
Template: templates[taskName],
}, nil
}
func (c *cwCollector) Collect(ch chan<- prometheus.Metric) {
now := time.Now()
scrape(c, ch)
c.ScrapeTime.Set(time.Since(now).Seconds())
ch <- c.ScrapeTime
ch <- c.ErroneousRequests
}
func (c *cwCollector) Describe(ch chan<- *prometheus.Desc) {
ch <- c.ScrapeTime.Desc()
ch <- c.ErroneousRequests.Desc()
for m := range c.Template.Metrics {
ch <- c.Template.Metrics[m].Desc
}
}