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 }