github.com/netdata/go.d.plugin@v0.58.1/modules/vernemq/collect.go (about)

     1  // SPDX-License-Identifier: GPL-3.0-or-later
     2  
     3  package vernemq
     4  
     5  import (
     6  	"errors"
     7  	"strings"
     8  
     9  	"github.com/netdata/go.d.plugin/pkg/prometheus"
    10  	"github.com/netdata/go.d.plugin/pkg/stm"
    11  )
    12  
    13  func isValidVerneMQMetrics(pms prometheus.Series) bool {
    14  	return pms.FindByName(metricPUBLISHError).Len() > 0 && pms.FindByName(metricRouterSubscriptions).Len() > 0
    15  }
    16  
    17  func (v *VerneMQ) collect() (map[string]int64, error) {
    18  	pms, err := v.prom.ScrapeSeries()
    19  	if err != nil {
    20  		return nil, err
    21  	}
    22  
    23  	if !isValidVerneMQMetrics(pms) {
    24  		return nil, errors.New("returned metrics aren't VerneMQ metrics")
    25  	}
    26  
    27  	mx := v.collectVerneMQ(pms)
    28  
    29  	return stm.ToMap(mx), nil
    30  }
    31  
    32  func (v *VerneMQ) collectVerneMQ(pms prometheus.Series) map[string]float64 {
    33  	mx := make(map[string]float64)
    34  	collectSockets(mx, pms)
    35  	collectQueues(mx, pms)
    36  	collectSubscriptions(mx, pms)
    37  	v.collectErlangVM(mx, pms)
    38  	collectBandwidth(mx, pms)
    39  	collectRetain(mx, pms)
    40  	collectCluster(mx, pms)
    41  	collectUptime(mx, pms)
    42  
    43  	v.collectAUTH(mx, pms)
    44  	v.collectCONNECT(mx, pms)
    45  	v.collectDISCONNECT(mx, pms)
    46  	v.collectSUBSCRIBE(mx, pms)
    47  	v.collectUNSUBSCRIBE(mx, pms)
    48  	v.collectPUBLISH(mx, pms)
    49  	v.collectPING(mx, pms)
    50  	v.collectMQTTInvalidMsgSize(mx, pms)
    51  	return mx
    52  }
    53  
    54  func (v *VerneMQ) collectCONNECT(mx map[string]float64, pms prometheus.Series) {
    55  	pms = pms.FindByNames(
    56  		metricCONNECTReceived,
    57  		metricCONNACKSent,
    58  	)
    59  	v.collectMQTT(mx, pms)
    60  }
    61  
    62  func (v *VerneMQ) collectDISCONNECT(mx map[string]float64, pms prometheus.Series) {
    63  	pms = pms.FindByNames(
    64  		metricDISCONNECTReceived,
    65  		metricDISCONNECTSent,
    66  	)
    67  	v.collectMQTT(mx, pms)
    68  }
    69  
    70  func (v *VerneMQ) collectPUBLISH(mx map[string]float64, pms prometheus.Series) {
    71  	pms = pms.FindByNames(
    72  		metricPUBACKReceived,
    73  		metricPUBACKSent,
    74  		metricPUBACKInvalid,
    75  
    76  		metricPUBCOMPReceived,
    77  		metricPUBCOMPSent,
    78  		metricPUNCOMPInvalid,
    79  
    80  		metricPUBSLISHReceived,
    81  		metricPUBSLIHSent,
    82  		metricPUBLISHError,
    83  		metricPUBLISHAuthError,
    84  
    85  		metricPUBRECReceived,
    86  		metricPUBRECSent,
    87  		metricPUBRECInvalid,
    88  
    89  		metricPUBRELReceived,
    90  		metricPUBRELSent,
    91  	)
    92  	v.collectMQTT(mx, pms)
    93  }
    94  
    95  func (v *VerneMQ) collectSUBSCRIBE(mx map[string]float64, pms prometheus.Series) {
    96  	pms = pms.FindByNames(
    97  		metricSUBSCRIBEReceived,
    98  		metricSUBACKSent,
    99  		metricSUBSCRIBEError,
   100  		metricSUBSCRIBEAuthError,
   101  	)
   102  	v.collectMQTT(mx, pms)
   103  }
   104  
   105  func (v *VerneMQ) collectUNSUBSCRIBE(mx map[string]float64, pms prometheus.Series) {
   106  	pms = pms.FindByNames(
   107  		metricUNSUBSCRIBEReceived,
   108  		metricUNSUBACKSent,
   109  		metricUNSUBSCRIBEError,
   110  	)
   111  	v.collectMQTT(mx, pms)
   112  }
   113  
   114  func (v *VerneMQ) collectPING(mx map[string]float64, pms prometheus.Series) {
   115  	pms = pms.FindByNames(
   116  		metricPINGREQReceived,
   117  		metricPINGRESPSent,
   118  	)
   119  	v.collectMQTT(mx, pms)
   120  }
   121  
   122  func (v *VerneMQ) collectAUTH(mx map[string]float64, pms prometheus.Series) {
   123  	pms = pms.FindByNames(
   124  		metricAUTHReceived,
   125  		metricAUTHSent,
   126  	)
   127  	v.collectMQTT(mx, pms)
   128  }
   129  
   130  func (v *VerneMQ) collectMQTTInvalidMsgSize(mx map[string]float64, pms prometheus.Series) {
   131  	pms = pms.FindByName(metricMQTTInvalidMsgSizeError)
   132  	v.collectMQTT(mx, pms)
   133  }
   134  
   135  func collectSockets(mx map[string]float64, pms prometheus.Series) {
   136  	pms = pms.FindByNames(
   137  		metricSocketClose,
   138  		metricSocketCloseTimeout,
   139  		metricSocketError,
   140  		metricSocketOpen,
   141  		metricClientKeepaliveExpired,
   142  	)
   143  	collectNonMQTT(mx, pms)
   144  	mx["open_sockets"] = mx[metricSocketOpen] - mx[metricSocketClose]
   145  }
   146  
   147  func collectQueues(mx map[string]float64, pms prometheus.Series) {
   148  	pms = pms.FindByNames(
   149  		metricQueueInitializedFromStorage,
   150  		metricQueueMessageDrop,
   151  		metricQueueMessageExpired,
   152  		metricQueueMessageIn,
   153  		metricQueueMessageOut,
   154  		metricQueueMessageUnhandled,
   155  		metricQueueProcesses,
   156  		metricQueueSetup,
   157  		metricQueueTeardown,
   158  	)
   159  	collectNonMQTT(mx, pms)
   160  }
   161  
   162  func collectSubscriptions(mx map[string]float64, pms prometheus.Series) {
   163  	pms = pms.FindByNames(
   164  		metricRouterMatchesLocal,
   165  		metricRouterMatchesRemote,
   166  		metricRouterMemory,
   167  		metricRouterSubscriptions,
   168  	)
   169  	collectNonMQTT(mx, pms)
   170  }
   171  
   172  func (v *VerneMQ) collectErlangVM(mx map[string]float64, pms prometheus.Series) {
   173  	v.collectSchedulersUtilization(mx, pms)
   174  	pms = pms.FindByNames(
   175  		metricSystemContextSwitches,
   176  		metricSystemGCCount,
   177  		metricSystemIOIn,
   178  		metricSystemIOOut,
   179  		metricSystemProcessCount,
   180  		metricSystemReductions,
   181  		metricSystemRunQueue,
   182  		metricSystemUtilization,
   183  		metricSystemWordsReclaimedByGC,
   184  		metricVMMemoryProcesses,
   185  		metricVMMemorySystem,
   186  	)
   187  	collectNonMQTT(mx, pms)
   188  }
   189  
   190  func (v *VerneMQ) collectSchedulersUtilization(mx map[string]float64, pms prometheus.Series) {
   191  	for _, pm := range pms {
   192  		if isSchedulerUtilizationMetric(pm) {
   193  			mx[pm.Name()] += pm.Value
   194  			v.notifyNewScheduler(pm.Name())
   195  		}
   196  	}
   197  }
   198  
   199  func collectBandwidth(mx map[string]float64, pms prometheus.Series) {
   200  	pms = pms.FindByNames(
   201  		metricBytesReceived,
   202  		metricBytesSent,
   203  	)
   204  	collectNonMQTT(mx, pms)
   205  }
   206  
   207  func collectRetain(mx map[string]float64, pms prometheus.Series) {
   208  	pms = pms.FindByNames(
   209  		metricRetainMemory,
   210  		metricRetainMessages,
   211  	)
   212  	collectNonMQTT(mx, pms)
   213  }
   214  
   215  func collectCluster(mx map[string]float64, pms prometheus.Series) {
   216  	pms = pms.FindByNames(
   217  		metricClusterBytesDropped,
   218  		metricClusterBytesReceived,
   219  		metricClusterBytesSent,
   220  		metricNetSplitDetected,
   221  		metricNetSplitResolved,
   222  	)
   223  	collectNonMQTT(mx, pms)
   224  	mx["netsplit_unresolved"] = mx[metricNetSplitDetected] - mx[metricNetSplitResolved]
   225  }
   226  
   227  func collectUptime(mx map[string]float64, pms prometheus.Series) {
   228  	pms = pms.FindByName(metricSystemWallClock)
   229  	collectNonMQTT(mx, pms)
   230  }
   231  
   232  func collectNonMQTT(mx map[string]float64, pms prometheus.Series) {
   233  	for _, pm := range pms {
   234  		mx[pm.Name()] += pm.Value
   235  	}
   236  }
   237  
   238  func (v *VerneMQ) collectMQTT(mx map[string]float64, pms prometheus.Series) {
   239  	for _, pm := range pms {
   240  		if !isMQTTMetric(pm) {
   241  			continue
   242  		}
   243  		version := versionLabelValue(pm)
   244  		if version == "" {
   245  			continue
   246  		}
   247  
   248  		mx[pm.Name()] += pm.Value
   249  		mx[join(pm.Name(), "v", version)] += pm.Value
   250  
   251  		if reason := reasonCodeLabelValue(pm); reason != "" {
   252  			mx[join(pm.Name(), reason)] += pm.Value
   253  			mx[join(pm.Name(), "v", version, reason)] += pm.Value
   254  
   255  			v.notifyNewReason(pm.Name(), reason)
   256  		}
   257  	}
   258  }
   259  
   260  func isMQTTMetric(pm prometheus.SeriesSample) bool {
   261  	return strings.HasPrefix(pm.Name(), "mqtt_")
   262  }
   263  
   264  func isSchedulerUtilizationMetric(pm prometheus.SeriesSample) bool {
   265  	return strings.HasPrefix(pm.Name(), "system_utilization_scheduler_")
   266  }
   267  
   268  func reasonCodeLabelValue(pm prometheus.SeriesSample) string {
   269  	if v := pm.Labels.Get("reason_code"); v != "" {
   270  		return v
   271  	}
   272  	// "mqtt_connack_sent" v4 has return_code
   273  	return pm.Labels.Get("return_code")
   274  }
   275  
   276  func versionLabelValue(pm prometheus.SeriesSample) string {
   277  	return pm.Labels.Get("mqtt_version")
   278  }
   279  
   280  func join(a, b string, rest ...string) string {
   281  	v := a + "_" + b
   282  	switch len(rest) {
   283  	case 0:
   284  		return v
   285  	default:
   286  		return join(v, rest[0], rest[1:]...)
   287  	}
   288  }