• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

oliver006 / redis_exporter / 17172001870

23 Aug 2025 05:58AM UTC coverage: 84.921% (-0.9%) from 85.87%
17172001870

Pull #1028

github

web-flow
Merge 891f7f01e into 7632b7b20
Pull Request #1028: sirupsen/log --> log/slog

121 of 249 new or added lines in 18 files covered. (48.59%)

6 existing lines in 1 file now uncovered.

2568 of 3024 relevant lines covered (84.92%)

13254.26 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.53
/exporter/sentinels.go
1
package exporter
2

3
import (
4
        "log/slog"
5
        "regexp"
6
        "strconv"
7
        "strings"
8

9
        "github.com/gomodule/redigo/redis"
10
        "github.com/prometheus/client_golang/prometheus"
11
)
12

13
func (e *Exporter) handleMetricsSentinel(ch chan<- prometheus.Metric, fieldKey string, fieldValue string) {
12✔
14
        switch fieldKey {
12✔
15
        case
16
                "sentinel_masters",
17
                "sentinel_tilt",
18
                "sentinel_running_scripts",
19
                "sentinel_scripts_queue_length",
20
                "sentinel_simulate_failure_flags":
10✔
21
                val, _ := strconv.Atoi(fieldValue)
10✔
22
                e.registerConstMetricGauge(ch, fieldKey, float64(val))
10✔
23
                return
10✔
24
        }
25

26
        if masterName, masterStatus, masterAddress, masterSlaves, masterSentinels, ok := parseSentinelMasterString(fieldKey, fieldValue); ok {
4✔
27
                masterStatusNum := 0.0
2✔
28
                if masterStatus == "ok" {
4✔
29
                        masterStatusNum = 1
2✔
30
                }
2✔
31
                e.registerConstMetricGauge(ch, "sentinel_master_status", masterStatusNum, masterName, masterAddress, masterStatus)
2✔
32
                e.registerConstMetricGauge(ch, "sentinel_master_slaves", masterSlaves, masterName, masterAddress)
2✔
33
                e.registerConstMetricGauge(ch, "sentinel_master_sentinels", masterSentinels, masterName, masterAddress)
2✔
34
                return
2✔
35
        }
36
}
37

38
func (e *Exporter) extractSentinelMetrics(ch chan<- prometheus.Metric, c redis.Conn) {
3✔
39
        masterDetails, err := redis.Values(doRedisCmd(c, "SENTINEL", "MASTERS"))
3✔
40
        if err != nil {
4✔
41
                slog.Debug("Error getting sentinel master details", "error", err)
1✔
42
                return
1✔
43
        }
1✔
44

45
        slog.Debug("Sentinel master details", "masterDetails", masterDetails)
2✔
46

2✔
47
        for _, masterDetail := range masterDetails {
4✔
48
                masterDetailMap, err := redis.StringMap(masterDetail, nil)
2✔
49
                if err != nil {
2✔
NEW
50
                        slog.Debug("Error getting masterDetailmap from masterDetail", "masterDetail", masterDetail, "error", err)
×
51
                        continue
×
52
                }
53

54
                masterName, ok := masterDetailMap["name"]
2✔
55
                if !ok {
2✔
56
                        continue
×
57
                }
58

59
                masterIp, ok := masterDetailMap["ip"]
2✔
60
                if !ok {
2✔
61
                        continue
×
62
                }
63

64
                masterPort, ok := masterDetailMap["port"]
2✔
65
                if !ok {
2✔
66
                        continue
×
67
                }
68
                masterAddr := masterIp + ":" + masterPort
2✔
69

2✔
70
                masterCkquorumMsg, err := redis.String(doRedisCmd(c, "SENTINEL", "CKQUORUM", masterName))
2✔
71
                slog.Debug("Sentinel ckquorum status for master", "masterName", masterName, "msg", masterCkquorumMsg, "error", err)
2✔
72
                masterCkquorumStatus := 1
2✔
73
                if err != nil {
4✔
74
                        masterCkquorumStatus = 0
2✔
75
                        masterCkquorumMsg = err.Error()
2✔
76
                }
2✔
77
                e.registerConstMetricGauge(ch, "sentinel_master_ckquorum_status", float64(masterCkquorumStatus), masterName, masterCkquorumMsg)
2✔
78

2✔
79
                masterCkquorum, _ := strconv.ParseFloat(masterDetailMap["quorum"], 64)
2✔
80
                masterFailoverTimeout, _ := strconv.ParseFloat(masterDetailMap["failover-timeout"], 64)
2✔
81
                masterParallelSyncs, _ := strconv.ParseFloat(masterDetailMap["parallel-syncs"], 64)
2✔
82
                masterDownAfterMs, _ := strconv.ParseFloat(masterDetailMap["down-after-milliseconds"], 64)
2✔
83

2✔
84
                e.registerConstMetricGauge(ch, "sentinel_master_setting_ckquorum", masterCkquorum, masterName, masterAddr)
2✔
85
                e.registerConstMetricGauge(ch, "sentinel_master_setting_failover_timeout", masterFailoverTimeout, masterName, masterAddr)
2✔
86
                e.registerConstMetricGauge(ch, "sentinel_master_setting_parallel_syncs", masterParallelSyncs, masterName, masterAddr)
2✔
87
                e.registerConstMetricGauge(ch, "sentinel_master_setting_down_after_milliseconds", masterDownAfterMs, masterName, masterAddr)
2✔
88

2✔
89
                sentinelDetails, _ := redis.Values(doRedisCmd(c, "SENTINEL", "SENTINELS", masterName))
2✔
90
                slog.Debug("Sentinel details for master", "masterName", masterName, "sentinelDetails", sentinelDetails)
2✔
91
                e.processSentinelSentinels(ch, sentinelDetails, masterName, masterAddr)
2✔
92

2✔
93
                slaveDetails, _ := redis.Values(doRedisCmd(c, "SENTINEL", "SLAVES", masterName))
2✔
94
                slog.Debug("Slave details for master", "masterName", masterName, "slaveDetails", slaveDetails)
2✔
95
                e.processSentinelSlaves(ch, slaveDetails, masterName, masterAddr)
2✔
96
        }
97
}
98

