...
1
2
3
4
5
6
7
8
9
10
11
12
13
14 package config
15
16 import (
17 "crypto/md5"
18 "encoding/binary"
19 "sync"
20
21 "github.com/go-kit/log"
22 "github.com/go-kit/log/level"
23 "github.com/prometheus/client_golang/prometheus"
24 )
25
26
27
28 type Coordinator struct {
29 configFilePath string
30 logger log.Logger
31
32
33 mutex sync.Mutex
34 config *Config
35 subscribers []func(*Config) error
36
37 configHashMetric prometheus.Gauge
38 configSuccessMetric prometheus.Gauge
39 configSuccessTimeMetric prometheus.Gauge
40 }
41
42
43
44
45 func NewCoordinator(configFilePath string, r prometheus.Registerer, l log.Logger) *Coordinator {
46 c := &Coordinator{
47 configFilePath: configFilePath,
48 logger: l,
49 }
50
51 c.registerMetrics(r)
52
53 return c
54 }
55
56 func (c *Coordinator) registerMetrics(r prometheus.Registerer) {
57 configHash := prometheus.NewGauge(prometheus.GaugeOpts{
58 Name: "alertmanager_config_hash",
59 Help: "Hash of the currently loaded alertmanager configuration.",
60 })
61 configSuccess := prometheus.NewGauge(prometheus.GaugeOpts{
62 Name: "alertmanager_config_last_reload_successful",
63 Help: "Whether the last configuration reload attempt was successful.",
64 })
65 configSuccessTime := prometheus.NewGauge(prometheus.GaugeOpts{
66 Name: "alertmanager_config_last_reload_success_timestamp_seconds",
67 Help: "Timestamp of the last successful configuration reload.",
68 })
69
70 r.MustRegister(configHash, configSuccess, configSuccessTime)
71
72 c.configHashMetric = configHash
73 c.configSuccessMetric = configSuccess
74 c.configSuccessTimeMetric = configSuccessTime
75 }
76
77
78 func (c *Coordinator) Subscribe(ss ...func(*Config) error) {
79 c.mutex.Lock()
80 defer c.mutex.Unlock()
81
82 c.subscribers = append(c.subscribers, ss...)
83 }
84
85 func (c *Coordinator) notifySubscribers() error {
86 for _, s := range c.subscribers {
87 if err := s(c.config); err != nil {
88 return err
89 }
90 }
91
92 return nil
93 }
94
95
96 func (c *Coordinator) loadFromFile() error {
97 conf, err := LoadFile(c.configFilePath)
98 if err != nil {
99 return err
100 }
101
102 c.config = conf
103
104 return nil
105 }
106
107
108
109 func (c *Coordinator) Reload() error {
110 c.mutex.Lock()
111 defer c.mutex.Unlock()
112
113 level.Info(c.logger).Log(
114 "msg", "Loading configuration file",
115 "file", c.configFilePath,
116 )
117 if err := c.loadFromFile(); err != nil {
118 level.Error(c.logger).Log(
119 "msg", "Loading configuration file failed",
120 "file", c.configFilePath,
121 "err", err,
122 )
123 c.configSuccessMetric.Set(0)
124 return err
125 }
126 level.Info(c.logger).Log(
127 "msg", "Completed loading of configuration file",
128 "file", c.configFilePath,
129 )
130
131 if err := c.notifySubscribers(); err != nil {
132 c.logger.Log(
133 "msg", "one or more config change subscribers failed to apply new config",
134 "file", c.configFilePath,
135 "err", err,
136 )
137 c.configSuccessMetric.Set(0)
138 return err
139 }
140
141 c.configSuccessMetric.Set(1)
142 c.configSuccessTimeMetric.SetToCurrentTime()
143 hash := md5HashAsMetricValue([]byte(c.config.original))
144 c.configHashMetric.Set(hash)
145
146 return nil
147 }
148
149 func md5HashAsMetricValue(data []byte) float64 {
150 sum := md5.Sum(data)
151
152 smallSum := sum[0:6]
153 bytes := make([]byte, 8)
154 copy(bytes, smallSum)
155 return float64(binary.LittleEndian.Uint64(bytes))
156 }
157
View as plain text