forked from free/sql_exporter
/
exporter.go
138 lines (121 loc) · 3.4 KB
/
exporter.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
package database_exporter
import (
"context"
"fmt"
"sync"
"github.com/Corundex/database_exporter/libs/config"
"github.com/golang/protobuf/proto"
"github.com/prometheus/client_golang/prometheus"
dto "github.com/prometheus/client_model/go"
)
// Exporter is a prometheus.Gatherer that gathers SQL metrics from targets and merges them with the default registry.
type Exporter interface {
prometheus.Gatherer
// WithContext returns a (single use) copy of the Exporter, which will use the provided context for Gather() calls.
WithContext(context.Context) Exporter
// Config returns the Exporter's underlying Config object.
Config() *config.Config
}
type exporter struct {
config *config.Config
targets []Target
ctx context.Context
}
// NewExporter returns a new Exporter with the provided config.
func NewExporter(configFile string) (Exporter, error) {
c, err := config.Load(configFile)
if err != nil {
return nil, err
}
var targets []Target
if c.Target != nil {
target, err := NewTarget("", "", string(c.Target.DSN), c.Target.Collectors(), nil, c.Globals)
if err != nil {
return nil, err
}
targets = []Target{target}
} else {
targets = make([]Target, 0, len(c.Jobs)*3)
for _, jc := range c.Jobs {
job, err := NewJob(jc, c.Globals)
if err != nil {
return nil, err
}
targets = append(targets, job.Targets()...)
}
}
return &exporter{
config: c,
targets: targets,
ctx: context.Background(),
}, nil
}
func (e *exporter) WithContext(ctx context.Context) Exporter {
return &exporter{
config: e.config,
targets: e.targets,
ctx: ctx,
}
}
// Gather implements prometheus.Gatherer.
func (e *exporter) Gather() ([]*dto.MetricFamily, error) {
var (
metricChan = make(chan Metric, capMetricChan)
errs prometheus.MultiError
)
var wg sync.WaitGroup
wg.Add(len(e.targets))
for _, t := range e.targets {
go func(target Target) {
defer wg.Done()
target.Collect(e.ctx, metricChan)
}(t)
}
// Wait for all collectors to complete, then close the channel.
go func() {
wg.Wait()
close(metricChan)
}()
// Drain metricChan in case of premature return.
defer func() {
for range metricChan {
}
}()
// Gather.
dtoMetricFamilies := make(map[string]*dto.MetricFamily, 10)
for metric := range metricChan {
dtoMetric := &dto.Metric{}
if err := metric.Write(dtoMetric); err != nil {
errs = append(errs, err)
continue
}
metricDesc := metric.Desc()
dtoMetricFamily, ok := dtoMetricFamilies[metricDesc.Name()]
if !ok {
dtoMetricFamily = &dto.MetricFamily{}
dtoMetricFamily.Name = proto.String(metricDesc.Name())
dtoMetricFamily.Help = proto.String(metricDesc.Help())
switch {
case dtoMetric.Gauge != nil:
dtoMetricFamily.Type = dto.MetricType_GAUGE.Enum()
case dtoMetric.Counter != nil:
dtoMetricFamily.Type = dto.MetricType_COUNTER.Enum()
default:
errs = append(errs, fmt.Errorf("don't know how to handle metric %v", dtoMetric))
continue
}
dtoMetricFamilies[metricDesc.Name()] = dtoMetricFamily
}
dtoMetricFamily.Metric = append(dtoMetricFamily.Metric, dtoMetric)
}
// No need to sort metric families, prometheus.Gatherers will do that for us when merging.
result := make([]*dto.MetricFamily, 0, len(dtoMetricFamilies))
for _, mf := range dtoMetricFamilies {
result = append(result, mf)
}
return result, errs
}
// Config implements Exporter.
func (e *exporter) Config() *config.Config {
return e.config
}