diff options
Diffstat (limited to 'src/go/plugin/go.d/modules/mongodb/collect_replsetgetstatus.go')
-rw-r--r-- | src/go/plugin/go.d/modules/mongodb/collect_replsetgetstatus.go | 113 |
1 files changed, 113 insertions, 0 deletions
diff --git a/src/go/plugin/go.d/modules/mongodb/collect_replsetgetstatus.go b/src/go/plugin/go.d/modules/mongodb/collect_replsetgetstatus.go new file mode 100644 index 000000000..43d4168db --- /dev/null +++ b/src/go/plugin/go.d/modules/mongodb/collect_replsetgetstatus.go @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package mongo + +import ( + "fmt" + "strings" + + "github.com/netdata/netdata/go/plugins/plugin/go.d/agent/module" +) + +// https://www.mongodb.com/docs/manual/reference/replica-states/#replica-set-member-states +var replicaSetMemberStates = map[string]int{ + "startup": 0, + "primary": 1, + "secondary": 2, + "recovering": 3, + "startup2": 5, + "unknown": 6, + "arbiter": 7, + "down": 8, + "rollback": 9, + "removed": 10, +} + +// TODO: deal with duplicates if we collect metrics from all cluster nodes +// should we only collect ReplSetStatus (at least by default) from primary nodes? (db.runCommand( { isMaster: 1 } )) +func (m *Mongo) collectReplSetStatus(mx map[string]int64) error { + s, err := m.conn.replSetGetStatus() + if err != nil { + return fmt.Errorf("error get status of the replica set from mongo: %s", err) + } + + seen := make(map[string]documentReplSetMember) + + for _, member := range s.Members { + seen[member.Name] = member + + px := fmt.Sprintf("repl_set_member_%s_", member.Name) + + mx[px+"replication_lag"] = s.Date.Sub(member.OptimeDate).Milliseconds() + + for k, v := range replicaSetMemberStates { + mx[px+"state_"+k] = boolToInt(member.State == v) + } + + mx[px+"health_status_up"] = boolToInt(member.Health == 1) + mx[px+"health_status_down"] = boolToInt(member.Health == 0) + + if member.Self == nil { + mx[px+"uptime"] = member.Uptime + if v := member.LastHeartbeatRecv; v != nil && !v.IsZero() { + mx[px+"heartbeat_latency"] = s.Date.Sub(*v).Milliseconds() + } + if v := member.PingMs; v != nil { + mx[px+"ping_rtt"] = *v + } + } + } + + for name, member := range seen { + if !m.replSetMembers[name] { + m.replSetMembers[name] = true + m.Debugf("new replica set member '%s': adding charts", name) + m.addReplSetMemberCharts(member) + } + } + + for name := range m.replSetMembers { + if _, ok := seen[name]; !ok { + delete(m.replSetMembers, name) + m.Debugf("stale replica set member '%s': removing charts", name) + m.removeReplSetMemberCharts(name) + } + } + + return nil +} + +func (m *Mongo) addReplSetMemberCharts(v documentReplSetMember) { + charts := chartsTmplReplSetMember.Copy() + + if v.Self != nil { + _ = charts.Remove(chartTmplReplSetMemberHeartbeatLatencyTime.ID) + _ = charts.Remove(chartTmplReplSetMemberPingRTTTime.ID) + _ = charts.Remove(chartTmplReplSetMemberUptime.ID) + } + + for _, chart := range *charts { + chart.ID = fmt.Sprintf(chart.ID, v.Name) + chart.Labels = []module.Label{ + {Key: "repl_set_member", Value: v.Name}, + } + for _, dim := range chart.Dims { + dim.ID = fmt.Sprintf(dim.ID, v.Name) + } + } + + if err := m.Charts().Add(*charts...); err != nil { + m.Warning(err) + } +} + +func (m *Mongo) removeReplSetMemberCharts(name string) { + px := fmt.Sprintf("%s%s_", chartPxReplSetMember, name) + + for _, chart := range *m.Charts() { + if strings.HasPrefix(chart.ID, px) { + chart.MarkRemove() + chart.MarkNotCreated() + } + } +} |