github.com/netdata/go.d.plugin@v0.58.1/modules/mongodb/collect_replsetgetstatus.go (about)

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