99
func (e *Exporter) processSentinelSentinels(ch chan<- prometheus.Metric, sentinelDetails []interface{}, labels ...string) {
7✔
100

7✔
101
        // If we are here then this master is in ok state
7✔
102
        masterOkSentinels := 1
7✔
103

7✔
104
        for _, sentinelDetail := range sentinelDetails {
16✔
105
                sentinelDetailMap, err := redis.StringMap(sentinelDetail, nil)
9✔
106
                if err != nil {
11✔
107
                        slog.Debug("Error getting sentinelDetailMap from sentinelDetail", "sentinelDetail", sentinelDetail, "error", err)
2✔
108
                        continue
2✔
109
                }
110

111
                sentinelFlags, ok := sentinelDetailMap["flags"]
7✔
112
                if !ok {
8✔
113
                        continue
1✔
114
                }
115
                if strings.Contains(sentinelFlags, "o_down") {
7✔
116
                        continue
1✔
117
                }
118
                if strings.Contains(sentinelFlags, "s_down") {
7✔
119
                        continue
2✔
120
                }
121
                masterOkSentinels = masterOkSentinels + 1
3✔
122
        }
123
        e.registerConstMetricGauge(ch, "sentinel_master_ok_sentinels", float64(masterOkSentinels), labels...)
7✔
124
}
125

126
func (e *Exporter) processSentinelSlaves(ch chan<- prometheus.Metric, slaveDetails []interface{}, labels ...string) {
7✔
127
        masterOkSlaves := 0
7✔
128
        for _, slaveDetail := range slaveDetails {
18✔
129
                slaveDetailMap, err := redis.StringMap(slaveDetail, nil)
11✔
130
                if err != nil {
12✔
131
                        slog.Debug("Error getting slavedetailMap from slaveDetail", "slaveDetail", slaveDetail, "error", err)
1✔
132
                        continue
1✔
133
                }
134

135
                slaveFlags, ok := slaveDetailMap["flags"]
10✔
136
                if !ok {
11✔
137
                        continue
1✔
138
                }
139
                if strings.Contains(slaveFlags, "o_down") {
10✔
140
                        continue
1✔
141
                }
142
                if strings.Contains(slaveFlags, "s_down") {
10✔
143
                        continue
2✔
144
                }
145
                masterOkSlaves = masterOkSlaves + 1
6✔
146
        }
147
        e.registerConstMetricGauge(ch, "sentinel_master_ok_slaves", float64(masterOkSlaves), labels...)
7✔
148
}
149

150
/*
151
valid examples:
152

153
        master0:name=user03,status=sdown,address=192.169.2.52:6381,slaves=1,sentinels=5
154
        master1:name=user02,status=ok,address=192.169.2.54:6380,slaves=1,sentinels=5
155
*/
156
func parseSentinelMasterString(master string, masterInfo string) (masterName string, masterStatus string, masterAddr string, masterSlaves float64, masterSentinels float64, ok bool) {
8✔
157
        ok = false
8✔
158
        if matched, _ := regexp.MatchString(`^master\d+`, master); !matched {
10✔
159
                return
2✔
160
        }
2✔
161
        matchedMasterInfo := make(map[string]string)
6✔
162
        for _, kvPart := range strings.Split(masterInfo, ",") {
30✔
163
                x := strings.Split(kvPart, "=")
24✔
164
                if len(x) != 2 {
24✔
NEW
165
                        slog.Error("Invalid format for sentinel's master string", "kvPart", kvPart)
×
166
                        continue
×
167
                }
168
                matchedMasterInfo[x[0]] = x[1]
24✔
169
        }
170

171
        masterName = matchedMasterInfo["name"]
6✔
172
        masterStatus = matchedMasterInfo["status"]
6✔
173
        masterAddr = matchedMasterInfo["address"]
6✔
174
        masterSlaves, err := strconv.ParseFloat(matchedMasterInfo["slaves"], 64)
6✔
175
        if err != nil {
7✔
176
                slog.Debug("Failed to parse slaves value", "slaves", matchedMasterInfo["slaves"], "error", err)
1✔
177
                return
1✔
178
        }
1✔
179
        masterSentinels, err = strconv.ParseFloat(matchedMasterInfo["sentinels"], 64)
5✔
180
        if err != nil {
6✔
181
                slog.Debug("Failed to parse sentinels value", "sentinels", matchedMasterInfo["sentinels"], "error", err)
1✔
182
                return
1✔
183
        }
1✔
184
        ok = true
4✔
185

4✔
186
        return
4✔
187
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc