master
go 1,190 lines 38.6 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package vernemq
4
5 import (
6 "fmt"
7 "strings"
8
9 "github.com/netdata/netdata/go/plugins/plugin/framework/collectorapi"
10 )
11
12 const (
13 prioNodeSockets = collectorapi.Priority + iota
14 prioNodeSocketEvents
15 prioNodeClientKeepaliveExpired
16 prioNodeSocketCloseTimeout
17 prioNodeSocketErrors
18
19 prioNodeQueueProcesses
20 prioNodeQueueProcessesEvents
21 prioNodeQueueProcessesOfflineStorage
22 prioNodeQueueMessages
23 prioNodeQueuedMessages
24 prioNodeQueueUndeliveredMessages
25
26 prioNodeRouterSubscriptions
27 prioNodeRouterMatchedSubscriptions
28 prioNodeRouterMemory
29
30 prioNodeAverageSchedulerUtilization
31 prioNodeSystemProcesses
32 prioNodeSystemReductions
33 prioNodeSystemContext
34 prioNodeSystemIO
35 prioNodeSystemRunQueue
36 prioNodeSystemGCCount
37 prioNodeSystemGCWordsReclaimed
38 prioNodeSystemMemoryAllocated
39
40 prioNodeTraffic
41
42 prioNodeRetainMessages
43 prioNodeRetainMemoryUsage
44
45 prioNodeClusterCommunicationTraffic
46 prioNodeClusterCommunicationDropped
47 prioNodeNetSplitUnresolved
48 prioNodeNetSplits
49
50 prioMqttPublishPackets
51 prioMqttPublishErrors
52 prioMqttPublishAuthPackets
53
54 prioMqttPubAckPackets
55 prioMqttPubAckReceivedReason
56 prioMqttPubAckSentReason
57 prioMqttPubAckUnexpectedMessages
58
59 prioMqttPubRecPackets
60 prioMqttPubRecReceivedReason
61 prioMqttPubRecSentReason
62 prioMqttPubRecUnexpectedMessages
63
64 prioMqttPubRelPackets
65 prioMqttPubRelReceivedReason
66 prioMqttPubRelSentReason
67
68 prioMqttPubCompPackets
69 prioMqttPubCompReceivedReason
70 prioMqttPubCompSentReason
71 prioMqttPubCompUnexpectedMessages
72
73 prioMqttConnectPackets
74 prioMqttConnectSentReason
75
76 prioMqttDisconnectPackets
77 prioMqttDisconnectReceivedReason
78 prioMqttDisconnectSentReason
79
80 prioMqttSubscribePackets
81 prioMqttSubscribeErrors
82 prioMqttSubscribeAuthPackets
83
84 prioMqttUnsubscribePackets
85 prioMqttUnsubscribeErrors
86
87 prioMqttAuthPackets
88 prioMqttAuthReceivedReason
89 prioMqttAuthSentReason
90
91 prioMqttPingPackets
92
93 prioNodeUptime
94 )
95
96 var nodeChartsTmpl = collectorapi.Charts{
97 nodeOpenSocketsChartTmpl.Copy(),
98 nodeSocketEventsChartTmpl.Copy(),
99 nodeSocketCloseTimeoutChartTmpl.Copy(),
100 nodeSocketErrorsChartTmpl.Copy(),
101
102 nodeQueueProcessesChartTmpl.Copy(),
103 nodeQueueProcessesEventsChartTmpl.Copy(),
104 nodeQueueProcessesOfflineStorageChartTmpl.Copy(),
105 nodeQueueMessagesChartTmpl.Copy(),
106 nodeQueuedMessagesChartTmpl.Copy(),
107 nodeQueueUndeliveredMessagesChartTmpl.Copy(),
108
109 nodeRouterSubscriptionsChartTmpl.Copy(),
110 nodeRouterMatchedSubscriptionsChartTmpl.Copy(),
111 nodeRouterMemoryChartTmpl.Copy(),
112
113 nodeAverageSchedulerUtilizationChartTmpl.Copy(),
114 nodeSystemProcessesChartTmpl.Copy(),
115 nodeSystemReductionsChartTmpl.Copy(),
116 nodeSystemContextSwitches.Copy(),
117 nodeSystemIOChartTmpl.Copy(),
118 nodeSystemRunQueueChartTmpl.Copy(),
119 nodeSystemGCCountChartTmpl.Copy(),
120 nodeSystemGCWordsReclaimedChartTmpl.Copy(),
121 nodeSystemMemoryAllocatedChartTmpl.Copy(),
122
123 nodeTrafficChartTmpl.Copy(),
124
125 nodeRetainMessagesChartsTmpl.Copy(),
126 nodeRetainMemoryUsageChartTmpl.Copy(),
127
128 nodeClusterCommunicationTrafficChartTmpl.Copy(),
129 nodeClusterCommunicationDroppedChartTmpl.Copy(),
130 nodeNetSplitUnresolvedChartTmpl.Copy(),
131 nodeNetSplitsChartTmpl.Copy(),
132
133 nodeUptimeChartTmpl.Copy(),
134 }
135
136 var nodeMqtt5ChartsTmpl = collectorapi.Charts{
137 nodeClientKeepaliveExpiredChartTmpl.Copy(),
138
139 nodeMqttPUBLISHPacketsChartTmpl.Copy(),
140 nodeMqttPUBLISHErrorsChartTmpl.Copy(),
141 nodeMqttPUBLISHAuthErrorsChartTmpl.Copy(),
142
143 nodeMqttPUBACKPacketsChartTmpl.Copy(),
144 nodeMqttPUBACKReceivedByReasonChartTmpl.Copy(),
145 nodeMqttPUBACKSentByReasonChartTmpl.Copy(),
146 nodeMqttPUBACKUnexpectedMessagesChartTmpl.Copy(),
147
148 nodeMqttPUBRECPacketsChartTmpl.Copy(),
149 nodeMqttPUBRECReceivedByReasonChartTmpl.Copy(),
150 nodeMqttPUBRECSentByReasonChartTmpl.Copy(),
151
152 nodeMqttPUBRELPacketsChartTmpl.Copy(),
153 nodeMqttPUBRELReceivedByReasonChartTmpl.Copy(),
154 nodeMqttPUBRELSentByReasonChartTmpl.Copy(),
155
156 nodeMqttPUBCOMPPacketsChartTmpl.Copy(),
157 nodeMqttPUBCOMPReceivedByReasonChartTmpl.Copy(),
158 nodeMqttPUBCOMPSentByReasonChartTmpl.Copy(),
159 nodeMqttPUBCOMPUnexpectedMessagesChartTmpl.Copy(),
160
161 nodeMqttCONNECTPacketsChartTmpl.Copy(),
162 nodeMqttCONNACKSentByReasonCodeChartTmpl.Copy(),
163
164 nodeMqtt5DISCONNECTPacketsChartTmpl.Copy(),
165 nodeMqttDISCONNECTReceivedByReasonChartTmpl.Copy(),
166 nodeMqttDISCONNECTSentByReasonChartTmpl.Copy(),
167
168 nodeMqttSUBSCRIBEPacketsChartTmpl.Copy(),
169 modeMqttSUBSCRIBEErrorsChartTmpl.Copy(),
170 nodeMqttSUBSCRIBEAuthErrorsChartTmpl.Copy(),
171
172 nodeMqttUNSUBSCRIBEPacketsChartTmpl.Copy(),
173 nodeMqttUNSUBSCRIBEErrorsChartTmpl.Copy(),
174
175 nodeMqttAUTHPacketsChartTmpl.Copy(),
176 nodeMqttAUTHReceivedByReasonChartTmpl.Copy(),
177 nodeMqttAUTHSentByReasonChartTmpl.Copy(),
178
179 nodeMqttPINGPacketsChartTmpl.Copy(),
180 }
181
182 var nodeMqtt4ChartsTmpl = collectorapi.Charts{
183 nodeClientKeepaliveExpiredChartTmpl.Copy(),
184
185 nodeMqttPUBLISHPacketsChartTmpl.Copy(),
186 nodeMqttPUBLISHErrorsChartTmpl.Copy(),
187 nodeMqttPUBLISHAuthErrorsChartTmpl.Copy(),
188
189 nodeMqttPUBACKPacketsChartTmpl.Copy(),
190 nodeMqttPUBACKUnexpectedMessagesChartTmpl.Copy(),
191
192 nodeMqttPUBRECPacketsChartTmpl.Copy(),
193 nodeMqttPUBRECUnexpectedMessagesChartTmpl.Copy(),
194
195 nodeMqttPUBRELPacketsChartTmpl.Copy(),
196
197 nodeMqttPUBCOMPPacketsChartTmpl.Copy(),
198 nodeMqttPUBCOMPUnexpectedMessagesChartTmpl.Copy(),
199
200 nodeMqttCONNECTPacketsChartTmpl.Copy(),
201 nodeMqttCONNACKSentByReturnCodeChartTmpl.Copy(),
202
203 nodeMqtt4DISCONNECTPacketsChartTmpl.Copy(),
204
205 nodeMqttSUBSCRIBEPacketsChartTmpl.Copy(),
206 modeMqttSUBSCRIBEErrorsChartTmpl.Copy(),
207
208 nodeMqttSUBSCRIBEAuthErrorsChartTmpl.Copy(),
209 nodeMqttUNSUBSCRIBEPacketsChartTmpl.Copy(),
210 nodeMqttUNSUBSCRIBEErrorsChartTmpl.Copy(),
211
212 nodeMqttPINGPacketsChartTmpl.Copy(),
213 }
214
215 // Sockets
216 var (
217 nodeOpenSocketsChartTmpl = collectorapi.Chart{
218 ID: "node_%s_sockets",
219 Title: "Open Sockets",
220 Units: "sockets",
221 Fam: "sockets",
222 Ctx: "vernemq.node_sockets",
223 Priority: prioNodeSockets,
224 Dims: collectorapi.Dims{
225 {ID: dimNode("open_sockets"), Name: "open"},
226 },
227 }
228 nodeSocketEventsChartTmpl = collectorapi.Chart{
229 ID: "node_%s_socket_events",
230 Title: "Open and Close Socket Events",
231 Units: "events/s",
232 Fam: "sockets",
233 Ctx: "vernemq.node_socket_operations",
234 Priority: prioNodeSocketEvents,
235 Dims: collectorapi.Dims{
236 {ID: dimNode(metricSocketOpen), Name: "open", Algo: collectorapi.Incremental},
237 {ID: dimNode(metricSocketClose), Name: "close", Algo: collectorapi.Incremental, Mul: -1},
238 },
239 }
240 nodeClientKeepaliveExpiredChartTmpl = collectorapi.Chart{
241 ID: "node_%s_mqtt%s_client_keepalive_expired",
242 Title: "Closed Sockets due to Keepalive Time Expired",
243 Units: "sockets/s",
244 Fam: "sockets",
245 Ctx: "vernemq.node_client_keepalive_expired",
246 Priority: prioNodeClientKeepaliveExpired,
247 Dims: collectorapi.Dims{
248 {ID: dimMqttVer(metricClientKeepaliveExpired), Name: "closed", Algo: collectorapi.Incremental},
249 },
250 }
251 nodeSocketCloseTimeoutChartTmpl = collectorapi.Chart{
252 ID: "node_%s_socket_close_timeout",
253 Title: "Closed Sockets due to no CONNECT Frame On Time",
254 Units: "sockets/s",
255 Fam: "sockets",
256 Ctx: "vernemq.node_socket_close_timeout",
257 Priority: prioNodeSocketCloseTimeout,
258 Dims: collectorapi.Dims{
259 {ID: dimNode(metricSocketCloseTimeout), Name: "closed", Algo: collectorapi.Incremental},
260 },
261 }
262 nodeSocketErrorsChartTmpl = collectorapi.Chart{
263 ID: "node_%s_socket_errors",
264 Title: "Socket Errors",
265 Units: "errors/s",
266 Fam: "sockets",
267 Ctx: "vernemq.node_socket_errors",
268 Priority: prioNodeSocketErrors,
269 Dims: collectorapi.Dims{
270 {ID: dimNode(metricSocketError), Name: "errors", Algo: collectorapi.Incremental},
271 },
272 }
273 )
274
275 // Queues
276 var (
277 nodeQueueProcessesChartTmpl = collectorapi.Chart{
278 ID: "node_%s_queue_processes",
279 Title: "Living Queues in an Online or an Offline State",
280 Units: "queue processes",
281 Fam: "queues",
282 Ctx: "vernemq.node_queue_processes",
283 Priority: prioNodeQueueProcesses,
284 Dims: collectorapi.Dims{
285 {ID: dimNode(metricQueueProcesses), Name: "queue_processes"},
286 },
287 }
288 nodeQueueProcessesEventsChartTmpl = collectorapi.Chart{
289 ID: "node_%s_queue_processes_events",
290 Title: "Queue Processes Setup and Teardown Events",
291 Units: "events/s",
292 Fam: "queues",
293 Ctx: "vernemq.node_queue_processes_operations",
294 Priority: prioNodeQueueProcessesEvents,
295 Dims: collectorapi.Dims{
296 {ID: dimNode(metricQueueSetup), Name: "setup", Algo: collectorapi.Incremental},
297 {ID: dimNode(metricQueueTeardown), Name: "teardown", Algo: collectorapi.Incremental, Mul: -1},
298 },
299 }
300 nodeQueueProcessesOfflineStorageChartTmpl = collectorapi.Chart{
301 ID: "node_%s_queue_process_init_from_storage",
302 Title: "Queue Processes Initialized from Offline Storage",
303 Units: "queue processes/s",
304 Fam: "queues",
305 Ctx: "vernemq.node_queue_process_init_from_storage",
306 Priority: prioNodeQueueProcessesOfflineStorage,
307 Dims: collectorapi.Dims{
308 {ID: dimNode(metricQueueInitializedFromStorage), Name: "queue processes", Algo: collectorapi.Incremental},
309 },
310 }
311 nodeQueueMessagesChartTmpl = collectorapi.Chart{
312 ID: "node_%s_queue_messages",
313 Title: "Received and Sent PUBLISH Messages",
314 Units: "messages/s",
315 Fam: "queues",
316 Ctx: "vernemq.node_queue_messages",
317 Type: collectorapi.Area,
318 Priority: prioNodeQueueMessages,
319 Dims: collectorapi.Dims{
320 {ID: dimNode(metricQueueMessageIn), Name: "received", Algo: collectorapi.Incremental},
321 {ID: dimNode(metricQueueMessageOut), Name: "sent", Algo: collectorapi.Incremental, Mul: -1},
322 },
323 }
324 nodeQueuedMessagesChartTmpl = collectorapi.Chart{
325 ID: "node_%s_queued_messages",
326 Title: "Queued PUBLISH Messages",
327 Units: "messages",
328 Fam: "queues",
329 Ctx: "vernemq.node_queued_messages",
330 Type: collectorapi.Line,
331 Priority: prioNodeQueuedMessages,
332 Dims: collectorapi.Dims{
333 {ID: dimNode("queued_messages"), Name: "queued"},
334 },
335 }
336 nodeQueueUndeliveredMessagesChartTmpl = collectorapi.Chart{
337 ID: "node_%s_queue_undelivered_messages",
338 Title: "Undelivered PUBLISH Messages",
339 Units: "messages/s",
340 Fam: "queues",
341 Ctx: "vernemq.node_queue_undelivered_messages",
342 Type: collectorapi.Stacked,
343 Priority: prioNodeQueueUndeliveredMessages,
344 Dims: collectorapi.Dims{
345 {ID: dimNode(metricQueueMessageDrop), Name: "dropped", Algo: collectorapi.Incremental},
346 {ID: dimNode(metricQueueMessageExpired), Name: "expired", Algo: collectorapi.Incremental},
347 {ID: dimNode(metricQueueMessageUnhandled), Name: "unhandled", Algo: collectorapi.Incremental},
348 },
349 }
350 )
351
352 // Subscriptions
353 var (
354 nodeRouterSubscriptionsChartTmpl = collectorapi.Chart{
355 ID: "node_%s_router_subscriptions",
356 Title: "Subscriptions in the Routing Table",
357 Units: "subscriptions",
358 Fam: "subscriptions",
359 Ctx: "vernemq.node_router_subscriptions",
360 Priority: prioNodeRouterSubscriptions,
361 Dims: collectorapi.Dims{
362 {ID: dimNode(metricRouterSubscriptions), Name: "subscriptions"},
363 },
364 }
365 nodeRouterMatchedSubscriptionsChartTmpl = collectorapi.Chart{
366 ID: "node_%s_router_matched_subscriptions",
367 Title: "Matched Subscriptions",
368 Units: "subscriptions/s",
369 Fam: "subscriptions",
370 Ctx: "vernemq.node_router_matched_subscriptions",
371 Priority: prioNodeRouterMatchedSubscriptions,
372 Dims: collectorapi.Dims{
373 {ID: dimNode(metricRouterMatchesLocal), Name: "local", Algo: collectorapi.Incremental},
374 {ID: dimNode(metricRouterMatchesRemote), Name: "remote", Algo: collectorapi.Incremental},
375 },
376 }
377 nodeRouterMemoryChartTmpl = collectorapi.Chart{
378 ID: "node_%s_router_memory",
379 Title: "Routing Table Memory Usage",
380 Units: "bytes",
381 Fam: "subscriptions",
382 Ctx: "vernemq.node_router_memory",
383 Type: collectorapi.Area,
384 Priority: prioNodeRouterMemory,
385 Dims: collectorapi.Dims{
386 {ID: dimNode(metricRouterMemory), Name: "used"},
387 },
388 }
389 )
390
391 // Erlang VM
392 var (
393 nodeAverageSchedulerUtilizationChartTmpl = collectorapi.Chart{
394 ID: "node_%s_average_scheduler_utilization",
395 Title: "Average Scheduler Utilization",
396 Units: "percentage",
397 Fam: "erlang vm",
398 Ctx: "vernemq.node_average_scheduler_utilization",
399 Type: collectorapi.Area,
400 Priority: prioNodeAverageSchedulerUtilization,
401 Dims: collectorapi.Dims{
402 {ID: dimNode(metricSystemUtilization), Name: "utilization"},
403 },
404 }
405 nodeSystemProcessesChartTmpl = collectorapi.Chart{
406 ID: "node_%s_system_processes",
407 Title: "Erlang Processes",
408 Units: "processes",
409 Fam: "erlang vm",
410 Ctx: "vernemq.node_system_processes",
411 Priority: prioNodeSystemProcesses,
412 Dims: collectorapi.Dims{
413 {ID: dimNode(metricSystemProcessCount), Name: "processes"},
414 },
415 }
416 nodeSystemReductionsChartTmpl = collectorapi.Chart{
417 ID: "node_%s_system_reductions",
418 Title: "Reductions",
419 Units: "ops/s",
420 Fam: "erlang vm",
421 Ctx: "vernemq.node_system_reductions",
422 Priority: prioNodeSystemReductions,
423 Dims: collectorapi.Dims{
424 {ID: dimNode(metricSystemReductions), Name: "reductions", Algo: collectorapi.Incremental},
425 },
426 }
427 nodeSystemContextSwitches = collectorapi.Chart{
428 ID: "node_%s_system_context_switches",
429 Title: "Context Switches",
430 Units: "ops/s",
431 Fam: "erlang vm",
432 Ctx: "vernemq.node_system_context_switches",
433 Priority: prioNodeSystemContext,
434 Dims: collectorapi.Dims{
435 {ID: dimNode(metricSystemContextSwitches), Name: "context switches", Algo: collectorapi.Incremental},
436 },
437 }
438 nodeSystemIOChartTmpl = collectorapi.Chart{
439 ID: "node_%s_system_io",
440 Title: "Received and Sent Traffic through Ports",
441 Units: "bytes/s",
442 Fam: "erlang vm",
443 Ctx: "vernemq.node_system_io",
444 Type: collectorapi.Area,
445 Priority: prioNodeSystemIO,
446 Dims: collectorapi.Dims{
447 {ID: dimNode(metricSystemIOIn), Name: "received", Algo: collectorapi.Incremental},
448 {ID: dimNode(metricSystemIOOut), Name: "sent", Algo: collectorapi.Incremental, Mul: -1},
449 },
450 }
451 nodeSystemRunQueueChartTmpl = collectorapi.Chart{
452 ID: "node_%s_system_run_queue",
453 Title: "Processes that are Ready to Run on All Run-Queues",
454 Units: "processes",
455 Fam: "erlang vm",
456 Ctx: "vernemq.node_system_run_queue",
457 Priority: prioNodeSystemRunQueue,
458 Dims: collectorapi.Dims{
459 {ID: dimNode(metricSystemRunQueue), Name: "ready"},
460 },
461 }
462 nodeSystemGCCountChartTmpl = collectorapi.Chart{
463 ID: "node_%s_system_gc_count",
464 Title: "GC Count",
465 Units: "ops/s",
466 Fam: "erlang vm",
467 Ctx: "vernemq.node_system_gc_count",
468 Priority: prioNodeSystemGCCount,
469 Dims: collectorapi.Dims{
470 {ID: dimNode(metricSystemGCCount), Name: "gc", Algo: collectorapi.Incremental},
471 },
472 }
473 nodeSystemGCWordsReclaimedChartTmpl = collectorapi.Chart{
474 ID: "node_%s_system_gc_words_reclaimed",
475 Title: "GC Words Reclaimed",
476 Units: "ops/s",
477 Fam: "erlang vm",
478 Ctx: "vernemq.node_system_gc_words_reclaimed",
479 Priority: prioNodeSystemGCWordsReclaimed,
480 Dims: collectorapi.Dims{
481 {ID: dimNode(metricSystemWordsReclaimedByGC), Name: "words reclaimed", Algo: collectorapi.Incremental},
482 },
483 }
484 nodeSystemMemoryAllocatedChartTmpl = collectorapi.Chart{
485 ID: "node_%s_system_allocated_memory",
486 Title: "Memory Allocated by the Erlang Processes and by the Emulator",
487 Units: "bytes",
488 Fam: "erlang vm",
489 Ctx: "vernemq.node_system_allocated_memory",
490 Type: collectorapi.Stacked,
491 Priority: prioNodeSystemMemoryAllocated,
492 Dims: collectorapi.Dims{
493 {ID: dimNode(metricVMMemoryProcesses), Name: "processes"},
494 {ID: dimNode(metricVMMemorySystem), Name: "system"},
495 },
496 }
497 )
498
499 // Traffic
500 var (
501 nodeTrafficChartTmpl = collectorapi.Chart{
502 ID: "node_%s_traffic",
503 Title: "Node Traffic",
504 Units: "bytes/s",
505 Fam: "traffic",
506 Ctx: "vernemq.node_traffic",
507 Type: collectorapi.Area,
508 Priority: prioNodeTraffic,
509 Dims: collectorapi.Dims{
510 {ID: dimNode(metricBytesReceived), Name: "received", Algo: collectorapi.Incremental},
511 {ID: dimNode(metricBytesSent), Name: "sent", Algo: collectorapi.Incremental, Mul: -1},
512 },
513 }
514 )
515
516 // Retain
517 var (
518 nodeRetainMessagesChartsTmpl = collectorapi.Chart{
519 ID: "node_%s_retain_messages",
520 Title: "Stored Retained Messages",
521 Units: "messages",
522 Fam: "retain",
523 Ctx: "vernemq.node_retain_messages",
524 Priority: prioNodeRetainMessages,
525 Dims: collectorapi.Dims{
526 {ID: dimNode(metricRetainMessages), Name: "messages"},
527 },
528 }
529 nodeRetainMemoryUsageChartTmpl = collectorapi.Chart{
530 ID: "node_%s_retain_memory",
531 Title: "Stored Retained Messages Memory Usage",
532 Units: "bytes",
533 Fam: "retain",
534 Ctx: "vernemq.node_retain_memory",
535 Type: collectorapi.Area,
536 Priority: prioNodeRetainMemoryUsage,
537 Dims: collectorapi.Dims{
538 {ID: dimNode(metricRetainMemory), Name: "used"},
539 },
540 }
541 )
542
543 // Cluster
544 var (
545 nodeClusterCommunicationTrafficChartTmpl = collectorapi.Chart{
546 ID: "node_%s_cluster_traffic",
547 Title: "Communication with Other Cluster Nodes",
548 Units: "bytes/s",
549 Fam: "cluster",
550 Ctx: "vernemq.node_cluster_traffic",
551 Type: collectorapi.Area,
552 Priority: prioNodeClusterCommunicationTraffic,
553 Dims: collectorapi.Dims{
554 {ID: dimNode(metricClusterBytesReceived), Name: "received", Algo: collectorapi.Incremental},
555 {ID: dimNode(metricClusterBytesSent), Name: "sent", Algo: collectorapi.Incremental, Mul: -1},
556 },
557 }
558 nodeClusterCommunicationDroppedChartTmpl = collectorapi.Chart{
559 ID: "node_%s_cluster_dropped",
560 Title: "Traffic Dropped During Communication with Other Cluster Nodes",
561 Units: "bytes/s",
562 Fam: "cluster",
563 Type: collectorapi.Area,
564 Ctx: "vernemq.node_cluster_dropped",
565 Priority: prioNodeClusterCommunicationDropped,
566 Dims: collectorapi.Dims{
567 {ID: dimNode(metricClusterBytesDropped), Name: "dropped", Algo: collectorapi.Incremental},
568 },
569 }
570 nodeNetSplitUnresolvedChartTmpl = collectorapi.Chart{
571 ID: "node_%s_netsplit_unresolved",
572 Title: "Unresolved Netsplits",
573 Units: "netsplits",
574 Fam: "cluster",
575 Ctx: "vernemq.node_netsplit_unresolved",
576 Priority: prioNodeNetSplitUnresolved,
577 Dims: collectorapi.Dims{
578 {ID: dimNode("netsplit_unresolved"), Name: "unresolved"},
579 },
580 }
581 nodeNetSplitsChartTmpl = collectorapi.Chart{
582 ID: "node_%s_netsplit",
583 Title: "Netsplits",
584 Units: "netsplits/s",
585 Fam: "cluster",
586 Ctx: "vernemq.node_netsplits",
587 Type: collectorapi.Stacked,
588 Priority: prioNodeNetSplits,
589 Dims: collectorapi.Dims{
590 {ID: dimNode(metricNetSplitResolved), Name: "resolved", Algo: collectorapi.Incremental},
591 {ID: dimNode(metricNetSplitDetected), Name: "detected", Algo: collectorapi.Incremental},
592 },
593 }
594 )
595
596 var (
597 nodeUptimeChartTmpl = collectorapi.Chart{
598 ID: "node_%s_uptime",
599 Title: "Node Uptime",
600 Units: "seconds",
601 Fam: "uptime",
602 Ctx: "vernemq.node_uptime",
603 Priority: prioNodeUptime,
604 Dims: collectorapi.Dims{
605 {ID: dimNode(metricSystemWallClock), Name: "time", Div: 1000},
606 },
607 }
608 )
609
610 // PUBLISH
611 var (
612 nodeMqttPUBLISHPacketsChartTmpl = collectorapi.Chart{
613 ID: "node_%s_mqtt%s_publish",
614 Title: "MQTT QoS 0,1,2 PUBLISH",
615 Units: "packets/s",
616 Fam: "mqtt publish",
617 Ctx: "vernemq.node_mqtt_publish",
618 Priority: prioMqttPublishPackets,
619 Dims: collectorapi.Dims{
620 {ID: dimMqttVer(metricPUBSLISHReceived), Name: "received", Algo: collectorapi.Incremental},
621 {ID: dimMqttVer(metricPUBSLIHSent), Name: "sent", Algo: collectorapi.Incremental, Mul: -1},
622 },
623 }
624 nodeMqttPUBLISHErrorsChartTmpl = collectorapi.Chart{
625 ID: "node_%s_mqtt%s_publish_errors",
626 Title: "MQTT Failed PUBLISH Operations due to a Netsplit",
627 Units: "errors/s",
628 Fam: "mqtt publish",
629 Ctx: "vernemq.node_mqtt_publish_errors",
630 Priority: prioMqttPublishErrors,
631 Dims: collectorapi.Dims{
632 {ID: dimMqttVer(metricPUBLISHError), Name: "publish", Algo: collectorapi.Incremental},
633 },
634 }
635 nodeMqttPUBLISHAuthErrorsChartTmpl = collectorapi.Chart{
636 ID: "node_%s_mqtt%s_publish_auth_errors",
637 Title: "MQTT Unauthorized PUBLISH Attempts",
638 Units: "errors/s",
639 Fam: "mqtt publish",
640 Ctx: "vernemq.node_mqtt_publish_auth_errors",
641 Type: collectorapi.Area,
642 Priority: prioMqttPublishAuthPackets,
643 Dims: collectorapi.Dims{
644 {ID: dimMqttVer(metricPUBLISHAuthError), Name: "publish_auth", Algo: collectorapi.Incremental},
645 },
646 }
647 nodeMqttPUBACKPacketsChartTmpl = collectorapi.Chart{
648 ID: "node_%s_mqtt%s_puback",
649 Title: "MQTT QoS 1 PUBACK Packets",
650 Units: "packets/s",
651 Fam: "mqtt publish",
652 Ctx: "vernemq.node_mqtt_puback",
653 Priority: prioMqttPubAckPackets,
654 Dims: collectorapi.Dims{
655 {ID: dimMqttVer(metricPUBACKReceived), Name: "received", Algo: collectorapi.Incremental},
656 {ID: dimMqttVer(metricPUBACKSent), Name: "sent", Algo: collectorapi.Incremental, Mul: -1},
657 },
658 }
659 nodeMqttPUBACKReceivedByReasonChartTmpl = func() collectorapi.Chart {
660 chart := collectorapi.Chart{
661 ID: "node_%s_mqtt%s_puback_received_by_reason_code",
662 Title: "MQTT PUBACK QoS 1 Received by Reason",
663 Units: "packets/s",
664 Fam: "mqtt publish",
665 Ctx: "vernemq.node_mqtt_puback_received_by_reason_code",
666 Type: collectorapi.Stacked,
667 Priority: prioMqttPubAckReceivedReason,
668 }
669 for _, v := range mqtt5PUBACKReceivedReasonCodes {
670 chart.Dims = append(chart.Dims, &collectorapi.Dim{
671 ID: dimMqttReason(metricPUBACKReceived, v), Name: v, Algo: collectorapi.Incremental,
672 })
673 }
674 return chart
675 }()
676 nodeMqttPUBACKSentByReasonChartTmpl = func() collectorapi.Chart {
677 chart := collectorapi.Chart{
678 ID: "node_%s_mqtt%s_puback_sent_by_reason_code",
679 Title: "MQTT PUBACK QoS 1 Sent by Reason",
680 Units: "packets/s",
681 Fam: "mqtt publish",
682 Ctx: "vernemq.node_mqtt_puback_sent_by_reason_code",
683 Type: collectorapi.Stacked,
684 Priority: prioMqttPubAckSentReason,
685 }
686 for _, v := range mqtt5PUBACKSentReasonCodes {
687 chart.Dims = append(chart.Dims, &collectorapi.Dim{
688 ID: dimMqttReason(metricPUBACKSent, v), Name: v, Algo: collectorapi.Incremental,
689 })
690 }
691 return chart
692 }()
693 nodeMqttPUBACKUnexpectedMessagesChartTmpl = collectorapi.Chart{
694 ID: "node_%s_mqtt%s_puback_unexpected",
695 Title: "MQTT PUBACK QoS 1 Received Unexpected Messages",
696 Units: "messages/s",
697 Fam: "mqtt publish",
698 Ctx: "vernemq.node_mqtt_puback_invalid_error",
699 Priority: prioMqttPubAckUnexpectedMessages,
700 Dims: collectorapi.Dims{
701 {ID: dimMqttVer(metricPUBACKInvalid), Name: "unexpected", Algo: collectorapi.Incremental},
702 },
703 }
704 nodeMqttPUBRECPacketsChartTmpl = collectorapi.Chart{
705 ID: "node_%s_mqtt%s_pubrec",
706 Title: "MQTT PUBREC QoS 2 Packets",
707 Units: "packets/s",
708 Fam: "mqtt publish",
709 Ctx: "vernemq.node_mqtt_pubrec",
710 Priority: prioMqttPubRecPackets,
711 Dims: collectorapi.Dims{
712 {ID: dimMqttVer(metricPUBRECReceived), Name: "received", Algo: collectorapi.Incremental},
713 {ID: dimMqttVer(metricPUBRECSent), Name: "sent", Algo: collectorapi.Incremental, Mul: -1},
714 },
715 }
716 nodeMqttPUBRECReceivedByReasonChartTmpl = func() collectorapi.Chart {
717 chart := collectorapi.Chart{
718 ID: "node_%s_mqtt%s_pubrec_received_by_reason_code",
719 Title: "MQTT PUBREC QoS 2 Received by Reason",
720 Units: "packets/s",
721 Fam: "mqtt publish",
722 Ctx: "vernemq.node_mqtt_pubrec_received_by_reason_code",
723 Type: collectorapi.Stacked,
724 Priority: prioMqttPubRecReceivedReason,
725 }
726 for _, v := range mqtt5PUBRECReceivedReasonCodes {
727 chart.Dims = append(chart.Dims, &collectorapi.Dim{
728 ID: dimMqttReason(metricPUBRECReceived, v), Name: v, Algo: collectorapi.Incremental,
729 })
730 }
731 return chart
732 }()
733 nodeMqttPUBRECSentByReasonChartTmpl = func() collectorapi.Chart {
734 chart := collectorapi.Chart{
735 ID: "node_%s_mqtt%s_pubrec_sent_by_reason_code",
736 Title: "MQTT PUBREC QoS 2 Sent by Reason",
737 Units: "packets/s",
738 Fam: "mqtt publish",
739 Ctx: "vernemq.node_mqtt_pubrec_sent_by_reason_code",
740 Type: collectorapi.Stacked,
741 Priority: prioMqttPubRecSentReason,
742 }
743 for _, v := range mqtt5PUBRECSentReasonCodes {
744 chart.Dims = append(chart.Dims, &collectorapi.Dim{
745 ID: dimMqttReason(metricPUBRECSent, v), Name: v, Algo: collectorapi.Incremental,
746 })
747 }
748 return chart
749 }()
750 nodeMqttPUBRECUnexpectedMessagesChartTmpl = collectorapi.Chart{
751 ID: "node_%s_mqtt%s_pubrec_unexpected",
752 Title: "MQTT PUBREC QoS 2 Received Unexpected Messages",
753 Units: "messages/s",
754 Fam: "mqtt publish",
755 Ctx: "vernemq.node_mqtt_pubrec_invalid_error",
756 Priority: prioMqttPubRecUnexpectedMessages,
757 Dims: collectorapi.Dims{
758 {ID: dimMqttVer(metricPUBRECInvalid), Name: "unexpected", Algo: collectorapi.Incremental},
759 },
760 }
761 nodeMqttPUBRELPacketsChartTmpl = collectorapi.Chart{
762 ID: "node_%s_mqtt%s_pubrel",
763 Title: "MQTT PUBREL QoS 2 Packets¬",
764 Units: "packets/s",
765 Fam: "mqtt publish",
766 Ctx: "vernemq.node_mqtt_pubrel",
767 Priority: prioMqttPubRelPackets,
768 Dims: collectorapi.Dims{
769 {ID: dimMqttVer(metricPUBRELReceived), Name: "received", Algo: collectorapi.Incremental},
770 {ID: dimMqttVer(metricPUBRELSent), Name: "sent", Algo: collectorapi.Incremental, Mul: -1},
771 },
772 }
773 nodeMqttPUBRELReceivedByReasonChartTmpl = func() collectorapi.Chart {
774 chart := collectorapi.Chart{
775 ID: "node_%s_mqtt%s_pubrel_received_by_reason_code",
776 Title: "MQTT PUBREL QoS 2 Received by Reason",
777 Units: "packets/s",
778 Fam: "mqtt publish",
779 Ctx: "vernemq.node_mqtt_pubrel_received_by_reason_code",
780 Type: collectorapi.Stacked,
781 Priority: prioMqttPubRelReceivedReason,
782 }
783 for _, v := range mqtt5PUBRELReceivedReasonCodes {
784 chart.Dims = append(chart.Dims, &collectorapi.Dim{
785 ID: dimMqttReason(metricPUBRELReceived, v), Name: v, Algo: collectorapi.Incremental,
786 })
787 }
788 return chart
789 }()
790 nodeMqttPUBRELSentByReasonChartTmpl = func() collectorapi.Chart {
791 chart := collectorapi.Chart{
792 ID: "node_%s_mqtt%s_pubrel_sent_by_reason_code",
793 Title: "MQTT PUBREL QoS 2 Sent by Reason",
794 Units: "packets/s",
795 Fam: "mqtt publish",
796 Ctx: "vernemq.node_mqtt_pubrel_sent_by_reason_code",
797 Type: collectorapi.Stacked,
798 Priority: prioMqttPubRelSentReason,
799 }
800 for _, v := range mqtt5PUBRELSentReasonCodes {
801 chart.Dims = append(chart.Dims, &collectorapi.Dim{
802 ID: dimMqttReason(metricPUBRELSent, v), Name: v, Algo: collectorapi.Incremental,
803 })
804 }
805 return chart
806 }()
807 nodeMqttPUBCOMPPacketsChartTmpl = collectorapi.Chart{
808 ID: "node_%s_mqtt%s_pubcomp",
809 Title: "MQTT PUBCOMP QoS 2 Packets",
810 Units: "packets/s",
811 Fam: "mqtt publish",
812 Ctx: "vernemq.node_mqtt_pubcomp",
813 Priority: prioMqttPubCompPackets,
814 Dims: collectorapi.Dims{
815 {ID: dimMqttVer(metricPUBCOMPReceived), Name: "received", Algo: collectorapi.Incremental},
816 {ID: dimMqttVer(metricPUBCOMPSent), Name: "sent", Algo: collectorapi.Incremental, Mul: -1},
817 },
818 }
819 nodeMqttPUBCOMPReceivedByReasonChartTmpl = func() collectorapi.Chart {
820 chart := collectorapi.Chart{
821 ID: "node_%s_mqtt%s_pubcomp_received_by_reason_code",
822 Title: "MQTT PUBCOMP QoS 2 Received by Reason",
823 Units: "packets/s",
824 Fam: "mqtt publish",
825 Ctx: "vernemq.node_mqtt_pubcomp_received_by_reason_code",
826 Type: collectorapi.Stacked,
827 Priority: prioMqttPubCompReceivedReason,
828 }
829 for _, v := range mqtt5PUBCOMPReceivedReasonCodes {
830 chart.Dims = append(chart.Dims, &collectorapi.Dim{
831 ID: dimMqttReason(metricPUBCOMPReceived, v), Name: v, Algo: collectorapi.Incremental,
832 })
833 }
834 return chart
835 }()
836 nodeMqttPUBCOMPSentByReasonChartTmpl = func() collectorapi.Chart {
837 chart := collectorapi.Chart{
838 ID: "node_%s_mqtt%s_pubcomp_sent_by_reason_code",
839 Title: "MQTT PUBCOMP QoS 2 Sent by Reason",
840 Units: "packets/s",
841 Fam: "mqtt publish",
842 Ctx: "vernemq.node_mqtt_pubcomp_sent_by_reason_code",
843 Type: collectorapi.Stacked,
844 Priority: prioMqttPubCompSentReason,
845 }
846 for _, v := range mqtt5PUBCOMPSentReasonCodes {
847 chart.Dims = append(chart.Dims, &collectorapi.Dim{
848 ID: dimMqttReason(metricPUBCOMPSent, v), Name: v, Algo: collectorapi.Incremental,
849 })
850 }
851 return chart
852 }()
853 nodeMqttPUBCOMPUnexpectedMessagesChartTmpl = collectorapi.Chart{
854 ID: "node_%s_mqtt%s_pubcomp_unexpected",
855 Title: "MQTT PUBCOMP QoS 2 Received Unexpected Messages",
856 Units: "messages/s",
857 Fam: "mqtt publish",
858 Ctx: "vernemq.node_mqtt_pubcomp_invalid_error",
859 Priority: prioMqttPubCompUnexpectedMessages,
860 Dims: collectorapi.Dims{
861 {ID: dimMqttVer(metricPUNCOMPInvalid), Name: "unexpected", Algo: collectorapi.Incremental},
862 },
863 }
864 )
865
866 // CONNECT
867 var (
868 nodeMqttCONNECTPacketsChartTmpl = collectorapi.Chart{
869 ID: "node_%s_mqtt%s_connect",
870 Title: "MQTT CONNECT and CONNACK",
871 Units: "packets/s",
872 Fam: "mqtt connect",
873 Ctx: "vernemq.node_mqtt_connect",
874 Priority: prioMqttConnectPackets,
875 Dims: collectorapi.Dims{
876 {ID: dimMqttVer(metricCONNECTReceived), Name: "connect", Algo: collectorapi.Incremental},
877 {ID: dimMqttVer(metricCONNACKSent), Name: "connack", Algo: collectorapi.Incremental, Mul: -1},
878 },
879 }
880 nodeMqttCONNACKSentByReturnCodeChartTmpl = func() collectorapi.Chart {
881 chart := collectorapi.Chart{
882 ID: "node_%s_mqtt%s_connack_sent_by_return_code",
883 Title: "MQTT CONNACK Sent by Return Code",
884 Units: "packets/s",
885 Fam: "mqtt connect",
886 Ctx: "vernemq.node_mqtt_connack_sent_by_return_code",
887 Type: collectorapi.Stacked,
888 Priority: prioMqttConnectSentReason,
889 }
890 for _, v := range mqtt4CONNACKSentReturnCodes {
891 chart.Dims = append(chart.Dims, &collectorapi.Dim{
892 ID: dimMqttRCode(metricCONNACKSent, v), Name: v, Algo: collectorapi.Incremental,
893 })
894 }
895 return chart
896 }()
897 nodeMqttCONNACKSentByReasonCodeChartTmpl = func() collectorapi.Chart {
898 chart := collectorapi.Chart{
899 ID: "node_%s_mqtt%s_connack_sent_by_reason_code",
900 Title: "MQTT CONNACK Sent by Reason",
901 Units: "packets/s",
902 Fam: "mqtt connect",
903 Ctx: "vernemq.node_mqtt_connack_sent_by_reason_code",
904 Type: collectorapi.Stacked,
905 Priority: prioMqttConnectSentReason,
906 }
907 for _, v := range mqtt5CONNACKSentReasonCodes {
908 chart.Dims = append(chart.Dims, &collectorapi.Dim{
909 ID: dimMqttReason(metricCONNACKSent, v), Name: v, Algo: collectorapi.Incremental,
910 })
911 }
912 return chart
913 }()
914 )
915
916 // DISCONNECT
917 var (
918 nodeMqtt5DISCONNECTPacketsChartTmpl = collectorapi.Chart{
919 ID: "node_%s_mqtt%s_disconnect",
920 Title: "MQTT DISCONNECT Packets",
921 Units: "packets/s",
922 Fam: "mqtt disconnect",
923 Ctx: "vernemq.node_mqtt_disconnect",
924 Priority: prioMqttDisconnectPackets,
925 Dims: collectorapi.Dims{
926 {ID: dimMqttVer(metricDISCONNECTReceived), Name: "received", Algo: collectorapi.Incremental},
927 {ID: dimMqttVer(metricDISCONNECTSent), Name: "sent", Algo: collectorapi.Incremental, Mul: -1},
928 },
929 }
930 nodeMqtt4DISCONNECTPacketsChartTmpl = func() collectorapi.Chart {
931 chart := nodeMqtt5DISCONNECTPacketsChartTmpl.Copy()
932 _ = chart.RemoveDim(dimMqttVer(metricDISCONNECTSent))
933 return *chart
934 }()
935 nodeMqttDISCONNECTReceivedByReasonChartTmpl = func() collectorapi.Chart {
936 chart := collectorapi.Chart{
937 ID: "node_%s_mqtt%s_disconnect_received_by_reason_code",
938 Title: "MQTT DISCONNECT Received by Reason",
939 Units: "packets/s",
940 Fam: "mqtt disconnect",
941 Ctx: "vernemq.node_mqtt_disconnect_received_by_reason_code",
942 Type: collectorapi.Stacked,
943 Priority: prioMqttDisconnectReceivedReason,
944 }
945 for _, v := range mqtt5DISCONNECTReceivedReasonCodes {
946 chart.Dims = append(chart.Dims, &collectorapi.Dim{
947 ID: dimMqttReason(metricDISCONNECTReceived, v), Name: v, Algo: collectorapi.Incremental,
948 })
949 }
950 return chart
951 }()
952 nodeMqttDISCONNECTSentByReasonChartTmpl = func() collectorapi.Chart {
953 chart := collectorapi.Chart{
954 ID: "node_%s_mqtt%s_disconnect_sent_by_reason_code",
955 Title: "MQTT DISCONNECT Sent by Reason",
956 Units: "packets/s",
957 Fam: "mqtt disconnect",
958 Ctx: "vernemq.node_mqtt_disconnect_sent_by_reason_code",
959 Type: collectorapi.Stacked,
960 Priority: prioMqttDisconnectSentReason,
961 }
962 for _, v := range mqtt5DISCONNECTSentReasonCodes {
963 chart.Dims = append(chart.Dims, &collectorapi.Dim{
964 ID: dimMqttReason(metricDISCONNECTSent, v), Name: v, Algo: collectorapi.Incremental,
965 })
966 }
967 return chart
968 }()
969 )
970
971 // SUBSCRIBE
972 var (
973 nodeMqttSUBSCRIBEPacketsChartTmpl = collectorapi.Chart{
974 ID: "node_%s_mqtt%s_subscribe",
975 Title: "MQTT SUBSCRIBE and SUBACK Packets",
976 Units: "packets/s",
977 Fam: "mqtt subscribe",
978 Ctx: "vernemq.node_mqtt_subscribe",
979 Priority: prioMqttSubscribePackets,
980 Dims: collectorapi.Dims{
981 {ID: dimMqttVer(metricSUBSCRIBEReceived), Name: "subscribe", Algo: collectorapi.Incremental},
982 {ID: dimMqttVer(metricSUBACKSent), Name: "suback", Algo: collectorapi.Incremental, Mul: -1},
983 },
984 }
985 modeMqttSUBSCRIBEErrorsChartTmpl = collectorapi.Chart{
986 ID: "node_%s_mqtt%s_subscribe_error",
987 Title: "MQTT Failed SUBSCRIBE Operations due to Netsplit",
988 Units: "errors/s",
989 Fam: "mqtt subscribe",
990 Ctx: "vernemq.node_mqtt_subscribe_error",
991 Priority: prioMqttSubscribeErrors,
992 Dims: collectorapi.Dims{
993 {ID: dimMqttVer(metricSUBSCRIBEError), Name: "subscribe", Algo: collectorapi.Incremental},
994 },
995 }
996 nodeMqttSUBSCRIBEAuthErrorsChartTmpl = collectorapi.Chart{
997 ID: "node_%s_mqtt%s_subscribe_auth_error",
998 Title: "MQTT Unauthorized SUBSCRIBE Attempts",
999 Units: "errors/s",
1000 Fam: "mqtt subscribe",
1001 Ctx: "vernemq.node_mqtt_subscribe_auth_error",
1002 Priority: prioMqttSubscribeAuthPackets,
1003 Dims: collectorapi.Dims{
1004 {ID: dimMqttVer(metricSUBSCRIBEAuthError), Name: "subscribe_auth", Algo: collectorapi.Incremental},
1005 },
1006 }
1007 )
1008
1009 // UNSUBSCRIBE
1010 var (
1011 nodeMqttUNSUBSCRIBEPacketsChartTmpl = collectorapi.Chart{
1012 ID: "node_%s_mqtt%s_unsubscribe",
1013 Title: "MQTT UNSUBSCRIBE and UNSUBACK Packets",
1014 Units: "packets/s",
1015 Fam: "mqtt unsubscribe",
1016 Ctx: "vernemq.node_mqtt_unsubscribe",
1017 Priority: prioMqttUnsubscribePackets,
1018 Dims: collectorapi.Dims{
1019 {ID: dimMqttVer(metricUNSUBSCRIBEReceived), Name: "unsubscribe", Algo: collectorapi.Incremental},
1020 {ID: dimMqttVer(metricUNSUBACKSent), Name: "unsuback", Algo: collectorapi.Incremental, Mul: -1},
1021 },
1022 }
1023 nodeMqttUNSUBSCRIBEErrorsChartTmpl = collectorapi.Chart{
1024 ID: "node_%s_mqtt%s_unsubscribe_error",
1025 Title: "MQTT Failed UNSUBSCRIBE Operations due to Netsplit",
1026 Units: "errors/s",
1027 Fam: "mqtt unsubscribe",
1028 Ctx: "vernemq.node_mqtt_unsubscribe_error",
1029 Priority: prioMqttUnsubscribeErrors,
1030 Dims: collectorapi.Dims{
1031 {ID: dimMqttVer(metricUNSUBSCRIBEError), Name: "unsubscribe", Algo: collectorapi.Incremental},
1032 },
1033 }
1034 )
1035
1036 // AUTH
1037 var (
1038 nodeMqttAUTHPacketsChartTmpl = collectorapi.Chart{
1039 ID: "node_%s_mqtt%s_auth",
1040 Title: "MQTT AUTH Packets",
1041 Units: "packets/s",
1042 Fam: "mqtt auth",
1043 Ctx: "vernemq.node_mqtt_auth",
1044 Priority: prioMqttAuthPackets,
1045 Dims: collectorapi.Dims{
1046 {ID: dimMqttVer(metricAUTHReceived), Name: "received", Algo: collectorapi.Incremental},
1047 {ID: dimMqttVer(metricAUTHSent), Name: "sent", Algo: collectorapi.Incremental, Mul: -1},
1048 },
1049 }
1050 nodeMqttAUTHReceivedByReasonChartTmpl = func() collectorapi.Chart {
1051 chart := collectorapi.Chart{
1052 ID: "node_%s_mqtt%s_auth_received_by_reason_code",
1053 Title: "MQTT AUTH Received by Reason",
1054 Units: "packets/s",
1055 Fam: "mqtt auth",
1056 Ctx: "vernemq.node_mqtt_auth_received_by_reason_code",
1057 Type: collectorapi.Stacked,
1058 Priority: prioMqttAuthReceivedReason,
1059 }
1060 for _, v := range mqtt5AUTHReceivedReasonCodes {
1061 chart.Dims = append(chart.Dims, &collectorapi.Dim{
1062 ID: dimMqttReason(metricAUTHReceived, v), Name: v, Algo: collectorapi.Incremental,
1063 })
1064 }
1065 return chart
1066 }()
1067 nodeMqttAUTHSentByReasonChartTmpl = func() collectorapi.Chart {
1068 chart := collectorapi.Chart{
1069 ID: "node_%s_mqtt%s_auth_sent_by_reason_code",
1070 Title: "MQTT AUTH Sent by Reason",
1071 Units: "packets/s",
1072 Fam: "mqtt auth",
1073 Ctx: "vernemq.node_mqtt_auth_sent_by_reason_code",
1074 Type: collectorapi.Stacked,
1075 Priority: prioMqttAuthSentReason,
1076 }
1077 for _, v := range mqtt5AUTHSentReasonCodes {
1078 chart.Dims = append(chart.Dims, &collectorapi.Dim{
1079 ID: dimMqttReason(metricAUTHSent, v), Name: v, Algo: collectorapi.Incremental,
1080 })
1081 }
1082 return chart
1083 }()
1084 )
1085
1086 // PING
1087 var (
1088 nodeMqttPINGPacketsChartTmpl = collectorapi.Chart{
1089 ID: "node_%s_mqtt_ver_%s_ping",
1090 Title: "MQTT PING Packets",
1091 Units: "packets/s",
1092 Fam: "mqtt ping",
1093 Ctx: "vernemq.node_mqtt_ping",
1094 Priority: prioMqttPingPackets,
1095 Dims: collectorapi.Dims{
1096 {ID: dimMqttVer(metricPINGREQReceived), Name: "pingreq", Algo: collectorapi.Incremental},
1097 {ID: dimMqttVer(metricPINGRESPSent), Name: "pingresp", Algo: collectorapi.Incremental, Mul: -1},
1098 },
1099 }
1100 )
1101
1102 func (c *Collector) addNodeCharts(node string, nst *nodeStats) {
1103 if err := c.Charts().Add(*newNodeCharts(node)...); err != nil {
1104 c.Warningf("error on adding node '%s' charts: %v", node, err)
1105 }
1106 if len(nst.mqtt4) > 0 {
1107 if err := c.Charts().Add(*newNodeMqttCharts(node, "4")...); err != nil {
1108 c.Warningf("error on adding node '%s' mqtt v4 charts: %v", node, err)
1109 }
1110 }
1111 if len(nst.mqtt5) > 0 {
1112 if err := c.Charts().Add(*newNodeMqttCharts(node, "5")...); err != nil {
1113 c.Warningf("error on adding node '%s' mqtt 5 charts: %v", node, err)
1114 }
1115 }
1116 }
1117
1118 func (c *Collector) removeNodeCharts(node string) {
1119 px := cleanChartID(fmt.Sprintf("node_%s_", node))
1120
1121 for _, chart := range *c.Charts() {
1122 if strings.HasPrefix(chart.ID, px) {
1123 chart.MarkRemove()
1124 chart.MarkNotCreated()
1125 }
1126 }
1127 }
1128
1129 func newNodeCharts(node string) *collectorapi.Charts {
1130 charts := nodeChartsTmpl.Copy()
1131
1132 for _, chart := range *charts {
1133 chart.ID = cleanChartID(fmt.Sprintf(chart.ID, node))
1134 chart.Labels = []collectorapi.Label{
1135 {Key: "node", Value: node},
1136 }
1137 for _, dim := range chart.Dims {
1138 dim.ID = fmt.Sprintf(dim.ID, node)
1139 }
1140 }
1141
1142 return charts
1143 }
1144
1145 func newNodeMqttCharts(node, mqttVer string) *collectorapi.Charts {
1146 var charts *collectorapi.Charts
1147
1148 switch mqttVer {
1149 case "4":
1150 charts = nodeMqtt4ChartsTmpl.Copy()
1151 case "5":
1152 charts = nodeMqtt5ChartsTmpl.Copy()
1153 default:
1154 return nil
1155 }
1156
1157 for _, chart := range *charts {
1158 chart.ID = cleanChartID(fmt.Sprintf(chart.ID, node, mqttVer))
1159 chart.Labels = []collectorapi.Label{
1160 {Key: "node", Value: node},
1161 {Key: "mqtt_version", Value: mqttVer},
1162 }
1163 for _, dim := range chart.Dims {
1164 dim.ID = fmt.Sprintf(dim.ID, node, mqttVer)
1165 }
1166 }
1167
1168 return charts
1169 }
1170
1171 func dimNode(name string) string {
1172 return join("node_%s", name)
1173 }
1174
1175 func dimMqttVer(name string) string {
1176 return join("node_%s_mqtt%s", name)
1177 }
1178
1179 func dimMqttReason(name, reason string) string {
1180 return join("node_%s_mqtt%s", name, "reason_code", reason)
1181 }
1182
1183 func dimMqttRCode(name, rcode string) string {
1184 return join("node_%s_mqtt%s", name, "return_code", rcode)
1185 }
1186
1187 func cleanChartID(id string) string {
1188 r := strings.NewReplacer(".", "_", "'", "_", " ", "_")
1189 return r.Replace(id)
1190 }