master
go 114 lines 2.96 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package mongo
4
5 import (
6 "fmt"
7 "strings"
8
9 "github.com/netdata/netdata/go/plugins/plugin/framework/collectorapi"
10 "github.com/netdata/netdata/go/plugins/plugin/go.d/pkg/oldmetrix"
11 )
12
13 // https://www.mongodb.com/docs/manual/reference/replica-states/#replica-set-member-states
14 var replicaSetMemberStates = map[string]int{
15 "startup": 0,
16 "primary": 1,
17 "secondary": 2,
18 "recovering": 3,
19 "startup2": 5,
20 "unknown": 6,
21 "arbiter": 7,
22 "down": 8,
23 "rollback": 9,
24 "removed": 10,
25 }
26
27 // TODO: deal with duplicates if we collect metrics from all cluster nodes
28 // should we only collect ReplSetStatus (at least by default) from primary nodes? (db.runCommand( { isMaster: 1 } ))
29 func (c *Collector) collectReplSetStatus(mx map[string]int64) error {
30 s, err := c.conn.replSetGetStatus()
31 if err != nil {
32 return fmt.Errorf("error get status of the replica set from mongo: %s", err)
33 }
34
35 seen := make(map[string]documentReplSetMember)
36
37 for _, member := range s.Members {
38 seen[member.Name] = member
39
40 px := fmt.Sprintf("repl_set_member_%s_", member.Name)
41
42 mx[px+"replication_lag"] = s.Date.Sub(member.OptimeDate).Milliseconds()
43
44 for k, v := range replicaSetMemberStates {
45 mx[px+"state_"+k] = oldmetrix.Bool(member.State == v)
46 }
47
48 mx[px+"health_status_up"] = oldmetrix.Bool(member.Health == 1)
49 mx[px+"health_status_down"] = oldmetrix.Bool(member.Health == 0)
50
51 if member.Self == nil {
52 mx[px+"uptime"] = member.Uptime
53 if v := member.LastHeartbeatRecv; v != nil && !v.IsZero() {
54 mx[px+"heartbeat_latency"] = s.Date.Sub(*v).Milliseconds()
55 }
56 if v := member.PingMs; v != nil {
57 mx[px+"ping_rtt"] = *v
58 }
59 }
60 }
61
62 for name, member := range seen {
63 if !c.replSetMembers[name] {
64 c.replSetMembers[name] = true
65 c.Debugf("new replica set member '%s': adding charts", name)
66 c.addReplSetMemberCharts(member)
67 }
68 }
69
70 for name := range c.replSetMembers {
71 if _, ok := seen[name]; !ok {
72 delete(c.replSetMembers, name)
73 c.Debugf("stale replica set member '%s': removing charts", name)
74 c.removeReplSetMemberCharts(name)
75 }
76 }
77
78 return nil
79 }
80
81 func (c *Collector) addReplSetMemberCharts(v documentReplSetMember) {
82 charts := chartsTmplReplSetMember.Copy()
83
84 if v.Self != nil {
85 _ = charts.Remove(chartTmplReplSetMemberHeartbeatLatencyTime.ID)
86 _ = charts.Remove(chartTmplReplSetMemberPingRTTTime.ID)
87 _ = charts.Remove(chartTmplReplSetMemberUptime.ID)
88 }
89
90 for _, chart := range *charts {
91 chart.ID = fmt.Sprintf(chart.ID, v.Name)
92 chart.Labels = []collectorapi.Label{
93 {Key: "repl_set_member", Value: v.Name},
94 }
95 for _, dim := range chart.Dims {
96 dim.ID = fmt.Sprintf(dim.ID, v.Name)
97 }
98 }
99
100 if err := c.Charts().Add(*charts...); err != nil {
101 c.Warning(err)
102 }
103 }
104
105 func (c *Collector) removeReplSetMemberCharts(name string) {
106 px := fmt.Sprintf("%s%s_", chartPxReplSetMember, name)
107
108 for _, chart := range *c.Charts() {
109 if strings.HasPrefix(chart.ID, px) {
110 chart.MarkRemove()
111 chart.MarkNotCreated()
112 }
113 }
114 }