diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-08-26 08:15:24 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-08-26 08:15:35 +0000 |
commit | f09848204fa5283d21ea43e262ee41aa578e1808 (patch) | |
tree | c62385d7adf209fa6a798635954d887f718fb3fb /src/go/plugin/go.d/modules/vernemq | |
parent | Releasing debian version 1.46.3-2. (diff) | |
download | netdata-f09848204fa5283d21ea43e262ee41aa578e1808.tar.xz netdata-f09848204fa5283d21ea43e262ee41aa578e1808.zip |
Merging upstream version 1.47.0.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/go/plugin/go.d/modules/vernemq')
l--------- | src/go/plugin/go.d/modules/vernemq/README.md | 1 | ||||
-rw-r--r-- | src/go/plugin/go.d/modules/vernemq/charts.go | 911 | ||||
-rw-r--r-- | src/go/plugin/go.d/modules/vernemq/collect.go | 288 | ||||
-rw-r--r-- | src/go/plugin/go.d/modules/vernemq/config_schema.json | 183 | ||||
-rw-r--r-- | src/go/plugin/go.d/modules/vernemq/init.go | 26 | ||||
-rw-r--r-- | src/go/plugin/go.d/modules/vernemq/integrations/vernemq.md | 332 | ||||
-rw-r--r-- | src/go/plugin/go.d/modules/vernemq/metadata.yaml | 670 | ||||
-rw-r--r-- | src/go/plugin/go.d/modules/vernemq/metrics.go | 150 | ||||
-rw-r--r-- | src/go/plugin/go.d/modules/vernemq/testdata/config.json | 20 | ||||
-rw-r--r-- | src/go/plugin/go.d/modules/vernemq/testdata/config.yaml | 17 | ||||
-rw-r--r-- | src/go/plugin/go.d/modules/vernemq/testdata/metrics-v1.10.1-mqtt5.txt | 416 | ||||
-rw-r--r-- | src/go/plugin/go.d/modules/vernemq/testdata/non_vernemq.txt | 27 | ||||
-rw-r--r-- | src/go/plugin/go.d/modules/vernemq/vernemq.go | 113 | ||||
-rw-r--r-- | src/go/plugin/go.d/modules/vernemq/vernemq_test.go | 578 |
14 files changed, 3732 insertions, 0 deletions
diff --git a/src/go/plugin/go.d/modules/vernemq/README.md b/src/go/plugin/go.d/modules/vernemq/README.md new file mode 120000 index 00000000..3d984de7 --- /dev/null +++ b/src/go/plugin/go.d/modules/vernemq/README.md @@ -0,0 +1 @@ +integrations/vernemq.md
\ No newline at end of file diff --git a/src/go/plugin/go.d/modules/vernemq/charts.go b/src/go/plugin/go.d/modules/vernemq/charts.go new file mode 100644 index 00000000..5d81a26b --- /dev/null +++ b/src/go/plugin/go.d/modules/vernemq/charts.go @@ -0,0 +1,911 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package vernemq + +import "github.com/netdata/netdata/go/plugins/plugin/go.d/agent/module" + +type ( + Charts = module.Charts + Chart = module.Chart + Dims = module.Dims + Dim = module.Dim +) + +var charts = Charts{ + chartOpenSockets.Copy(), + chartSocketEvents.Copy(), + chartClientKeepaliveExpired.Copy(), + chartSocketErrors.Copy(), + chartSocketCloseTimeout.Copy(), + + chartQueueProcesses.Copy(), + chartQueueProcessesEvents.Copy(), + chartQueueProcessesOfflineStorage.Copy(), + chartQueueMessages.Copy(), + chartQueueUndeliveredMessages.Copy(), + + chartRouterSubscriptions.Copy(), + chartRouterMatchedSubscriptions.Copy(), + chartRouterMemory.Copy(), + + chartAverageSchedulerUtilization.Copy(), + chartSchedulerUtilization.Copy(), + chartSystemProcesses.Copy(), + chartSystemReductions.Copy(), + chartSystemContextSwitches.Copy(), + chartSystemIO.Copy(), + chartSystemRunQueue.Copy(), + chartSystemGCCount.Copy(), + chartSystemGCWordsReclaimed.Copy(), + chartSystemMemoryAllocated.Copy(), + + chartBandwidth.Copy(), + + chartRetainMessages.Copy(), + chartRetainMemoryUsage.Copy(), + + chartClusterCommunicationBandwidth.Copy(), + chartClusterCommunicationDropped.Copy(), + chartNetSplitUnresolved.Copy(), + chartNetSplits.Copy(), + + chartMQTTv5AUTH.Copy(), + chartMQTTv5AUTHReceivedReason.Copy(), + chartMQTTv5AUTHSentReason.Copy(), + + chartMQTTv3v5CONNECT.Copy(), + chartMQTTv3v5CONNACKSentReason.Copy(), + + chartMQTTv3v5DISCONNECT.Copy(), + chartMQTTv5DISCONNECTReceivedReason.Copy(), + chartMQTTv5DISCONNECTSentReason.Copy(), + + chartMQTTv3v5SUBSCRIBE.Copy(), + chartMQTTv3v5SUBSCRIBEError.Copy(), + chartMQTTv3v5SUBSCRIBEAuthError.Copy(), + + chartMQTTv3v5UNSUBSCRIBE.Copy(), + chartMQTTv3v5UNSUBSCRIBEError.Copy(), + + chartMQTTv3v5PUBLISH.Copy(), + chartMQTTv3v5PUBLISHErrors.Copy(), + chartMQTTv3v5PUBLISHAuthErrors.Copy(), + chartMQTTv3v5PUBACK.Copy(), + chartMQTTv5PUBACKReceivedReason.Copy(), + chartMQTTv5PUBACKSentReason.Copy(), + chartMQTTv3v5PUBACKUnexpected.Copy(), + chartMQTTv3v5PUBREC.Copy(), + chartMQTTv5PUBRECReceivedReason.Copy(), + chartMQTTv5PUBRECSentReason.Copy(), + chartMQTTv3PUBRECUnexpected.Copy(), + chartMQTTv3v5PUBREL.Copy(), + chartMQTTv5PUBRELReceivedReason.Copy(), + chartMQTTv5PUBRELSentReason.Copy(), + chartMQTTv3v5PUBCOMP.Copy(), + chartMQTTv5PUBCOMPReceivedReason.Copy(), + chartMQTTv5PUBCOMPSentReason.Copy(), + chartMQTTv3v5PUBCOMPUnexpected.Copy(), + + chartMQTTv3v5PING.Copy(), + + chartUptime.Copy(), +} + +// Sockets +var ( + chartOpenSockets = Chart{ + ID: "sockets", + Title: "Open Sockets", + Units: "sockets", + Fam: "sockets", + Ctx: "vernemq.sockets", + Dims: Dims{ + {ID: "open_sockets", Name: "open"}, + }, + } + chartSocketEvents = Chart{ + ID: "socket_events", + Title: "Socket Open and Close Events", + Units: "events/s", + Fam: "sockets", + Ctx: "vernemq.socket_operations", + Dims: Dims{ + {ID: metricSocketOpen, Name: "open", Algo: module.Incremental}, + {ID: metricSocketClose, Name: "close", Algo: module.Incremental, Mul: -1}, + }, + } + chartClientKeepaliveExpired = Chart{ + ID: "client_keepalive_expired", + Title: "Closed Sockets due to Keepalive Time Expired", + Units: "sockets/s", + Fam: "sockets", + Ctx: "vernemq.client_keepalive_expired", + Dims: Dims{ + {ID: metricClientKeepaliveExpired, Name: "closed", Algo: module.Incremental}, + }, + } + chartSocketCloseTimeout = Chart{ + ID: "socket_close_timeout", + Title: "Closed Sockets due to no CONNECT Frame On Time", + Units: "sockets/s", + Fam: "sockets", + Ctx: "vernemq.socket_close_timeout", + Dims: Dims{ + {ID: metricSocketCloseTimeout, Name: "closed", Algo: module.Incremental}, + }, + } + chartSocketErrors = Chart{ + ID: "socket_errors", + Title: "Socket Errors", + Units: "errors/s", + Fam: "sockets", + Ctx: "vernemq.socket_errors", + Dims: Dims{ + {ID: metricSocketError, Name: "errors", Algo: module.Incremental}, + }, + } +) + +// Queues +var ( + chartQueueProcesses = Chart{ + ID: "queue_processes", + Title: "Living Queues in an Online or an Offline State", + Units: "queue processes", + Fam: "queues", + Ctx: "vernemq.queue_processes", + Dims: Dims{ + {ID: metricQueueProcesses, Name: "queue_processes"}, + }, + } + chartQueueProcessesEvents = Chart{ + ID: "queue_processes_events", + Title: "Queue Processes Setup and Teardown Events", + Units: "events/s", + Fam: "queues", + Ctx: "vernemq.queue_processes_operations", + Dims: Dims{ + {ID: metricQueueSetup, Name: "setup", Algo: module.Incremental}, + {ID: metricQueueTeardown, Name: "teardown", Algo: module.Incremental, Mul: -1}, + }, + } + chartQueueProcessesOfflineStorage = Chart{ + ID: "queue_process_init_from_storage", + Title: "Queue Processes Initialized from Offline Storage", + Units: "queue processes/s", + Fam: "queues", + Ctx: "vernemq.queue_process_init_from_storage", + Dims: Dims{ + {ID: metricQueueInitializedFromStorage, Name: "queue processes", Algo: module.Incremental}, + }, + } + chartQueueMessages = Chart{ + ID: "queue_messages", + Title: "Received and Sent PUBLISH Messages", + Units: "messages/s", + Fam: "queues", + Ctx: "vernemq.queue_messages", + Type: module.Area, + Dims: Dims{ + {ID: metricQueueMessageIn, Name: "received", Algo: module.Incremental}, + {ID: metricQueueMessageOut, Name: "sent", Algo: module.Incremental, Mul: -1}, + }, + } + chartQueueUndeliveredMessages = Chart{ + ID: "queue_undelivered_messages", + Title: "Undelivered PUBLISH Messages", + Units: "messages/s", + Fam: "queues", + Ctx: "vernemq.queue_undelivered_messages", + Type: module.Stacked, + Dims: Dims{ + {ID: metricQueueMessageDrop, Name: "dropped", Algo: module.Incremental}, + {ID: metricQueueMessageExpired, Name: "expired", Algo: module.Incremental}, + {ID: metricQueueMessageUnhandled, Name: "unhandled", Algo: module.Incremental}, + }, + } +) + +// Subscriptions +var ( + chartRouterSubscriptions = Chart{ + ID: "router_subscriptions", + Title: "Subscriptions in the Routing Table", + Units: "subscriptions", + Fam: "subscriptions", + Ctx: "vernemq.router_subscriptions", + Dims: Dims{ + {ID: metricRouterSubscriptions, Name: "subscriptions"}, + }, + } + chartRouterMatchedSubscriptions = Chart{ + ID: "router_matched_subscriptions", + Title: "Matched Subscriptions", + Units: "subscriptions/s", + Fam: "subscriptions", + Ctx: "vernemq.router_matched_subscriptions", + Dims: Dims{ + {ID: metricRouterMatchesLocal, Name: "local", Algo: module.Incremental}, + {ID: metricRouterMatchesRemote, Name: "remote", Algo: module.Incremental}, + }, + } + chartRouterMemory = Chart{ + ID: "router_memory", + Title: "Routing Table Memory Usage", + Units: "KiB", + Fam: "subscriptions", + Ctx: "vernemq.router_memory", + Type: module.Area, + Dims: Dims{ + {ID: metricRouterMemory, Name: "used", Div: 1024}, + }, + } +) + +// Erlang VM +var ( + chartAverageSchedulerUtilization = Chart{ + ID: "average_scheduler_utilization", + Title: "Average Scheduler Utilization", + Units: "percentage", + Fam: "erlang vm", + Ctx: "vernemq.average_scheduler_utilization", + Type: module.Area, + Dims: Dims{ + {ID: metricSystemUtilization, Name: "utilization"}, + }, + } + chartSchedulerUtilization = Chart{ + ID: "scheduler_utilization", + Title: "Scheduler Utilization", + Units: "percentage", + Fam: "erlang vm", + Type: module.Stacked, + Ctx: "vernemq.system_utilization_scheduler", + } + chartSystemProcesses = Chart{ + ID: "system_processes", + Title: "Erlang Processes", + Units: "processes", + Fam: "erlang vm", + Ctx: "vernemq.system_processes", + Dims: Dims{ + {ID: metricSystemProcessCount, Name: "processes"}, + }, + } + chartSystemReductions = Chart{ + ID: "system_reductions", + Title: "Reductions", + Units: "ops/s", + Fam: "erlang vm", + Ctx: "vernemq.system_reductions", + Dims: Dims{ + {ID: metricSystemReductions, Name: "reductions", Algo: module.Incremental}, + }, + } + chartSystemContextSwitches = Chart{ + ID: "system_context_switches", + Title: "Context Switches", + Units: "ops/s", + Fam: "erlang vm", + Ctx: "vernemq.system_context_switches", + Dims: Dims{ + {ID: metricSystemContextSwitches, Name: "context switches", Algo: module.Incremental}, + }, + } + chartSystemIO = Chart{ + ID: "system_io", + Title: "Received and Sent Traffic through Ports", + Units: "kilobits/s", + Fam: "erlang vm", + Ctx: "vernemq.system_io", + Type: module.Area, + Dims: Dims{ + {ID: metricSystemIOIn, Name: "received", Algo: module.Incremental, Mul: 8, Div: 1024}, + {ID: metricSystemIOOut, Name: "sent", Algo: module.Incremental, Mul: 8, Div: -1024}, + }, + } + chartSystemRunQueue = Chart{ + ID: "system_run_queue", + Title: "Processes that are Ready to Run on All Run-Queues", + Units: "processes", + Fam: "erlang vm", + Ctx: "vernemq.system_run_queue", + Dims: Dims{ + {ID: metricSystemRunQueue, Name: "ready"}, + }, + } + chartSystemGCCount = Chart{ + ID: "system_gc_count", + Title: "GC Count", + Units: "ops/s", + Fam: "erlang vm", + Ctx: "vernemq.system_gc_count", + Dims: Dims{ + {ID: metricSystemGCCount, Name: "gc", Algo: module.Incremental}, + }, + } + chartSystemGCWordsReclaimed = Chart{ + ID: "system_gc_words_reclaimed", + Title: "GC Words Reclaimed", + Units: "ops/s", + Fam: "erlang vm", + Ctx: "vernemq.system_gc_words_reclaimed", + Dims: Dims{ + {ID: metricSystemWordsReclaimedByGC, Name: "words reclaimed", Algo: module.Incremental}, + }, + } + chartSystemMemoryAllocated = Chart{ + ID: "system_allocated_memory", + Title: "Memory Allocated by the Erlang Processes and by the Emulator", + Units: "KiB", + Fam: "erlang vm", + Ctx: "vernemq.system_allocated_memory", + Type: module.Stacked, + Dims: Dims{ + {ID: metricVMMemoryProcesses, Name: "processes", Div: 1024}, + {ID: metricVMMemorySystem, Name: "system", Div: 1024}, + }, + } +) + +// Bandwidth +var ( + chartBandwidth = Chart{ + ID: "bandwidth", + Title: "Bandwidth", + Units: "kilobits/s", + Fam: "bandwidth", + Ctx: "vernemq.bandwidth", + Type: module.Area, + Dims: Dims{ + {ID: metricBytesReceived, Name: "received", Algo: module.Incremental, Mul: 8, Div: 1024}, + {ID: metricBytesSent, Name: "sent", Algo: module.Incremental, Mul: 8, Div: -1024}, + }, + } +) + +// Retain +var ( + chartRetainMessages = Chart{ + ID: "retain_messages", + Title: "Stored Retained Messages", + Units: "messages", + Fam: "retain", + Ctx: "vernemq.retain_messages", + Dims: Dims{ + {ID: metricRetainMessages, Name: "messages"}, + }, + } + chartRetainMemoryUsage = Chart{ + ID: "retain_memory", + Title: "Stored Retained Messages Memory Usage", + Units: "KiB", + Fam: "retain", + Ctx: "vernemq.retain_memory", + Type: module.Area, + Dims: Dims{ + {ID: metricRetainMemory, Name: "used", Div: 1024}, + }, + } +) + +// Cluster +var ( + chartClusterCommunicationBandwidth = Chart{ + ID: "cluster_bandwidth", + Title: "Communication with Other Cluster Nodes", + Units: "kilobits/s", + Fam: "cluster", + Ctx: "vernemq.cluster_bandwidth", + Type: module.Area, + Dims: Dims{ + {ID: metricClusterBytesReceived, Name: "received", Algo: module.Incremental, Mul: 8, Div: 1024}, + {ID: metricClusterBytesSent, Name: "sent", Algo: module.Incremental, Mul: 8, Div: -1024}, + }, + } + chartClusterCommunicationDropped = Chart{ + ID: "cluster_dropped", + Title: "Traffic Dropped During Communication with Other Cluster Nodes", + Units: "kilobits/s", + Fam: "cluster", + Type: module.Area, + Ctx: "vernemq.cluster_dropped", + Dims: Dims{ + {ID: metricClusterBytesDropped, Name: "dropped", Algo: module.Incremental, Mul: 8, Div: 1024}, + }, + } + chartNetSplitUnresolved = Chart{ + ID: "netsplit_unresolved", + Title: "Unresolved Netsplits", + Units: "netsplits", + Fam: "cluster", + Ctx: "vernemq.netsplit_unresolved", + Dims: Dims{ + {ID: "netsplit_unresolved", Name: "unresolved"}, + }, + } + chartNetSplits = Chart{ + ID: "netsplit", + Title: "Netsplits", + Units: "netsplits/s", + Fam: "cluster", + Ctx: "vernemq.netsplits", + Type: module.Stacked, + Dims: Dims{ + {ID: metricNetSplitResolved, Name: "resolved", Algo: module.Incremental}, + {ID: metricNetSplitDetected, Name: "detected", Algo: module.Incremental}, + }, + } +) + +// AUTH +var ( + chartMQTTv5AUTH = Chart{ + ID: "mqtt_auth", + Title: "v5 AUTH", + Units: "packets/s", + Fam: "mqtt auth", + Ctx: "vernemq.mqtt_auth", + Dims: Dims{ + {ID: metricAUTHReceived, Name: "received", Algo: module.Incremental}, + {ID: metricAUTHSent, Name: "sent", Algo: module.Incremental, Mul: -1}, + }, + } + chartMQTTv5AUTHReceivedReason = Chart{ + ID: "mqtt_auth_received_reason", + Title: "v5 AUTH Received by Reason", + Units: "packets/s", + Fam: "mqtt auth", + Ctx: "vernemq.mqtt_auth_received_reason", + Type: module.Stacked, + Dims: Dims{ + {ID: join(metricAUTHReceived, "success"), Name: "success", Algo: module.Incremental}, + }, + } + chartMQTTv5AUTHSentReason = Chart{ + ID: "mqtt_auth_sent_reason", + Title: "v5 AUTH Sent by Reason", + Units: "packets/s", + Fam: "mqtt auth", + Ctx: "vernemq.mqtt_auth_sent_reason", + Type: module.Stacked, + Dims: Dims{ + {ID: join(metricAUTHSent, "success"), Name: "success", Algo: module.Incremental}, + }, + } +) + +// CONNECT +var ( + chartMQTTv3v5CONNECT = Chart{ + ID: "mqtt_connect", + Title: "v3/v5 CONNECT and CONNACK", + Units: "packets/s", + Fam: "mqtt connect", + Ctx: "vernemq.mqtt_connect", + Dims: Dims{ + {ID: metricCONNECTReceived, Name: "CONNECT", Algo: module.Incremental}, + {ID: metricCONNACKSent, Name: "CONNACK", Algo: module.Incremental, Mul: -1}, + }, + } + chartMQTTv3v5CONNACKSentReason = Chart{ + ID: "mqtt_connack_sent_reason", + Title: "v3/v5 CONNACK Sent by Reason", + Units: "packets/s", + Fam: "mqtt connect", + Ctx: "vernemq.mqtt_connack_sent_reason", + Type: module.Stacked, + Dims: Dims{ + {ID: join(metricCONNACKSent, "success"), Name: "success", Algo: module.Incremental}, + }, + } +) + +// DISCONNECT +var ( + chartMQTTv3v5DISCONNECT = Chart{ + ID: "mqtt_disconnect", + Title: "v3/v5 DISCONNECT", + Units: "packets/s", + Fam: "mqtt disconnect", + Ctx: "vernemq.mqtt_disconnect", + Dims: Dims{ + {ID: metricDISCONNECTReceived, Name: "received", Algo: module.Incremental}, + {ID: metricDISCONNECTSent, Name: "sent", Algo: module.Incremental, Mul: -1}, + }, + } + chartMQTTv5DISCONNECTReceivedReason = Chart{ + ID: "mqtt_disconnect_received_reason", + Title: "v5 DISCONNECT Received by Reason", + Units: "packets/s", + Fam: "mqtt disconnect", + Ctx: "vernemq.mqtt_disconnect_received_reason", + Type: module.Stacked, + Dims: Dims{ + {ID: join(metricDISCONNECTReceived, "normal_disconnect"), Name: "normal_disconnect", Algo: module.Incremental}, + }, + } + chartMQTTv5DISCONNECTSentReason = Chart{ + ID: "mqtt_disconnect_sent_reason", + Title: "v5 DISCONNECT Sent by Reason", + Units: "packets/s", + Fam: "mqtt disconnect", + Ctx: "vernemq.mqtt_disconnect_sent_reason", + Type: module.Stacked, + Dims: Dims{ + {ID: join(metricDISCONNECTSent, "normal_disconnect"), Name: "normal_disconnect", Algo: module.Incremental}, + }, + } +) + +// SUBSCRIBE +var ( + chartMQTTv3v5SUBSCRIBE = Chart{ + ID: "mqtt_subscribe", + Title: "v3/v5 SUBSCRIBE and SUBACK", + Units: "packets/s", + Fam: "mqtt subscribe", + Ctx: "vernemq.mqtt_subscribe", + Dims: Dims{ + {ID: metricSUBSCRIBEReceived, Name: "SUBSCRIBE", Algo: module.Incremental}, + {ID: metricSUBACKSent, Name: "SUBACK", Algo: module.Incremental, Mul: -1}, + }, + } + chartMQTTv3v5SUBSCRIBEError = Chart{ + ID: "mqtt_subscribe_error", + Title: "v3/v5 Failed SUBSCRIBE Operations due to a Netsplit", + Units: "ops/s", + Fam: "mqtt subscribe", + Ctx: "vernemq.mqtt_subscribe_error", + Dims: Dims{ + {ID: metricSUBSCRIBEError, Name: "failed", Algo: module.Incremental}, + }, + } + chartMQTTv3v5SUBSCRIBEAuthError = Chart{ + ID: "mqtt_subscribe_auth_error", + Title: "v3/v5 Unauthorized SUBSCRIBE Attempts", + Units: "attempts/s", + Fam: "mqtt subscribe", + Ctx: "vernemq.mqtt_subscribe_auth_error", + Dims: Dims{ + {ID: metricSUBSCRIBEAuthError, Name: "unauth", Algo: module.Incremental}, + }, + } +) + +// UNSUBSCRIBE +var ( + chartMQTTv3v5UNSUBSCRIBE = Chart{ + ID: "mqtt_unsubscribe", + Title: "v3/v5 UNSUBSCRIBE and UNSUBACK", + Units: "packets/s", + Fam: "mqtt unsubscribe", + Ctx: "vernemq.mqtt_unsubscribe", + Dims: Dims{ + {ID: metricUNSUBSCRIBEReceived, Name: "UNSUBSCRIBE", Algo: module.Incremental}, + {ID: metricUNSUBACKSent, Name: "UNSUBACK", Algo: module.Incremental, Mul: -1}, + }, + } + chartMQTTv3v5UNSUBSCRIBEError = Chart{ + ID: "mqtt_unsubscribe_error", + Title: "v3/v5 Failed UNSUBSCRIBE Operations due to a Netsplit", + Units: "ops/s", + Fam: "mqtt unsubscribe", + Ctx: "vernemq.mqtt_unsubscribe_error", + Dims: Dims{ + {ID: metricUNSUBSCRIBEError, Name: "failed", Algo: module.Incremental}, + }, + } +) + +// PUBLISH +var ( + chartMQTTv3v5PUBLISH = Chart{ + ID: "mqtt_publish", + Title: "v3/v5 QoS 0,1,2 PUBLISH", + Units: "packets/s", + Fam: "mqtt publish", + Ctx: "vernemq.mqtt_publish", + Dims: Dims{ + {ID: metricPUBSLISHReceived, Name: "received", Algo: module.Incremental}, + {ID: metricPUBSLIHSent, Name: "sent", Algo: module.Incremental, Mul: -1}, + }, + } + chartMQTTv3v5PUBLISHErrors = Chart{ + ID: "mqtt_publish_errors", + Title: "v3/v5 Failed PUBLISH Operations due to a Netsplit", + Units: "ops/s", + Fam: "mqtt publish", + Ctx: "vernemq.mqtt_publish_errors", + Dims: Dims{ + {ID: metricPUBLISHError, Name: "failed", Algo: module.Incremental}, + }, + } + chartMQTTv3v5PUBLISHAuthErrors = Chart{ + ID: "mqtt_publish_auth_errors", + Title: "v3/v5 Unauthorized PUBLISH Attempts", + Units: "attempts/s", + Fam: "mqtt publish", + Ctx: "vernemq.mqtt_publish_auth_errors", + Type: module.Area, + Dims: Dims{ + {ID: metricPUBLISHAuthError, Name: "unauth", Algo: module.Incremental}, + }, + } + chartMQTTv3v5PUBACK = Chart{ + ID: "mqtt_puback", + Title: "v3/v5 QoS 1 PUBACK", + Units: "packets/s", + Fam: "mqtt publish", + Ctx: "vernemq.mqtt_puback", + Dims: Dims{ + {ID: metricPUBACKReceived, Name: "received", Algo: module.Incremental}, + {ID: metricPUBACKSent, Name: "sent", Algo: module.Incremental, Mul: -1}, + }, + } + chartMQTTv5PUBACKReceivedReason = Chart{ + ID: "mqtt_puback_received_reason", + Title: "v5 PUBACK QoS 1 Received by Reason", + Units: "packets/s", + Fam: "mqtt publish", + Ctx: "vernemq.mqtt_puback_received_reason", + Type: module.Stacked, + Dims: Dims{ + {ID: join(metricPUBACKReceived, "success"), Name: "success", Algo: module.Incremental}, + }, + } + chartMQTTv5PUBACKSentReason = Chart{ + ID: "mqtt_puback_sent_reason", + Title: "v5 PUBACK QoS 1 Sent by Reason", + Units: "packets/s", + Fam: "mqtt publish", + Ctx: "vernemq.mqtt_puback_sent_reason", + Type: module.Stacked, + Dims: Dims{ + {ID: join(metricPUBACKSent, "success"), Name: "success", Algo: module.Incremental}, + }, + } + chartMQTTv3v5PUBACKUnexpected = Chart{ + ID: "mqtt_puback_unexpected", + Title: "v3/v5 PUBACK QoS 1 Received Unexpected Messages", + Units: "messages/s", + Fam: "mqtt publish", + Ctx: "vernemq.mqtt_puback_invalid_error", + Dims: Dims{ + {ID: metricPUBACKInvalid, Name: "unexpected", Algo: module.Incremental}, + }, + } + chartMQTTv3v5PUBREC = Chart{ + ID: "mqtt_pubrec", + Title: "v3/v5 PUBREC QoS 2", + Units: "packets/s", + Fam: "mqtt publish", + Ctx: "vernemq.mqtt_pubrec", + Dims: Dims{ + {ID: metricPUBRECReceived, Name: "received", Algo: module.Incremental}, + {ID: metricPUBRECSent, Name: "sent", Algo: module.Incremental, Mul: -1}, + }, + } + chartMQTTv5PUBRECReceivedReason = Chart{ + ID: "mqtt_pubrec_received_reason", + Title: "v5 PUBREC QoS 2 Received by Reason", + Units: "packets/s", + Fam: "mqtt publish", + Ctx: "vernemq.mqtt_pubrec_received_reason", + Type: module.Stacked, + Dims: Dims{ + {ID: join(metricPUBRECReceived, "success"), Name: "success", Algo: module.Incremental}, + }, + } + chartMQTTv5PUBRECSentReason = Chart{ + ID: "mqtt_pubrec_sent_reason", + Title: "v5 PUBREC QoS 2 Sent by Reason", + Units: "packets/s", + Fam: "mqtt publish", + Ctx: "vernemq.mqtt_pubrec_sent_reason", + Type: module.Stacked, + Dims: Dims{ + {ID: join(metricPUBRECSent, "success"), Name: "success", Algo: module.Incremental}, + }, + } + chartMQTTv3PUBRECUnexpected = Chart{ + ID: "mqtt_pubrec_unexpected", + Title: "v3 PUBREC QoS 2 Received Unexpected Messages", + Units: "messages/s", + Fam: "mqtt publish", + Ctx: "vernemq.mqtt_pubrec_invalid_error", + Dims: Dims{ + {ID: metricPUBRECInvalid, Name: "unexpected", Algo: module.Incremental}, + }, + } + chartMQTTv3v5PUBREL = Chart{ + ID: "mqtt_pubrel", + Title: "v3/v5 PUBREL QoS 2", + Units: "packets/s", + Fam: "mqtt publish", + Ctx: "vernemq.mqtt_pubrel", + Dims: Dims{ + {ID: metricPUBRELReceived, Name: "received", Algo: module.Incremental}, + {ID: metricPUBRELSent, Name: "sent", Algo: module.Incremental, Mul: -1}, + }, + } + chartMQTTv5PUBRELReceivedReason = Chart{ + ID: "mqtt_pubrel_received_reason", + Title: "v5 PUBREL QoS 2 Received by Reason", + Units: "packets/s", + Fam: "mqtt publish", + Ctx: "vernemq.mqtt_pubrel_received_reason", + Type: module.Stacked, + Dims: Dims{ + {ID: join(metricPUBRELReceived, "success"), Name: "success", Algo: module.Incremental}, + }, + } + chartMQTTv5PUBRELSentReason = Chart{ + ID: "mqtt_pubrel_sent_reason", + Title: "v5 PUBREL QoS 2 Sent by Reason", + Units: "packets/s", + Fam: "mqtt publish", + Ctx: "vernemq.mqtt_pubrel_sent_reason", + Type: module.Stacked, + Dims: Dims{ + {ID: join(metricPUBRELSent, "success"), Name: "success", Algo: module.Incremental}, + }, + } + chartMQTTv3v5PUBCOMP = Chart{ + ID: "mqtt_pubcomp", + Title: "v3/v5 PUBCOMP QoS 2", + Units: "packets/s", + Fam: "mqtt publish", + Ctx: "vernemq.mqtt_pubcom", + Dims: Dims{ + {ID: metricPUBCOMPReceived, Name: "received", Algo: module.Incremental}, + {ID: metricPUBCOMPSent, Name: "sent", Algo: module.Incremental, Mul: -1}, + }, + } + chartMQTTv5PUBCOMPReceivedReason = Chart{ + ID: "mqtt_pubcomp_received_reason", + Title: "v5 PUBCOMP QoS 2 Received by Reason", + Units: "packets/s", + Fam: "mqtt publish", + Ctx: "vernemq.mqtt_pubcomp_received_reason", + Type: module.Stacked, + Dims: Dims{ + {ID: join(metricPUBCOMPReceived, "success"), Name: "success", Algo: module.Incremental}, + }, + } + chartMQTTv5PUBCOMPSentReason = Chart{ + ID: "mqtt_pubcomp_sent_reason", + Title: "v5 PUBCOMP QoS 2 Sent by Reason", + Units: "packets/s", + Fam: "mqtt publish", + Ctx: "vernemq.mqtt_pubcomp_sent_reason", + Type: module.Stacked, + Dims: Dims{ + {ID: join(metricPUBCOMPSent, "success"), Name: "success", Algo: module.Incremental}, + }, + } + chartMQTTv3v5PUBCOMPUnexpected = Chart{ + ID: "mqtt_pubcomp_unexpected", + Title: "v3/v5 PUBCOMP QoS 2 Received Unexpected Messages", + Units: "messages/s", + Fam: "mqtt publish", + Ctx: "vernemq.mqtt_pubcomp_invalid_error", + Dims: Dims{ + {ID: metricPUNCOMPInvalid, Name: "unexpected", Algo: module.Incremental}, + }, + } +) + +// PING +var ( + chartMQTTv3v5PING = Chart{ + ID: "mqtt_ping", + Title: "v3/v5 PING", + Units: "packets/s", + Fam: "mqtt ping", + Ctx: "vernemq.mqtt_ping", + Dims: Dims{ + {ID: metricPINGREQReceived, Name: "PINGREQ", Algo: module.Incremental}, + {ID: metricPINGRESPSent, Name: "PINGRESP", Algo: module.Incremental, Mul: -1}, + }, + } +) + +var ( + chartUptime = Chart{ + ID: "node_uptime", + Title: "Node Uptime", + Units: "seconds", + Fam: "uptime", + Ctx: "vernemq.node_uptime", + Dims: Dims{ + {ID: metricSystemWallClock, Name: "time", Div: 1000}, + }, + } +) + +func (v *VerneMQ) notifyNewScheduler(name string) { + if v.cache[name] { + return + } + v.cache[name] = true + + id := chartSchedulerUtilization.ID + num := name[len("system_utilization_scheduler_"):] + + v.addAbsDimToChart(id, name, num) +} + +func (v *VerneMQ) notifyNewReason(name, reason string) { + if reason == "success" || reason == "normal_disconnect" { + return + } + key := join(name, reason) + if v.cache[key] { + return + } + v.cache[key] = true + + var chart Chart + switch name { + case metricAUTHReceived: + chart = chartMQTTv5AUTHReceivedReason + case metricAUTHSent: + chart = chartMQTTv5AUTHSentReason + case metricCONNACKSent: + chart = chartMQTTv3v5CONNACKSentReason + case metricDISCONNECTReceived: + chart = chartMQTTv5DISCONNECTReceivedReason + case metricDISCONNECTSent: + chart = chartMQTTv5DISCONNECTSentReason + case metricPUBACKReceived: + chart = chartMQTTv5PUBACKReceivedReason + case metricPUBACKSent: + chart = chartMQTTv5PUBACKSentReason + case metricPUBRECReceived: + chart = chartMQTTv5PUBRECReceivedReason + case metricPUBRECSent: + chart = chartMQTTv5PUBRECSentReason + case metricPUBRELReceived: + chart = chartMQTTv5PUBRELReceivedReason + case metricPUBRELSent: + chart = chartMQTTv5PUBRELSentReason + case metricPUBCOMPReceived: + chart = chartMQTTv5PUBCOMPReceivedReason + case metricPUBCOMPSent: + chart = chartMQTTv5PUBCOMPSentReason + default: + v.Warningf("unknown metric name, wont be added to the charts: '%s'", name) + return + } + + v.addIncDimToChart(chart.ID, key, reason) +} + +func (v *VerneMQ) addAbsDimToChart(chartID, dimID, dimName string) { + v.addDimToChart(chartID, dimID, dimName, false) +} + +func (v *VerneMQ) addIncDimToChart(chartID, dimID, dimName string) { + v.addDimToChart(chartID, dimID, dimName, true) +} + +func (v *VerneMQ) addDimToChart(chartID, dimID, dimName string, inc bool) { + chart := v.Charts().Get(chartID) + if chart == nil { + v.Warningf("add '%s' dim: couldn't find '%s' chart", dimID, chartID) + return + } + + dim := &Dim{ID: dimID, Name: dimName} + if inc { + dim.Algo = module.Incremental + } + + if err := chart.AddDim(dim); err != nil { + v.Warningf("add '%s' dim: %v", dimID, err) + return + } + chart.MarkNotCreated() +} diff --git a/src/go/plugin/go.d/modules/vernemq/collect.go b/src/go/plugin/go.d/modules/vernemq/collect.go new file mode 100644 index 00000000..c6fb3ecb --- /dev/null +++ b/src/go/plugin/go.d/modules/vernemq/collect.go @@ -0,0 +1,288 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package vernemq + +import ( + "errors" + "strings" + + "github.com/netdata/netdata/go/plugins/plugin/go.d/pkg/prometheus" + "github.com/netdata/netdata/go/plugins/plugin/go.d/pkg/stm" +) + +func isValidVerneMQMetrics(pms prometheus.Series) bool { + return pms.FindByName(metricPUBLISHError).Len() > 0 && pms.FindByName(metricRouterSubscriptions).Len() > 0 +} + +func (v *VerneMQ) collect() (map[string]int64, error) { + pms, err := v.prom.ScrapeSeries() + if err != nil { + return nil, err + } + + if !isValidVerneMQMetrics(pms) { + return nil, errors.New("returned metrics aren't VerneMQ metrics") + } + + mx := v.collectVerneMQ(pms) + + return stm.ToMap(mx), nil +} + +func (v *VerneMQ) collectVerneMQ(pms prometheus.Series) map[string]float64 { + mx := make(map[string]float64) + collectSockets(mx, pms) + collectQueues(mx, pms) + collectSubscriptions(mx, pms) + v.collectErlangVM(mx, pms) + collectBandwidth(mx, pms) + collectRetain(mx, pms) + collectCluster(mx, pms) + collectUptime(mx, pms) + + v.collectAUTH(mx, pms) + v.collectCONNECT(mx, pms) + v.collectDISCONNECT(mx, pms) + v.collectSUBSCRIBE(mx, pms) + v.collectUNSUBSCRIBE(mx, pms) + v.collectPUBLISH(mx, pms) + v.collectPING(mx, pms) + v.collectMQTTInvalidMsgSize(mx, pms) + return mx +} + +func (v *VerneMQ) collectCONNECT(mx map[string]float64, pms prometheus.Series) { + pms = pms.FindByNames( + metricCONNECTReceived, + metricCONNACKSent, + ) + v.collectMQTT(mx, pms) +} + +func (v *VerneMQ) collectDISCONNECT(mx map[string]float64, pms prometheus.Series) { + pms = pms.FindByNames( + metricDISCONNECTReceived, + metricDISCONNECTSent, + ) + v.collectMQTT(mx, pms) +} + +func (v *VerneMQ) collectPUBLISH(mx map[string]float64, pms prometheus.Series) { + pms = pms.FindByNames( + metricPUBACKReceived, + metricPUBACKSent, + metricPUBACKInvalid, + + metricPUBCOMPReceived, + metricPUBCOMPSent, + metricPUNCOMPInvalid, + + metricPUBSLISHReceived, + metricPUBSLIHSent, + metricPUBLISHError, + metricPUBLISHAuthError, + + metricPUBRECReceived, + metricPUBRECSent, + metricPUBRECInvalid, + + metricPUBRELReceived, + metricPUBRELSent, + ) + v.collectMQTT(mx, pms) +} + +func (v *VerneMQ) collectSUBSCRIBE(mx map[string]float64, pms prometheus.Series) { + pms = pms.FindByNames( + metricSUBSCRIBEReceived, + metricSUBACKSent, + metricSUBSCRIBEError, + metricSUBSCRIBEAuthError, + ) + v.collectMQTT(mx, pms) +} + +func (v *VerneMQ) collectUNSUBSCRIBE(mx map[string]float64, pms prometheus.Series) { + pms = pms.FindByNames( + metricUNSUBSCRIBEReceived, + metricUNSUBACKSent, + metricUNSUBSCRIBEError, + ) + v.collectMQTT(mx, pms) +} + +func (v *VerneMQ) collectPING(mx map[string]float64, pms prometheus.Series) { + pms = pms.FindByNames( + metricPINGREQReceived, + metricPINGRESPSent, + ) + v.collectMQTT(mx, pms) +} + +func (v *VerneMQ) collectAUTH(mx map[string]float64, pms prometheus.Series) { + pms = pms.FindByNames( + metricAUTHReceived, + metricAUTHSent, + ) + v.collectMQTT(mx, pms) +} + +func (v *VerneMQ) collectMQTTInvalidMsgSize(mx map[string]float64, pms prometheus.Series) { + pms = pms.FindByName(metricMQTTInvalidMsgSizeError) + v.collectMQTT(mx, pms) +} + +func collectSockets(mx map[string]float64, pms prometheus.Series) { + pms = pms.FindByNames( + metricSocketClose, + metricSocketCloseTimeout, + metricSocketError, + metricSocketOpen, + metricClientKeepaliveExpired, + ) + collectNonMQTT(mx, pms) + mx["open_sockets"] = mx[metricSocketOpen] - mx[metricSocketClose] +} + +func collectQueues(mx map[string]float64, pms prometheus.Series) { + pms = pms.FindByNames( + metricQueueInitializedFromStorage, + metricQueueMessageDrop, + metricQueueMessageExpired, + metricQueueMessageIn, + metricQueueMessageOut, + metricQueueMessageUnhandled, + metricQueueProcesses, + metricQueueSetup, + metricQueueTeardown, + ) + collectNonMQTT(mx, pms) +} + +func collectSubscriptions(mx map[string]float64, pms prometheus.Series) { + pms = pms.FindByNames( + metricRouterMatchesLocal, + metricRouterMatchesRemote, + metricRouterMemory, + metricRouterSubscriptions, + ) + collectNonMQTT(mx, pms) +} + +func (v *VerneMQ) collectErlangVM(mx map[string]float64, pms prometheus.Series) { + v.collectSchedulersUtilization(mx, pms) + pms = pms.FindByNames( + metricSystemContextSwitches, + metricSystemGCCount, + metricSystemIOIn, + metricSystemIOOut, + metricSystemProcessCount, + metricSystemReductions, + metricSystemRunQueue, + metricSystemUtilization, + metricSystemWordsReclaimedByGC, + metricVMMemoryProcesses, + metricVMMemorySystem, + ) + collectNonMQTT(mx, pms) +} + +func (v *VerneMQ) collectSchedulersUtilization(mx map[string]float64, pms prometheus.Series) { + for _, pm := range pms { + if isSchedulerUtilizationMetric(pm) { + mx[pm.Name()] += pm.Value + v.notifyNewScheduler(pm.Name()) + } + } +} + +func collectBandwidth(mx map[string]float64, pms prometheus.Series) { + pms = pms.FindByNames( + metricBytesReceived, + metricBytesSent, + ) + collectNonMQTT(mx, pms) +} + +func collectRetain(mx map[string]float64, pms prometheus.Series) { + pms = pms.FindByNames( + metricRetainMemory, + metricRetainMessages, + ) + collectNonMQTT(mx, pms) +} + +func collectCluster(mx map[string]float64, pms prometheus.Series) { + pms = pms.FindByNames( + metricClusterBytesDropped, + metricClusterBytesReceived, + metricClusterBytesSent, + metricNetSplitDetected, + metricNetSplitResolved, + ) + collectNonMQTT(mx, pms) + mx["netsplit_unresolved"] = mx[metricNetSplitDetected] - mx[metricNetSplitResolved] +} + +func collectUptime(mx map[string]float64, pms prometheus.Series) { + pms = pms.FindByName(metricSystemWallClock) + collectNonMQTT(mx, pms) +} + +func collectNonMQTT(mx map[string]float64, pms prometheus.Series) { + for _, pm := range pms { + mx[pm.Name()] += pm.Value + } +} + +func (v *VerneMQ) collectMQTT(mx map[string]float64, pms prometheus.Series) { + for _, pm := range pms { + if !isMQTTMetric(pm) { + continue + } + version := versionLabelValue(pm) + if version == "" { + continue + } + + mx[pm.Name()] += pm.Value + mx[join(pm.Name(), "v", version)] += pm.Value + + if reason := reasonCodeLabelValue(pm); reason != "" { + mx[join(pm.Name(), reason)] += pm.Value + mx[join(pm.Name(), "v", version, reason)] += pm.Value + + v.notifyNewReason(pm.Name(), reason) + } + } +} + +func isMQTTMetric(pm prometheus.SeriesSample) bool { + return strings.HasPrefix(pm.Name(), "mqtt_") +} + +func isSchedulerUtilizationMetric(pm prometheus.SeriesSample) bool { + return strings.HasPrefix(pm.Name(), "system_utilization_scheduler_") +} + +func reasonCodeLabelValue(pm prometheus.SeriesSample) string { + if v := pm.Labels.Get("reason_code"); v != "" { + return v + } + // "mqtt_connack_sent" v4 has return_code + return pm.Labels.Get("return_code") +} + +func versionLabelValue(pm prometheus.SeriesSample) string { + return pm.Labels.Get("mqtt_version") +} + +func join(a, b string, rest ...string) string { + v := a + "_" + b + switch len(rest) { + case 0: + return v + default: + return join(v, rest[0], rest[1:]...) + } +} diff --git a/src/go/plugin/go.d/modules/vernemq/config_schema.json b/src/go/plugin/go.d/modules/vernemq/config_schema.json new file mode 100644 index 00000000..092d7f41 --- /dev/null +++ b/src/go/plugin/go.d/modules/vernemq/config_schema.json @@ -0,0 +1,183 @@ +{ + "jsonSchema": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "VerneMQ collector configuration.", + "type": "object", + "properties": { + "update_every": { + "title": "Update every", + "description": "Data collection interval, measured in seconds.", + "type": "integer", + "minimum": 1, + "default": 1 + }, + "url": { + "title": "URL", + "description": "The URL of the VerneMQ [metrics endpoint](https://docs.vernemq.com/monitoring/prometheus).", + "type": "string", + "default": "http://127.0.0.1:8888/metrics", + "format": "uri" + }, + "timeout": { + "title": "Timeout", + "description": "The timeout in seconds for the HTTP request.", + "type": "number", + "minimum": 0.5, + "default": 1 + }, + "not_follow_redirects": { + "title": "Not follow redirects", + "description": "If set, the client will not follow HTTP redirects automatically.", + "type": "boolean" + }, + "username": { + "title": "Username", + "description": "The username for basic authentication.", + "type": "string", + "sensitive": true + }, + "password": { + "title": "Password", + "description": "The password for basic authentication.", + "type": "string", + "sensitive": true + }, + "proxy_url": { + "title": "Proxy URL", + "description": "The URL of the proxy server.", + "type": "string" + }, + "proxy_username": { + "title": "Proxy username", + "description": "The username for proxy authentication.", + "type": "string", + "sensitive": true + }, + "proxy_password": { + "title": "Proxy password", + "description": "The password for proxy authentication.", + "type": "string", + "sensitive": true + }, + "headers": { + "title": "Headers", + "description": "Additional HTTP headers to include in the request.", + "type": [ + "object", + "null" + ], + "additionalProperties": { + "type": "string" + } + }, + "tls_skip_verify": { + "title": "Skip TLS verification", + "description": "If set, TLS certificate verification will be skipped.", + "type": "boolean" + }, + "tls_ca": { + "title": "TLS CA", + "description": "The path to the CA certificate file for TLS verification.", + "type": "string", + "pattern": "^$|^/" + }, + "tls_cert": { + "title": "TLS certificate", + "description": "The path to the client certificate file for TLS authentication.", + "type": "string", + "pattern": "^$|^/" + }, + "tls_key": { + "title": "TLS key", + "description": "The path to the client key file for TLS authentication.", + "type": "string", + "pattern": "^$|^/" + }, + "body": { + "title": "Body", + "type": "string" + }, + "method": { + "title": "Method", + "type": "string" + } + }, + "required": [ + "url" + ], + "additionalProperties": false, + "patternProperties": { + "^name$": {} + } + }, + "uiSchema": { + "ui:flavour": "tabs", + "ui:options": { + "tabs": [ + { + "title": "Base", + "fields": [ + "update_every", + "url", + "timeout", + "not_follow_redirects" + ] + }, + { + "title": "Auth", + "fields": [ + "username", + "password" + ] + }, + { + "title": "TLS", + "fields": [ + "tls_skip_verify", + "tls_ca", + "tls_cert", + "tls_key" + ] + }, + { + "title": "Proxy", + "fields": [ + "proxy_url", + "proxy_username", + "proxy_password" + ] + }, + { + "title": "Headers", + "fields": [ + "headers" + ] + } + ] + }, + "uiOptions": { + "fullPage": true + }, + "body": { + "ui:widget": "hidden" + }, + "method": { + "ui:widget": "hidden" + }, + "timeout": { + "ui:help": "Accepts decimals for precise control (e.g., type 1.5 for 1.5 seconds)." + }, + "username": { + "ui:widget": "password" + }, + "proxy_username": { + "ui:widget": "password" + }, + "password": { + "ui:widget": "password" + }, + "proxy_password": { + "ui:widget": "password" + } + } +} diff --git a/src/go/plugin/go.d/modules/vernemq/init.go b/src/go/plugin/go.d/modules/vernemq/init.go new file mode 100644 index 00000000..64ed3418 --- /dev/null +++ b/src/go/plugin/go.d/modules/vernemq/init.go @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package vernemq + +import ( + "errors" + + "github.com/netdata/netdata/go/plugins/plugin/go.d/pkg/prometheus" + "github.com/netdata/netdata/go/plugins/plugin/go.d/pkg/web" +) + +func (v *VerneMQ) validateConfig() error { + if v.URL == "" { + return errors.New("url is not set") + } + return nil +} + +func (v *VerneMQ) initPrometheusClient() (prometheus.Prometheus, error) { + client, err := web.NewHTTPClient(v.Client) + if err != nil { + return nil, err + } + + return prometheus.New(client, v.Request), nil +} diff --git a/src/go/plugin/go.d/modules/vernemq/integrations/vernemq.md b/src/go/plugin/go.d/modules/vernemq/integrations/vernemq.md new file mode 100644 index 00000000..f3b4c287 --- /dev/null +++ b/src/go/plugin/go.d/modules/vernemq/integrations/vernemq.md @@ -0,0 +1,332 @@ +<!--startmeta +custom_edit_url: "https://github.com/netdata/netdata/edit/master/src/go/plugin/go.d/modules/vernemq/README.md" +meta_yaml: "https://github.com/netdata/netdata/edit/master/src/go/plugin/go.d/modules/vernemq/metadata.yaml" +sidebar_label: "VerneMQ" +learn_status: "Published" +learn_rel_path: "Collecting Metrics/Message Brokers" +most_popular: False +message: "DO NOT EDIT THIS FILE DIRECTLY, IT IS GENERATED BY THE COLLECTOR'S metadata.yaml FILE" +endmeta--> + +# VerneMQ + + +<img src="https://netdata.cloud/img/vernemq.svg" width="150"/> + + +Plugin: go.d.plugin +Module: vernemq + +<img src="https://img.shields.io/badge/maintained%20by-Netdata-%2300ab44" /> + +## Overview + +This collector monitors VerneMQ instances. + + + + +This collector is supported on all platforms. + +This collector supports collecting metrics from multiple instances of this integration, including remote instances. + + +### Default Behavior + +#### Auto-Detection + +This integration doesn't support auto-detection. + +#### Limits + +The default configuration for this integration does not impose any limits on data collection. + +#### Performance Impact + +The default configuration for this integration is not expected to impose a significant performance impact on the system. + + +## Metrics + +Metrics grouped by *scope*. + +The scope defines the instance that the metric belongs to. An instance is uniquely identified by a set of labels. + + + +### Per VerneMQ instance + +These metrics refer to the entire monitored application. + +This scope has no labels. + +Metrics: + +| Metric | Dimensions | Unit | +|:------|:----------|:----| +| vernemq.sockets | open | sockets | +| vernemq.socket_operations | open, close | sockets/s | +| vernemq.client_keepalive_expired | closed | sockets/s | +| vernemq.socket_close_timeout | closed | sockets/s | +| vernemq.socket_errors | errors | errors/s | +| vernemq.queue_processes | queue_processes | queue processes | +| vernemq.queue_processes_operations | setup, teardown | events/s | +| vernemq.queue_process_init_from_storage | queue_processes | queue processes/s | +| vernemq.queue_messages | received, sent | messages/s | +| vernemq.queue_undelivered_messages | dropped, expired, unhandled | messages/s | +| vernemq.router_subscriptions | subscriptions | subscriptions | +| vernemq.router_matched_subscriptions | local, remote | subscriptions/s | +| vernemq.router_memory | used | KiB | +| vernemq.average_scheduler_utilization | utilization | percentage | +| vernemq.system_utilization_scheduler | a dimension per scheduler | percentage | +| vernemq.system_processes | processes | processes | +| vernemq.system_reductions | reductions | ops/s | +| vernemq.system_context_switches | context_switches | ops/s | +| vernemq.system_io | received, sent | kilobits/s | +| vernemq.system_run_queue | ready | processes | +| vernemq.system_gc_count | gc | ops/s | +| vernemq.system_gc_words_reclaimed | words_reclaimed | ops/s | +| vernemq.system_allocated_memory | processes, system | KiB | +| vernemq.bandwidth | received, sent | kilobits/s | +| vernemq.retain_messages | messages | messages | +| vernemq.retain_memory | used | KiB | +| vernemq.cluster_bandwidth | received, sent | kilobits/s | +| vernemq.cluster_dropped | dropped | kilobits/s | +| vernemq.netsplit_unresolved | unresolved | netsplits | +| vernemq.netsplits | resolved, detected | netsplits/s | +| vernemq.mqtt_auth | received, sent | packets/s | +| vernemq.mqtt_auth_received_reason | a dimensions per reason | packets/s | +| vernemq.mqtt_auth_sent_reason | a dimensions per reason | packets/s | +| vernemq.mqtt_connect | connect, connack | packets/s | +| vernemq.mqtt_connack_sent_reason | a dimensions per reason | packets/s | +| vernemq.mqtt_disconnect | received, sent | packets/s | +| vernemq.mqtt_disconnect_received_reason | a dimensions per reason | packets/s | +| vernemq.mqtt_disconnect_sent_reason | a dimensions per reason | packets/s | +| vernemq.mqtt_subscribe | subscribe, suback | packets/s | +| vernemq.mqtt_subscribe_error | failed | ops/s | +| vernemq.mqtt_subscribe_auth_error | unauth | attempts/s | +| vernemq.mqtt_unsubscribe | unsubscribe, unsuback | packets/s | +| vernemq.mqtt_unsubscribe_error | mqtt_unsubscribe_error | ops/s | +| vernemq.mqtt_publish | received, sent | packets/s | +| vernemq.mqtt_publish_errors | failed | ops/s | +| vernemq.mqtt_publish_auth_errors | unauth | attempts/s | +| vernemq.mqtt_puback | received, sent | packets/s | +| vernemq.mqtt_puback_received_reason | a dimensions per reason | packets/s | +| vernemq.mqtt_puback_sent_reason | a dimensions per reason | packets/s | +| vernemq.mqtt_puback_invalid_error | unexpected | messages/s | +| vernemq.mqtt_pubrec | received, sent | packets/s | +| vernemq.mqtt_pubrec_received_reason | a dimensions per reason | packets/s | +| vernemq.mqtt_pubrec_sent_reason | a dimensions per reason | packets/s | +| vernemq.mqtt_pubrec_invalid_error | unexpected | messages/s | +| vernemq.mqtt_pubrel | received, sent | packets/s | +| vernemq.mqtt_pubrel_received_reason | a dimensions per reason | packets/s | +| vernemq.mqtt_pubrel_sent_reason | a dimensions per reason | packets/s | +| vernemq.mqtt_pubcom | received, sent | packets/s | +| vernemq.mqtt_pubcomp_received_reason | a dimensions per reason | packets/s | +| vernemq.mqtt_pubcomp_sent_reason | a dimensions per reason | packets/s | +| vernemq.mqtt_pubcomp_invalid_error | unexpected | messages/s | +| vernemq.mqtt_ping | pingreq, pingresp | packets/s | +| vernemq.node_uptime | time | seconds | + + + +## Alerts + + +The following alerts are available: + +| Alert name | On metric | Description | +|:------------|:----------|:------------| +| [ vernemq_socket_errors ](https://github.com/netdata/netdata/blob/master/src/health/health.d/vernemq.conf) | vernemq.socket_errors | number of socket errors in the last minute | +| [ vernemq_queue_message_drop ](https://github.com/netdata/netdata/blob/master/src/health/health.d/vernemq.conf) | vernemq.queue_undelivered_messages | number of dropped messaged due to full queues in the last minute | +| [ vernemq_queue_message_expired ](https://github.com/netdata/netdata/blob/master/src/health/health.d/vernemq.conf) | vernemq.queue_undelivered_messages | number of messages which expired before delivery in the last minute | +| [ vernemq_queue_message_unhandled ](https://github.com/netdata/netdata/blob/master/src/health/health.d/vernemq.conf) | vernemq.queue_undelivered_messages | number of unhandled messages (connections with clean session=true) in the last minute | +| [ vernemq_average_scheduler_utilization ](https://github.com/netdata/netdata/blob/master/src/health/health.d/vernemq.conf) | vernemq.average_scheduler_utilization | average scheduler utilization over the last 10 minutes | +| [ vernemq_cluster_dropped ](https://github.com/netdata/netdata/blob/master/src/health/health.d/vernemq.conf) | vernemq.cluster_dropped | amount of traffic dropped during communication with the cluster nodes in the last minute | +| [ vernemq_netsplits ](https://github.com/netdata/netdata/blob/master/src/health/health.d/vernemq.conf) | vvernemq.netsplits | number of detected netsplits (split brain situation) in the last minute | +| [ vernemq_mqtt_connack_sent_reason_unsuccessful ](https://github.com/netdata/netdata/blob/master/src/health/health.d/vernemq.conf) | vernemq.mqtt_connack_sent_reason | number of sent unsuccessful v3/v5 CONNACK packets in the last minute | +| [ vernemq_mqtt_disconnect_received_reason_not_normal ](https://github.com/netdata/netdata/blob/master/src/health/health.d/vernemq.conf) | vernemq.mqtt_disconnect_received_reason | number of received not normal v5 DISCONNECT packets in the last minute | +| [ vernemq_mqtt_disconnect_sent_reason_not_normal ](https://github.com/netdata/netdata/blob/master/src/health/health.d/vernemq.conf) | vernemq.mqtt_disconnect_sent_reason | number of sent not normal v5 DISCONNECT packets in the last minute | +| [ vernemq_mqtt_subscribe_error ](https://github.com/netdata/netdata/blob/master/src/health/health.d/vernemq.conf) | vernemq.mqtt_subscribe_error | number of failed v3/v5 SUBSCRIBE operations in the last minute | +| [ vernemq_mqtt_subscribe_auth_error ](https://github.com/netdata/netdata/blob/master/src/health/health.d/vernemq.conf) | vernemq.mqtt_subscribe_auth_error | number of unauthorized v3/v5 SUBSCRIBE attempts in the last minute | +| [ vernemq_mqtt_unsubscribe_error ](https://github.com/netdata/netdata/blob/master/src/health/health.d/vernemq.conf) | vernemq.mqtt_unsubscribe_error | number of failed v3/v5 UNSUBSCRIBE operations in the last minute | +| [ vernemq_mqtt_publish_errors ](https://github.com/netdata/netdata/blob/master/src/health/health.d/vernemq.conf) | vernemq.mqtt_publish_errors | number of failed v3/v5 PUBLISH operations in the last minute | +| [ vernemq_mqtt_publish_auth_errors ](https://github.com/netdata/netdata/blob/master/src/health/health.d/vernemq.conf) | vernemq.mqtt_publish_auth_errors | number of unauthorized v3/v5 PUBLISH attempts in the last minute | +| [ vernemq_mqtt_puback_received_reason_unsuccessful ](https://github.com/netdata/netdata/blob/master/src/health/health.d/vernemq.conf) | vernemq.mqtt_puback_received_reason | number of received unsuccessful v5 PUBACK packets in the last minute | +| [ vernemq_mqtt_puback_sent_reason_unsuccessful ](https://github.com/netdata/netdata/blob/master/src/health/health.d/vernemq.conf) | vernemq.mqtt_puback_sent_reason | number of sent unsuccessful v5 PUBACK packets in the last minute | +| [ vernemq_mqtt_puback_unexpected ](https://github.com/netdata/netdata/blob/master/src/health/health.d/vernemq.conf) | vernemq.mqtt_puback_invalid_error | number of received unexpected v3/v5 PUBACK packets in the last minute | +| [ vernemq_mqtt_pubrec_received_reason_unsuccessful ](https://github.com/netdata/netdata/blob/master/src/health/health.d/vernemq.conf) | vernemq.mqtt_pubrec_received_reason | number of received unsuccessful v5 PUBREC packets in the last minute | +| [ vernemq_mqtt_pubrec_sent_reason_unsuccessful ](https://github.com/netdata/netdata/blob/master/src/health/health.d/vernemq.conf) | vernemq.mqtt_pubrec_sent_reason | number of sent unsuccessful v5 PUBREC packets in the last minute | +| [ vernemq_mqtt_pubrec_invalid_error ](https://github.com/netdata/netdata/blob/master/src/health/health.d/vernemq.conf) | vernemq.mqtt_pubrec_invalid_error | number of received unexpected v3 PUBREC packets in the last minute | +| [ vernemq_mqtt_pubrel_received_reason_unsuccessful ](https://github.com/netdata/netdata/blob/master/src/health/health.d/vernemq.conf) | vernemq.mqtt_pubrel_received_reason | number of received unsuccessful v5 PUBREL packets in the last minute | +| [ vernemq_mqtt_pubrel_sent_reason_unsuccessful ](https://github.com/netdata/netdata/blob/master/src/health/health.d/vernemq.conf) | vernemq.mqtt_pubrel_sent_reason | number of sent unsuccessful v5 PUBREL packets in the last minute | +| [ vernemq_mqtt_pubcomp_received_reason_unsuccessful ](https://github.com/netdata/netdata/blob/master/src/health/health.d/vernemq.conf) | vernemq.mqtt_pubcomp_received_reason | number of received unsuccessful v5 PUBCOMP packets in the last minute | +| [ vernemq_mqtt_pubcomp_sent_reason_unsuccessful ](https://github.com/netdata/netdata/blob/master/src/health/health.d/vernemq.conf) | vernemq.mqtt_pubcomp_sent_reason | number of sent unsuccessful v5 PUBCOMP packets in the last minute | +| [ vernemq_mqtt_pubcomp_unexpected ](https://github.com/netdata/netdata/blob/master/src/health/health.d/vernemq.conf) | vernemq.mqtt_pubcomp_invalid_error | number of received unexpected v3/v5 PUBCOMP packets in the last minute | + + +## Setup + +### Prerequisites + +No action required. + +### Configuration + +#### File + +The configuration file name for this integration is `go.d/vernemq.conf`. + + +You can edit the configuration file using the `edit-config` script from the +Netdata [config directory](/docs/netdata-agent/configuration/README.md#the-netdata-config-directory). + +```bash +cd /etc/netdata 2>/dev/null || cd /opt/netdata/etc/netdata +sudo ./edit-config go.d/vernemq.conf +``` +#### Options + +The following options can be defined globally: update_every, autodetection_retry. + + +<details open><summary>Config options</summary> + +| Name | Description | Default | Required | +|:----|:-----------|:-------|:--------:| +| update_every | Data collection frequency. | 1 | no | +| autodetection_retry | Recheck interval in seconds. Zero means no recheck will be scheduled. | 0 | no | +| url | Server URL. | http://127.0.0.1:8888/metrics | yes | +| timeout | HTTP request timeout. | 1 | no | +| username | Username for basic HTTP authentication. | | no | +| password | Password for basic HTTP authentication. | | no | +| proxy_url | Proxy URL. | | no | +| proxy_username | Username for proxy basic HTTP authentication. | | no | +| proxy_password | Password for proxy basic HTTP authentication. | | no | +| method | HTTP request method. | GET | no | +| body | HTTP request body. | | no | +| headers | HTTP request headers. | | no | +| not_follow_redirects | Redirect handling policy. Controls whether the client follows redirects. | no | no | +| tls_skip_verify | Server certificate chain and hostname validation policy. Controls whether the client performs this check. | no | no | +| tls_ca | Certification authority that the client uses when verifying the server's certificates. | | no | +| tls_cert | Client TLS certificate. | | no | +| tls_key | Client TLS key. | | no | + +</details> + +#### Examples + +##### Basic + +An example configuration. + +<details open><summary>Config</summary> + +```yaml +jobs: + - name: local + url: http://127.0.0.1:8888/metrics + +``` +</details> + +##### HTTP authentication + +Local instance with basic HTTP authentication. + +<details open><summary>Config</summary> + +```yaml +jobs: + - name: local + url: http://127.0.0.1:8888/metrics + username: username + password: password + +``` +</details> + +##### Multi-instance + +> **Note**: When you define multiple jobs, their names must be unique. + +Local and remote instances. + + +<details open><summary>Config</summary> + +```yaml +jobs: + - name: local + url: http://127.0.0.1:8888/metrics + + - name: remote + url: http://203.0.113.10:8888/metrics + +``` +</details> + + + +## Troubleshooting + +### Debug Mode + +**Important**: Debug mode is not supported for data collection jobs created via the UI using the Dyncfg feature. + +To troubleshoot issues with the `vernemq` collector, run the `go.d.plugin` with the debug option enabled. The output +should give you clues as to why the collector isn't working. + +- Navigate to the `plugins.d` directory, usually at `/usr/libexec/netdata/plugins.d/`. If that's not the case on + your system, open `netdata.conf` and look for the `plugins` setting under `[directories]`. + + ```bash + cd /usr/libexec/netdata/plugins.d/ + ``` + +- Switch to the `netdata` user. + + ```bash + sudo -u netdata -s + ``` + +- Run the `go.d.plugin` to debug the collector: + + ```bash + ./go.d.plugin -d -m vernemq + ``` + +### Getting Logs + +If you're encountering problems with the `vernemq` collector, follow these steps to retrieve logs and identify potential issues: + +- **Run the command** specific to your system (systemd, non-systemd, or Docker container). +- **Examine the output** for any warnings or error messages that might indicate issues. These messages should provide clues about the root cause of the problem. + +#### System with systemd + +Use the following command to view logs generated since the last Netdata service restart: + +```bash +journalctl _SYSTEMD_INVOCATION_ID="$(systemctl show --value --property=InvocationID netdata)" --namespace=netdata --grep vernemq +``` + +#### System without systemd + +Locate the collector log file, typically at `/var/log/netdata/collector.log`, and use `grep` to filter for collector's name: + +```bash +grep vernemq /var/log/netdata/collector.log +``` + +**Note**: This method shows logs from all restarts. Focus on the **latest entries** for troubleshooting current issues. + +#### Docker Container + +If your Netdata runs in a Docker container named "netdata" (replace if different), use this command: + +```bash +docker logs netdata 2>&1 | grep vernemq +``` + + diff --git a/src/go/plugin/go.d/modules/vernemq/metadata.yaml b/src/go/plugin/go.d/modules/vernemq/metadata.yaml new file mode 100644 index 00000000..2ec25fb7 --- /dev/null +++ b/src/go/plugin/go.d/modules/vernemq/metadata.yaml @@ -0,0 +1,670 @@ +plugin_name: go.d.plugin +modules: + - meta: + id: collector-go.d.plugin-vernemq + plugin_name: go.d.plugin + module_name: vernemq + monitored_instance: + name: VerneMQ + link: https://vernemq.com + icon_filename: vernemq.svg + categories: + - data-collection.message-brokers + keywords: + - vernemq + - message brokers + related_resources: + integrations: + list: [] + info_provided_to_referring_integrations: + description: "" + most_popular: false + overview: + data_collection: + metrics_description: | + This collector monitors VerneMQ instances. + method_description: "" + supported_platforms: + include: [] + exclude: [] + multi_instance: true + additional_permissions: + description: "" + default_behavior: + auto_detection: + description: "" + limits: + description: "" + performance_impact: + description: "" + setup: + prerequisites: + list: [] + configuration: + file: + name: go.d/vernemq.conf + options: + description: | + The following options can be defined globally: update_every, autodetection_retry. + folding: + title: Config options + enabled: true + list: + - name: update_every + description: Data collection frequency. + default_value: 1 + required: false + - name: autodetection_retry + description: Recheck interval in seconds. Zero means no recheck will be scheduled. + default_value: 0 + required: false + - name: url + description: Server URL. + default_value: http://127.0.0.1:8888/metrics + required: true + - name: timeout + description: HTTP request timeout. + default_value: 1 + required: false + - name: username + description: Username for basic HTTP authentication. + default_value: "" + required: false + - name: password + description: Password for basic HTTP authentication. + default_value: "" + required: false + - name: proxy_url + description: Proxy URL. + default_value: "" + required: false + - name: proxy_username + description: Username for proxy basic HTTP authentication. + default_value: "" + required: false + - name: proxy_password + description: Password for proxy basic HTTP authentication. + default_value: "" + required: false + - name: method + description: HTTP request method. + default_value: GET + required: false + - name: body + description: HTTP request body. + default_value: "" + required: false + - name: headers + description: HTTP request headers. + default_value: "" + required: false + - name: not_follow_redirects + description: Redirect handling policy. Controls whether the client follows redirects. + default_value: false + required: false + - name: tls_skip_verify + description: Server certificate chain and hostname validation policy. Controls whether the client performs this check. + default_value: false + required: false + - name: tls_ca + description: Certification authority that the client uses when verifying the server's certificates. + default_value: "" + required: false + - name: tls_cert + description: Client TLS certificate. + default_value: "" + required: false + - name: tls_key + description: Client TLS key. + default_value: "" + required: false + examples: + folding: + title: Config + enabled: true + list: + - name: Basic + description: An example configuration. + config: | + jobs: + - name: local + url: http://127.0.0.1:8888/metrics + - name: HTTP authentication + description: Local instance with basic HTTP authentication. + config: | + jobs: + - name: local + url: http://127.0.0.1:8888/metrics + username: username + password: password + - name: Multi-instance + description: | + > **Note**: When you define multiple jobs, their names must be unique. + + Local and remote instances. + config: | + jobs: + - name: local + url: http://127.0.0.1:8888/metrics + + - name: remote + url: http://203.0.113.10:8888/metrics + troubleshooting: + problems: + list: [] + alerts: + - name: vernemq_socket_errors + metric: vernemq.socket_errors + info: number of socket errors in the last minute + link: https://github.com/netdata/netdata/blob/master/src/health/health.d/vernemq.conf + - name: vernemq_queue_message_drop + metric: vernemq.queue_undelivered_messages + info: number of dropped messaged due to full queues in the last minute + link: https://github.com/netdata/netdata/blob/master/src/health/health.d/vernemq.conf + - name: vernemq_queue_message_expired + metric: vernemq.queue_undelivered_messages + info: number of messages which expired before delivery in the last minute + link: https://github.com/netdata/netdata/blob/master/src/health/health.d/vernemq.conf + - name: vernemq_queue_message_unhandled + metric: vernemq.queue_undelivered_messages + info: "number of unhandled messages (connections with clean session=true) in the last minute" + link: https://github.com/netdata/netdata/blob/master/src/health/health.d/vernemq.conf + - name: vernemq_average_scheduler_utilization + metric: vernemq.average_scheduler_utilization + info: average scheduler utilization over the last 10 minutes + link: https://github.com/netdata/netdata/blob/master/src/health/health.d/vernemq.conf + - name: vernemq_cluster_dropped + metric: vernemq.cluster_dropped + info: amount of traffic dropped during communication with the cluster nodes in the last minute + link: https://github.com/netdata/netdata/blob/master/src/health/health.d/vernemq.conf + - name: vernemq_netsplits + metric: vvernemq.netsplits + info: "number of detected netsplits (split brain situation) in the last minute" + link: https://github.com/netdata/netdata/blob/master/src/health/health.d/vernemq.conf + - name: vernemq_mqtt_connack_sent_reason_unsuccessful + metric: vernemq.mqtt_connack_sent_reason + info: number of sent unsuccessful v3/v5 CONNACK packets in the last minute + link: https://github.com/netdata/netdata/blob/master/src/health/health.d/vernemq.conf + - name: vernemq_mqtt_disconnect_received_reason_not_normal + metric: vernemq.mqtt_disconnect_received_reason + info: number of received not normal v5 DISCONNECT packets in the last minute + link: https://github.com/netdata/netdata/blob/master/src/health/health.d/vernemq.conf + - name: vernemq_mqtt_disconnect_sent_reason_not_normal + metric: vernemq.mqtt_disconnect_sent_reason + info: number of sent not normal v5 DISCONNECT packets in the last minute + link: https://github.com/netdata/netdata/blob/master/src/health/health.d/vernemq.conf + - name: vernemq_mqtt_subscribe_error + metric: vernemq.mqtt_subscribe_error + info: number of failed v3/v5 SUBSCRIBE operations in the last minute + link: https://github.com/netdata/netdata/blob/master/src/health/health.d/vernemq.conf + - name: vernemq_mqtt_subscribe_auth_error + metric: vernemq.mqtt_subscribe_auth_error + info: number of unauthorized v3/v5 SUBSCRIBE attempts in the last minute + link: https://github.com/netdata/netdata/blob/master/src/health/health.d/vernemq.conf + - name: vernemq_mqtt_unsubscribe_error + metric: vernemq.mqtt_unsubscribe_error + info: number of failed v3/v5 UNSUBSCRIBE operations in the last minute + link: https://github.com/netdata/netdata/blob/master/src/health/health.d/vernemq.conf + - name: vernemq_mqtt_publish_errors + metric: vernemq.mqtt_publish_errors + info: number of failed v3/v5 PUBLISH operations in the last minute + link: https://github.com/netdata/netdata/blob/master/src/health/health.d/vernemq.conf + - name: vernemq_mqtt_publish_auth_errors + metric: vernemq.mqtt_publish_auth_errors + info: number of unauthorized v3/v5 PUBLISH attempts in the last minute + link: https://github.com/netdata/netdata/blob/master/src/health/health.d/vernemq.conf + - name: vernemq_mqtt_puback_received_reason_unsuccessful + metric: vernemq.mqtt_puback_received_reason + info: number of received unsuccessful v5 PUBACK packets in the last minute + link: https://github.com/netdata/netdata/blob/master/src/health/health.d/vernemq.conf + - name: vernemq_mqtt_puback_sent_reason_unsuccessful + metric: vernemq.mqtt_puback_sent_reason + info: number of sent unsuccessful v5 PUBACK packets in the last minute + link: https://github.com/netdata/netdata/blob/master/src/health/health.d/vernemq.conf + - name: vernemq_mqtt_puback_unexpected + metric: vernemq.mqtt_puback_invalid_error + info: number of received unexpected v3/v5 PUBACK packets in the last minute + link: https://github.com/netdata/netdata/blob/master/src/health/health.d/vernemq.conf + - name: vernemq_mqtt_pubrec_received_reason_unsuccessful + metric: vernemq.mqtt_pubrec_received_reason + info: number of received unsuccessful v5 PUBREC packets in the last minute + link: https://github.com/netdata/netdata/blob/master/src/health/health.d/vernemq.conf + - name: vernemq_mqtt_pubrec_sent_reason_unsuccessful + metric: vernemq.mqtt_pubrec_sent_reason + info: number of sent unsuccessful v5 PUBREC packets in the last minute + link: https://github.com/netdata/netdata/blob/master/src/health/health.d/vernemq.conf + - name: vernemq_mqtt_pubrec_invalid_error + metric: vernemq.mqtt_pubrec_invalid_error + info: number of received unexpected v3 PUBREC packets in the last minute + link: https://github.com/netdata/netdata/blob/master/src/health/health.d/vernemq.conf + - name: vernemq_mqtt_pubrel_received_reason_unsuccessful + metric: vernemq.mqtt_pubrel_received_reason + info: number of received unsuccessful v5 PUBREL packets in the last minute + link: https://github.com/netdata/netdata/blob/master/src/health/health.d/vernemq.conf + - name: vernemq_mqtt_pubrel_sent_reason_unsuccessful + metric: vernemq.mqtt_pubrel_sent_reason + info: number of sent unsuccessful v5 PUBREL packets in the last minute + link: https://github.com/netdata/netdata/blob/master/src/health/health.d/vernemq.conf + - name: vernemq_mqtt_pubcomp_received_reason_unsuccessful + metric: vernemq.mqtt_pubcomp_received_reason + info: number of received unsuccessful v5 PUBCOMP packets in the last minute + link: https://github.com/netdata/netdata/blob/master/src/health/health.d/vernemq.conf + - name: vernemq_mqtt_pubcomp_sent_reason_unsuccessful + metric: vernemq.mqtt_pubcomp_sent_reason + info: number of sent unsuccessful v5 PUBCOMP packets in the last minute + link: https://github.com/netdata/netdata/blob/master/src/health/health.d/vernemq.conf + - name: vernemq_mqtt_pubcomp_unexpected + metric: vernemq.mqtt_pubcomp_invalid_error + info: number of received unexpected v3/v5 PUBCOMP packets in the last minute + link: https://github.com/netdata/netdata/blob/master/src/health/health.d/vernemq.conf + metrics: + folding: + title: Metrics + enabled: false + description: "" + availability: [] + scopes: + - name: global + description: These metrics refer to the entire monitored application. + labels: [] + metrics: + - name: vernemq.sockets + description: Open Sockets + unit: sockets + chart_type: line + dimensions: + - name: open + - name: vernemq.socket_operations + description: Socket Open and Close Events + unit: sockets/s + chart_type: line + dimensions: + - name: open + - name: close + - name: vernemq.client_keepalive_expired + description: Closed Sockets due to Keepalive Time Expired + unit: sockets/s + chart_type: line + dimensions: + - name: closed + - name: vernemq.socket_close_timeout + description: Closed Sockets due to no CONNECT Frame On Time + unit: sockets/s + chart_type: line + dimensions: + - name: closed + - name: vernemq.socket_errors + description: Socket Errors + unit: errors/s + chart_type: line + dimensions: + - name: errors + - name: vernemq.queue_processes + description: Living Queues in an Online or an Offline State + unit: queue processes + chart_type: line + dimensions: + - name: queue_processes + - name: vernemq.queue_processes_operations + description: Queue Processes Setup and Teardown Events + unit: events/s + chart_type: line + dimensions: + - name: setup + - name: teardown + - name: vernemq.queue_process_init_from_storage + description: Queue Processes Initialized from Offline Storage + unit: queue processes/s + chart_type: line + dimensions: + - name: queue_processes + - name: vernemq.queue_messages + description: Received and Sent PUBLISH Messages + unit: messages/s + chart_type: area + dimensions: + - name: received + - name: sent + - name: vernemq.queue_undelivered_messages + description: Undelivered PUBLISH Messages + unit: messages/s + chart_type: stacked + dimensions: + - name: dropped + - name: expired + - name: unhandled + - name: vernemq.router_subscriptions + description: Subscriptions in the Routing Table + unit: subscriptions + chart_type: line + dimensions: + - name: subscriptions + - name: vernemq.router_matched_subscriptions + description: Matched Subscriptions + unit: subscriptions/s + chart_type: line + dimensions: + - name: local + - name: remote + - name: vernemq.router_memory + description: Routing Table Memory Usage + unit: KiB + chart_type: area + dimensions: + - name: used + - name: vernemq.average_scheduler_utilization + description: Average Scheduler Utilization + unit: percentage + chart_type: area + dimensions: + - name: utilization + - name: vernemq.system_utilization_scheduler + description: Scheduler Utilization + unit: percentage + chart_type: stacked + dimensions: + - name: a dimension per scheduler + - name: vernemq.system_processes + description: Erlang Processes + unit: processes + chart_type: line + dimensions: + - name: processes + - name: vernemq.system_reductions + description: Reductions + unit: ops/s + chart_type: line + dimensions: + - name: reductions + - name: vernemq.system_context_switches + description: Context Switches + unit: ops/s + chart_type: line + dimensions: + - name: context_switches + - name: vernemq.system_io + description: Received and Sent Traffic through Ports + unit: kilobits/s + chart_type: area + dimensions: + - name: received + - name: sent + - name: vernemq.system_run_queue + description: Processes that are Ready to Run on All Run-Queues + unit: processes + chart_type: line + dimensions: + - name: ready + - name: vernemq.system_gc_count + description: GC Count + unit: ops/s + chart_type: line + dimensions: + - name: gc + - name: vernemq.system_gc_words_reclaimed + description: GC Words Reclaimed + unit: ops/s + chart_type: line + dimensions: + - name: words_reclaimed + - name: vernemq.system_allocated_memory + description: Memory Allocated by the Erlang Processes and by the Emulator + unit: KiB + chart_type: stacked + dimensions: + - name: processes + - name: system + - name: vernemq.bandwidth + description: Bandwidth + unit: kilobits/s + chart_type: area + dimensions: + - name: received + - name: sent + - name: vernemq.retain_messages + description: Stored Retained Messages + unit: messages + chart_type: line + dimensions: + - name: messages + - name: vernemq.retain_memory + description: Stored Retained Messages Memory Usage + unit: KiB + chart_type: area + dimensions: + - name: used + - name: vernemq.cluster_bandwidth + description: Communication with Other Cluster Nodes + unit: kilobits/s + chart_type: area + dimensions: + - name: received + - name: sent + - name: vernemq.cluster_dropped + description: Traffic Dropped During Communication with Other Cluster Nodes + unit: kilobits/s + chart_type: area + dimensions: + - name: dropped + - name: vernemq.netsplit_unresolved + description: Unresolved Netsplits + unit: netsplits + chart_type: line + dimensions: + - name: unresolved + - name: vernemq.netsplits + description: Netsplits + unit: netsplits/s + chart_type: stacked + dimensions: + - name: resolved + - name: detected + - name: vernemq.mqtt_auth + description: v5 AUTH + unit: packets/s + chart_type: line + dimensions: + - name: received + - name: sent + - name: vernemq.mqtt_auth_received_reason + description: v5 AUTH Received by Reason + unit: packets/s + chart_type: stacked + dimensions: + - name: a dimensions per reason + - name: vernemq.mqtt_auth_sent_reason + description: v5 AUTH Sent by Reason + unit: packets/s + chart_type: stacked + dimensions: + - name: a dimensions per reason + - name: vernemq.mqtt_connect + description: v3/v5 CONNECT and CONNACK + unit: packets/s + chart_type: line + dimensions: + - name: connect + - name: connack + - name: vernemq.mqtt_connack_sent_reason + description: v3/v5 CONNACK Sent by Reason + unit: packets/s + chart_type: stacked + dimensions: + - name: a dimensions per reason + - name: vernemq.mqtt_disconnect + description: v3/v5 DISCONNECT + unit: packets/s + chart_type: line + dimensions: + - name: received + - name: sent + - name: vernemq.mqtt_disconnect_received_reason + description: v5 DISCONNECT Received by Reason + unit: packets/s + chart_type: stacked + dimensions: + - name: a dimensions per reason + - name: vernemq.mqtt_disconnect_sent_reason + description: v5 DISCONNECT Sent by Reason + unit: packets/s + chart_type: stacked + dimensions: + - name: a dimensions per reason + - name: vernemq.mqtt_subscribe + description: v3/v5 SUBSCRIBE and SUBACK + unit: packets/s + chart_type: line + dimensions: + - name: subscribe + - name: suback + - name: vernemq.mqtt_subscribe_error + description: v3/v5 Failed SUBSCRIBE Operations due to a Netsplit + unit: ops/s + chart_type: line + dimensions: + - name: failed + - name: vernemq.mqtt_subscribe_auth_error + description: v3/v5 Unauthorized SUBSCRIBE Attempts + unit: attempts/s + chart_type: line + dimensions: + - name: unauth + - name: vernemq.mqtt_unsubscribe + description: v3/v5 UNSUBSCRIBE and UNSUBACK + unit: packets/s + chart_type: line + dimensions: + - name: unsubscribe + - name: unsuback + - name: vernemq.mqtt_unsubscribe_error + description: v3/v5 Failed UNSUBSCRIBE Operations due to a Netsplit + unit: ops/s + chart_type: line + dimensions: + - name: mqtt_unsubscribe_error + - name: vernemq.mqtt_publish + description: v3/v5 QoS 0,1,2 PUBLISH + unit: packets/s + chart_type: line + dimensions: + - name: received + - name: sent + - name: vernemq.mqtt_publish_errors + description: v3/v5 Failed PUBLISH Operations due to a Netsplit + unit: ops/s + chart_type: line + dimensions: + - name: failed + - name: vernemq.mqtt_publish_auth_errors + description: v3/v5 Unauthorized PUBLISH Attempts + unit: attempts/s + chart_type: area + dimensions: + - name: unauth + - name: vernemq.mqtt_puback + description: v3/v5 QoS 1 PUBACK + unit: packets/s + chart_type: line + dimensions: + - name: received + - name: sent + - name: vernemq.mqtt_puback_received_reason + description: v5 PUBACK QoS 1 Received by Reason + unit: packets/s + chart_type: stacked + dimensions: + - name: a dimensions per reason + - name: vernemq.mqtt_puback_sent_reason + description: v5 PUBACK QoS 1 Sent by Reason + unit: packets/s + chart_type: stacked + dimensions: + - name: a dimensions per reason + - name: vernemq.mqtt_puback_invalid_error + description: v3/v5 PUBACK QoS 1 Received Unexpected Messages + unit: messages/s + chart_type: line + dimensions: + - name: unexpected + - name: vernemq.mqtt_pubrec + description: v3/v5 PUBREC QoS 2 + unit: packets/s + chart_type: line + dimensions: + - name: received + - name: sent + - name: vernemq.mqtt_pubrec_received_reason + description: v5 PUBREC QoS 2 Received by Reason + unit: packets/s + chart_type: stacked + dimensions: + - name: a dimensions per reason + - name: vernemq.mqtt_pubrec_sent_reason + description: v5 PUBREC QoS 2 Sent by Reason + unit: packets/s + chart_type: stacked + dimensions: + - name: a dimensions per reason + - name: vernemq.mqtt_pubrec_invalid_error + description: v3 PUBREC QoS 2 Received Unexpected Messages + unit: messages/s + chart_type: line + dimensions: + - name: unexpected + - name: vernemq.mqtt_pubrel + description: v3/v5 PUBREL QoS 2 + unit: packets/s + chart_type: line + dimensions: + - name: received + - name: sent + - name: vernemq.mqtt_pubrel_received_reason + description: v5 PUBREL QoS 2 Received by Reason + unit: packets/s + chart_type: stacked + dimensions: + - name: a dimensions per reason + - name: vernemq.mqtt_pubrel_sent_reason + description: v5 PUBREL QoS 2 Sent by Reason + unit: packets/s + chart_type: stacked + dimensions: + - name: a dimensions per reason + - name: vernemq.mqtt_pubcom + description: v3/v5 PUBCOMP QoS 2 + unit: packets/s + chart_type: line + dimensions: + - name: received + - name: sent + - name: vernemq.mqtt_pubcomp_received_reason + description: v5 PUBCOMP QoS 2 Received by Reason + unit: packets/s + chart_type: stacked + dimensions: + - name: a dimensions per reason + - name: vernemq.mqtt_pubcomp_sent_reason + description: v5 PUBCOMP QoS 2 Sent by Reason + unit: packets/s + chart_type: stacked + dimensions: + - name: a dimensions per reason + - name: vernemq.mqtt_pubcomp_invalid_error + description: v3/v5 PUBCOMP QoS 2 Received Unexpected Messages + unit: messages/s + chart_type: line + dimensions: + - name: unexpected + - name: vernemq.mqtt_ping + description: v3/v5 PING + unit: packets/s + chart_type: line + dimensions: + - name: pingreq + - name: pingresp + - name: vernemq.node_uptime + description: Node Uptime + unit: seconds + chart_type: line + dimensions: + - name: time diff --git a/src/go/plugin/go.d/modules/vernemq/metrics.go b/src/go/plugin/go.d/modules/vernemq/metrics.go new file mode 100644 index 00000000..863cc635 --- /dev/null +++ b/src/go/plugin/go.d/modules/vernemq/metrics.go @@ -0,0 +1,150 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package vernemq + +// Source Code Metrics: +// - https://github.com/vernemq/vernemq/blob/master/apps/vmq_server/src/vmq_metrics.erl +// - https://github.com/vernemq/vernemq/blob/master/apps/vmq_server/src/vmq_metrics.hrl + +// Source Code FSM: +// - https://github.com/vernemq/vernemq/blob/master/apps/vmq_server/src/vmq_mqtt_fsm.erl +// - https://github.com/vernemq/vernemq/blob/master/apps/vmq_server/src/vmq_mqtt5_fsm.erl + +// MQTT Packet Types: +// - v4: http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/errata01/os/mqtt-v3.1.1-errata01-os-complete.html#_Toc442180834 +// - v5: https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901019 + +// Erlang VM: +// - http://erlang.org/documentation/doc-5.7.1/erts-5.7.1/doc/html/erlang.html + +// Not used metrics (https://docs.vernemq.com/monitoring/introduction): +// - "mqtt_connack_accepted_sent" // v4, not populated, "mqtt_connack_sent" used instead +// - "mqtt_connack_unacceptable_protocol_sent" // v4, not populated, "mqtt_connack_sent" used instead +// - "mqtt_connack_identifier_rejected_sent" // v4, not populated, "mqtt_connack_sent" used instead +// - "mqtt_connack_server_unavailable_sent" // v4, not populated, "mqtt_connack_sent" used instead +// - "mqtt_connack_bad_credentials_sent" // v4, not populated, "mqtt_connack_sent" used instead +// - "mqtt_connack_not_authorized_sent" // v4, not populated, "mqtt_connack_sent" used instead +// - "system_exact_reductions" +// - "system_runtime" +// - "vm_memory_atom" +// - "vm_memory_atom_used" +// - "vm_memory_binary" +// - "vm_memory_code" +// - "vm_memory_ets" +// - "vm_memory_processes_used" +// - "vm_memory_total" + +// -----------------------------------------------MQTT------------------------------------------------------------------ +const ( + // AUTH + metricAUTHReceived = "mqtt_auth_received" // v5 has 'reason_code' label + metricAUTHSent = "mqtt_auth_sent" // v5 has 'reason_code' label + + // CONNECT + metricCONNECTReceived = "mqtt_connect_received" // v4, v5 + metricCONNACKSent = "mqtt_connack_sent" // v4 has 'return_code' label, v5 has 'reason_code' + + // SUBSCRIBE + metricSUBSCRIBEReceived = "mqtt_subscribe_received" // v4, v5 + metricSUBACKSent = "mqtt_suback_sent" // v4, v5 + metricSUBSCRIBEError = "mqtt_subscribe_error" // v4, v5 + metricSUBSCRIBEAuthError = "mqtt_subscribe_auth_error" // v4, v5 + + // UNSUBSCRIBE + metricUNSUBSCRIBEReceived = "mqtt_unsubscribe_received" // v4, v5 + metricUNSUBACKSent = "mqtt_unsuback_sent" // v4, v5 + metricUNSUBSCRIBEError = "mqtt_unsubscribe_error" // v4, v5 + + // PUBLISH + metricPUBSLISHReceived = "mqtt_publish_received" // v4, v5 + metricPUBSLIHSent = "mqtt_publish_sent" // v4, v5 + metricPUBLISHError = "mqtt_publish_error" // v4, v5 + metricPUBLISHAuthError = "mqtt_publish_auth_error" // v4, v5 + + // Publish acknowledgment (QoS 1) + metricPUBACKReceived = "mqtt_puback_received" // v4, v5 has 'reason_code' label + metricPUBACKSent = "mqtt_puback_sent" // v4, v5 has 'reason_code' label + metricPUBACKInvalid = "mqtt_puback_invalid_error" // v4, v5 + + // Publish received (QoS 2 delivery part 1) + metricPUBRECReceived = "mqtt_pubrec_received" // v4, v5 has 'reason_code' label + metricPUBRECSent = "mqtt_pubrec_sent" // v4, v5 has 'reason_code' label + metricPUBRECInvalid = "mqtt_pubrec_invalid_error" // v4 + + // Publish release (QoS 2 delivery part 2) + metricPUBRELReceived = "mqtt_pubrel_received" // v4, v5 has 'reason_code' label + metricPUBRELSent = "mqtt_pubrel_sent" // v4, v5 has 'reason_code' label + + // Publish complete (QoS 2 delivery part 3) + metricPUBCOMPReceived = "mqtt_pubcomp_received" // v4, v5 has 'reason_code' label + metricPUBCOMPSent = "mqtt_pubcomp_sent" // v4, v5 has 'reason_code' label + metricPUNCOMPInvalid = "mqtt_pubcomp_invalid_error" // v4, v5 + + // PING + metricPINGREQReceived = "mqtt_pingreq_received" // v4, v5 + metricPINGRESPSent = "mqtt_pingresp_sent" // v4, v5 + + // DISCONNECT + metricDISCONNECTReceived = "mqtt_disconnect_received" // v4, v5 has 'reason_code' label + metricDISCONNECTSent = "mqtt_disconnect_sent" // v5 has 'reason_code' label + + // Misc + metricMQTTInvalidMsgSizeError = "mqtt_invalid_msg_size_error" // v4, v5 +) + +const ( + // Sockets + metricSocketOpen = "socket_open" + metricSocketClose = "socket_close" + metricSocketError = "socket_error" + metricSocketCloseTimeout = "socket_close_timeout" + metricClientKeepaliveExpired = "client_keepalive_expired" // v4, v5 + + // Queues + metricQueueProcesses = "queue_processes" + metricQueueSetup = "queue_setup" + metricQueueTeardown = "queue_teardown" + metricQueueMessageIn = "queue_message_in" + metricQueueMessageOut = "queue_message_out" + metricQueueMessageDrop = "queue_message_drop" + metricQueueMessageExpired = "queue_message_expired" + metricQueueMessageUnhandled = "queue_message_unhandled" + metricQueueInitializedFromStorage = "queue_initialized_from_storage" + + // Subscriptions + metricRouterMatchesLocal = "router_matches_local" + metricRouterMatchesRemote = "router_matches_remote" + metricRouterMemory = "router_memory" + metricRouterSubscriptions = "router_subscriptions" + + // Erlang VM + metricSystemUtilization = "system_utilization" + metricSystemProcessCount = "system_process_count" + metricSystemReductions = "system_reductions" + metricSystemContextSwitches = "system_context_switches" + metricSystemIOIn = "system_io_in" + metricSystemIOOut = "system_io_out" + metricSystemRunQueue = "system_run_queue" + metricSystemGCCount = "system_gc_count" + metricSystemWordsReclaimedByGC = "system_words_reclaimed_by_gc" + metricVMMemoryProcesses = "vm_memory_processes" + metricVMMemorySystem = "vm_memory_system" + + // Bandwidth + metricBytesReceived = "bytes_received" + metricBytesSent = "bytes_sent" + + // Retain + metricRetainMemory = "retain_memory" + metricRetainMessages = "retain_messages" + + // Cluster + metricClusterBytesDropped = "cluster_bytes_dropped" + metricClusterBytesReceived = "cluster_bytes_received" + metricClusterBytesSent = "cluster_bytes_sent" + metricNetSplitDetected = "netsplit_detected" + metricNetSplitResolved = "netsplit_resolved" + + // Uptime + metricSystemWallClock = "system_wallclock" +) diff --git a/src/go/plugin/go.d/modules/vernemq/testdata/config.json b/src/go/plugin/go.d/modules/vernemq/testdata/config.json new file mode 100644 index 00000000..984c3ed6 --- /dev/null +++ b/src/go/plugin/go.d/modules/vernemq/testdata/config.json @@ -0,0 +1,20 @@ +{ + "update_every": 123, + "url": "ok", + "body": "ok", + "method": "ok", + "headers": { + "ok": "ok" + }, + "username": "ok", + "password": "ok", + "proxy_url": "ok", + "proxy_username": "ok", + "proxy_password": "ok", + "timeout": 123.123, + "not_follow_redirects": true, + "tls_ca": "ok", + "tls_cert": "ok", + "tls_key": "ok", + "tls_skip_verify": true +} diff --git a/src/go/plugin/go.d/modules/vernemq/testdata/config.yaml b/src/go/plugin/go.d/modules/vernemq/testdata/config.yaml new file mode 100644 index 00000000..8558b61c --- /dev/null +++ b/src/go/plugin/go.d/modules/vernemq/testdata/config.yaml @@ -0,0 +1,17 @@ +update_every: 123 +url: "ok" +body: "ok" +method: "ok" +headers: + ok: "ok" +username: "ok" +password: "ok" +proxy_url: "ok" +proxy_username: "ok" +proxy_password: "ok" +timeout: 123.123 +not_follow_redirects: yes +tls_ca: "ok" +tls_cert: "ok" +tls_key: "ok" +tls_skip_verify: yes diff --git a/src/go/plugin/go.d/modules/vernemq/testdata/metrics-v1.10.1-mqtt5.txt b/src/go/plugin/go.d/modules/vernemq/testdata/metrics-v1.10.1-mqtt5.txt new file mode 100644 index 00000000..2e98a3e9 --- /dev/null +++ b/src/go/plugin/go.d/modules/vernemq/testdata/metrics-v1.10.1-mqtt5.txt @@ -0,0 +1,416 @@ +# HELP socket_open The number of times an MQTT socket has been opened. +# TYPE socket_open counter +socket_open{node="VerneMQ@172.17.0.2"} 338956 +# HELP socket_close The number of times an MQTT socket has been closed. +# TYPE socket_close counter +socket_close{node="VerneMQ@172.17.0.2"} 338956 +# HELP socket_close_timeout The number of times VerneMQ closed an MQTT socket due to no CONNECT frame has been received on time. +# TYPE socket_close_timeout counter +socket_close_timeout{node="VerneMQ@172.17.0.2"} 0 +# HELP socket_error The total number of socket errors that have occurred. +# TYPE socket_error counter +socket_error{node="VerneMQ@172.17.0.2"} 0 +# HELP bytes_received The total number of bytes received. +# TYPE bytes_received counter +bytes_received{node="VerneMQ@172.17.0.2"} 36796908 +# HELP bytes_sent The total number of bytes sent. +# TYPE bytes_sent counter +bytes_sent{node="VerneMQ@172.17.0.2"} 23361693 +# HELP mqtt_connect_received The number of CONNECT packets received. +# TYPE mqtt_connect_received counter +mqtt_connect_received{node="VerneMQ@172.17.0.2",mqtt_version="4"} 338956 +# HELP mqtt_publish_received The number of PUBLISH packets received. +# TYPE mqtt_publish_received counter +mqtt_publish_received{node="VerneMQ@172.17.0.2",mqtt_version="4"} 537088 +# HELP mqtt_puback_received The number of PUBACK packets received. +# TYPE mqtt_puback_received counter +mqtt_puback_received{node="VerneMQ@172.17.0.2",mqtt_version="4"} 525694 +# HELP mqtt_pubrec_received The number of PUBREC packets received. +# TYPE mqtt_pubrec_received counter +mqtt_pubrec_received{node="VerneMQ@172.17.0.2",mqtt_version="4"} 0 +# HELP mqtt_pubrel_received The number of PUBREL packets received. +# TYPE mqtt_pubrel_received counter +mqtt_pubrel_received{node="VerneMQ@172.17.0.2",mqtt_version="4"} 0 +# HELP mqtt_pubcomp_received The number of PUBCOMP packets received. +# TYPE mqtt_pubcomp_received counter +mqtt_pubcomp_received{node="VerneMQ@172.17.0.2",mqtt_version="4"} 0 +# HELP mqtt_subscribe_received The number of SUBSCRIBE packets received. +# TYPE mqtt_subscribe_received counter +mqtt_subscribe_received{node="VerneMQ@172.17.0.2",mqtt_version="4"} 122 +# HELP mqtt_unsubscribe_received The number of UNSUBSCRIBE packets received. +# TYPE mqtt_unsubscribe_received counter +mqtt_unsubscribe_received{node="VerneMQ@172.17.0.2",mqtt_version="4"} 108 +# HELP mqtt_pingreq_received The number of PINGREQ packets received. +# TYPE mqtt_pingreq_received counter +mqtt_pingreq_received{node="VerneMQ@172.17.0.2",mqtt_version="4"} 205 +# HELP mqtt_disconnect_received The number of DISCONNECT packets received. +# TYPE mqtt_disconnect_received counter +mqtt_disconnect_received{node="VerneMQ@172.17.0.2",mqtt_version="4"} 107 +# HELP mqtt_connack_accepted_sent The number of times a connection has been accepted. +# TYPE mqtt_connack_accepted_sent counter +mqtt_connack_accepted_sent{node="VerneMQ@172.17.0.2",mqtt_version="4"} 0 +# HELP mqtt_connack_unacceptable_protocol_sent The number of times the broker is not able to support the requested protocol. +# TYPE mqtt_connack_unacceptable_protocol_sent counter +mqtt_connack_unacceptable_protocol_sent{node="VerneMQ@172.17.0.2",mqtt_version="4"} 0 +# HELP mqtt_connack_identifier_rejected_sent The number of times a client was rejected due to a unacceptable identifier. +# TYPE mqtt_connack_identifier_rejected_sent counter +mqtt_connack_identifier_rejected_sent{node="VerneMQ@172.17.0.2",mqtt_version="4"} 0 +# HELP mqtt_connack_server_unavailable_sent The number of times a client was rejected due the the broker being unavailable. +# TYPE mqtt_connack_server_unavailable_sent counter +mqtt_connack_server_unavailable_sent{node="VerneMQ@172.17.0.2",mqtt_version="4"} 0 +# HELP mqtt_connack_bad_credentials_sent The number of times a client sent bad credentials. +# TYPE mqtt_connack_bad_credentials_sent counter +mqtt_connack_bad_credentials_sent{node="VerneMQ@172.17.0.2",mqtt_version="4"} 0 +# HELP mqtt_connack_not_authorized_sent The number of times a client was rejected due to insufficient authorization. +# TYPE mqtt_connack_not_authorized_sent counter +mqtt_connack_not_authorized_sent{node="VerneMQ@172.17.0.2",mqtt_version="4"} 0 +# HELP mqtt_publish_sent The number of PUBLISH packets sent. +# TYPE mqtt_publish_sent counter +mqtt_publish_sent{node="VerneMQ@172.17.0.2",mqtt_version="4"} 525721 +# HELP mqtt_puback_sent The number of PUBACK packets sent. +# TYPE mqtt_puback_sent counter +mqtt_puback_sent{node="VerneMQ@172.17.0.2",mqtt_version="4"} 537068 +# HELP mqtt_pubrec_sent The number of PUBREC packets sent. +# TYPE mqtt_pubrec_sent counter +mqtt_pubrec_sent{node="VerneMQ@172.17.0.2",mqtt_version="4"} 0 +# HELP mqtt_pubrel_sent The number of PUBREL packets sent. +# TYPE mqtt_pubrel_sent counter +mqtt_pubrel_sent{node="VerneMQ@172.17.0.2",mqtt_version="4"} 0 +# HELP mqtt_pubcomp_sent The number of PUBCOMP packets sent. +# TYPE mqtt_pubcomp_sent counter +mqtt_pubcomp_sent{node="VerneMQ@172.17.0.2",mqtt_version="4"} 0 +# HELP mqtt_suback_sent The number of SUBACK packets sent. +# TYPE mqtt_suback_sent counter +mqtt_suback_sent{node="VerneMQ@172.17.0.2",mqtt_version="4"} 122 +# HELP mqtt_unsuback_sent The number of UNSUBACK packets sent. +# TYPE mqtt_unsuback_sent counter +mqtt_unsuback_sent{node="VerneMQ@172.17.0.2",mqtt_version="4"} 108 +# HELP mqtt_pingresp_sent The number of PINGRESP packets sent. +# TYPE mqtt_pingresp_sent counter +mqtt_pingresp_sent{node="VerneMQ@172.17.0.2",mqtt_version="4"} 205 +# HELP mqtt_publish_auth_error The number of unauthorized publish attempts. +# TYPE mqtt_publish_auth_error counter +mqtt_publish_auth_error{node="VerneMQ@172.17.0.2",mqtt_version="4"} 0 +# HELP mqtt_subscribe_auth_error The number of unauthorized subscription attempts. +# TYPE mqtt_subscribe_auth_error counter +mqtt_subscribe_auth_error{node="VerneMQ@172.17.0.2",mqtt_version="4"} 0 +# HELP mqtt_invalid_msg_size_error The number of packages exceeding the maximum allowed size. +# TYPE mqtt_invalid_msg_size_error counter +mqtt_invalid_msg_size_error{node="VerneMQ@172.17.0.2",mqtt_version="4"} 0 +# HELP mqtt_puback_invalid_error The number of unexpected PUBACK messages received. +# TYPE mqtt_puback_invalid_error counter +mqtt_puback_invalid_error{node="VerneMQ@172.17.0.2",mqtt_version="4"} 0 +# HELP mqtt_pubrec_invalid_error The number of unexpected PUBREC messages received. +# TYPE mqtt_pubrec_invalid_error counter +mqtt_pubrec_invalid_error{node="VerneMQ@172.17.0.2",mqtt_version="4"} 0 +# HELP mqtt_pubcomp_invalid_error The number of unexpected PUBCOMP messages received. +# TYPE mqtt_pubcomp_invalid_error counter +mqtt_pubcomp_invalid_error{node="VerneMQ@172.17.0.2",mqtt_version="4"} 0 +# HELP mqtt_publish_error The number of times a PUBLISH operation failed due to a netsplit. +# TYPE mqtt_publish_error counter +mqtt_publish_error{node="VerneMQ@172.17.0.2",mqtt_version="4"} 0 +# HELP mqtt_subscribe_error The number of times a SUBSCRIBE operation failed due to a netsplit. +# TYPE mqtt_subscribe_error counter +mqtt_subscribe_error{node="VerneMQ@172.17.0.2",mqtt_version="4"} 0 +# HELP mqtt_unsubscribe_error The number of times an UNSUBSCRIBE operation failed due to a netsplit. +# TYPE mqtt_unsubscribe_error counter +mqtt_unsubscribe_error{node="VerneMQ@172.17.0.2",mqtt_version="4"} 0 +# HELP client_keepalive_expired The number of clients which failed to communicate within the keepalive time period. +# TYPE client_keepalive_expired counter +client_keepalive_expired{node="VerneMQ@172.17.0.2",mqtt_version="4"} 1 +mqtt_connect_received{node="VerneMQ@172.17.0.2",mqtt_version="5"} 0 +mqtt_invalid_msg_size_error{node="VerneMQ@172.17.0.2",mqtt_version="5"} 0 +mqtt_pingreq_received{node="VerneMQ@172.17.0.2",mqtt_version="5"} 0 +mqtt_pingresp_sent{node="VerneMQ@172.17.0.2",mqtt_version="5"} 0 +mqtt_puback_invalid_error{node="VerneMQ@172.17.0.2",mqtt_version="5"} 0 +mqtt_pubcomp_invalid_error{node="VerneMQ@172.17.0.2",mqtt_version="5"} 0 +mqtt_publish_auth_error{node="VerneMQ@172.17.0.2",mqtt_version="5"} 0 +mqtt_publish_error{node="VerneMQ@172.17.0.2",mqtt_version="5"} 0 +mqtt_publish_received{node="VerneMQ@172.17.0.2",mqtt_version="5"} 0 +mqtt_publish_sent{node="VerneMQ@172.17.0.2",mqtt_version="5"} 0 +mqtt_suback_sent{node="VerneMQ@172.17.0.2",mqtt_version="5"} 0 +mqtt_subscribe_auth_error{node="VerneMQ@172.17.0.2",mqtt_version="5"} 0 +mqtt_subscribe_error{node="VerneMQ@172.17.0.2",mqtt_version="5"} 0 +mqtt_subscribe_received{node="VerneMQ@172.17.0.2",mqtt_version="5"} 0 +mqtt_unsuback_sent{node="VerneMQ@172.17.0.2",mqtt_version="5"} 0 +mqtt_unsubscribe_error{node="VerneMQ@172.17.0.2",mqtt_version="5"} 0 +mqtt_unsubscribe_received{node="VerneMQ@172.17.0.2",mqtt_version="5"} 0 +client_keepalive_expired{node="VerneMQ@172.17.0.2",mqtt_version="5"} 0 +# HELP queue_setup The number of times a MQTT queue process has been started. +# TYPE queue_setup counter +queue_setup{node="VerneMQ@172.17.0.2"} 338948 +# HELP queue_initialized_from_storage The number of times a MQTT queue process has been initialized from offline storage. +# TYPE queue_initialized_from_storage counter +queue_initialized_from_storage{node="VerneMQ@172.17.0.2"} 0 +# HELP queue_teardown The number of times a MQTT queue process has been terminated. +# TYPE queue_teardown counter +queue_teardown{node="VerneMQ@172.17.0.2"} 338948 +# HELP queue_message_drop The number of messages dropped due to full queues. +# TYPE queue_message_drop counter +queue_message_drop{node="VerneMQ@172.17.0.2"} 0 +# HELP queue_message_expired The number of messages which expired before delivery. +# TYPE queue_message_expired counter +queue_message_expired{node="VerneMQ@172.17.0.2"} 0 +# HELP queue_message_unhandled The number of unhandled messages when connecting with clean session=true. +# TYPE queue_message_unhandled counter +queue_message_unhandled{node="VerneMQ@172.17.0.2"} 1 +# HELP queue_message_in The number of PUBLISH packets received by MQTT queue processes. +# TYPE queue_message_in counter +queue_message_in{node="VerneMQ@172.17.0.2"} 525722 +# HELP queue_message_out The number of PUBLISH packets sent from MQTT queue processes. +# TYPE queue_message_out counter +queue_message_out{node="VerneMQ@172.17.0.2"} 525721 +# HELP client_expired Not in use (deprecated) +# TYPE client_expired counter +client_expired{node="VerneMQ@172.17.0.2"} 0 +# HELP cluster_bytes_received The number of bytes received from other cluster nodes. +# TYPE cluster_bytes_received counter +cluster_bytes_received{node="VerneMQ@172.17.0.2"} 0 +# HELP cluster_bytes_sent The number of bytes send to other cluster nodes. +# TYPE cluster_bytes_sent counter +cluster_bytes_sent{node="VerneMQ@172.17.0.2"} 0 +# HELP cluster_bytes_dropped The number of bytes dropped while sending data to other cluster nodes. +# TYPE cluster_bytes_dropped counter +cluster_bytes_dropped{node="VerneMQ@172.17.0.2"} 0 +# HELP router_matches_local The number of matched local subscriptions. +# TYPE router_matches_local counter +router_matches_local{node="VerneMQ@172.17.0.2"} 525722 +# HELP router_matches_remote The number of matched remote subscriptions. +# TYPE router_matches_remote counter +router_matches_remote{node="VerneMQ@172.17.0.2"} 0 +# HELP mqtt_connack_sent The number of CONNACK packets sent. +# TYPE mqtt_connack_sent counter +mqtt_connack_sent{node="VerneMQ@172.17.0.2",mqtt_version="4",return_code="success"} 338948 +mqtt_connack_sent{node="VerneMQ@172.17.0.2",mqtt_version="4",return_code="unsupported_protocol_version"} 0 +mqtt_connack_sent{node="VerneMQ@172.17.0.2",mqtt_version="4",return_code="client_identifier_not_valid"} 0 +mqtt_connack_sent{node="VerneMQ@172.17.0.2",mqtt_version="4",return_code="server_unavailable"} 0 +mqtt_connack_sent{node="VerneMQ@172.17.0.2",mqtt_version="4",return_code="bad_username_or_password"} 4 +mqtt_connack_sent{node="VerneMQ@172.17.0.2",mqtt_version="4",return_code="not_authorized"} 4 +mqtt_disconnect_received{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="normal_disconnect"} 0 +mqtt_disconnect_received{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="disconnect_with_will_msg"} 0 +mqtt_disconnect_received{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="unspecified_error"} 0 +mqtt_disconnect_received{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="malformed_packet"} 0 +mqtt_disconnect_received{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="protocol_error"} 0 +mqtt_disconnect_received{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="impl_specific_error"} 0 +mqtt_disconnect_received{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="topic_name_invalid"} 0 +mqtt_disconnect_received{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="receive_max_exceeded"} 0 +mqtt_disconnect_received{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="topic_alias_invalid"} 0 +mqtt_disconnect_received{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="packet_too_large"} 0 +mqtt_disconnect_received{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="message_rate_too_high"} 0 +mqtt_disconnect_received{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="quota_exceeded"} 0 +mqtt_disconnect_received{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="administrative_action"} 0 +mqtt_disconnect_received{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="payload_format_invalid"} 0 +# HELP mqtt_disconnect_sent The number of DISCONNECT packets sent. +# TYPE mqtt_disconnect_sent counter +mqtt_disconnect_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="normal_disconnect"} 0 +mqtt_disconnect_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="unspecified_error"} 0 +mqtt_disconnect_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="malformed_packet"} 0 +mqtt_disconnect_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="protocol_error"} 0 +mqtt_disconnect_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="impl_specific_error"} 0 +mqtt_disconnect_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="not_authorized"} 0 +mqtt_disconnect_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="server_busy"} 0 +mqtt_disconnect_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="server_shutting_down"} 0 +mqtt_disconnect_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="keep_alive_timeout"} 0 +mqtt_disconnect_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="session_taken_over"} 0 +mqtt_disconnect_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="topic_filter_invalid"} 0 +mqtt_disconnect_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="topic_name_invalid"} 0 +mqtt_disconnect_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="receive_max_exceeded"} 0 +mqtt_disconnect_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="topic_alias_invalid"} 0 +mqtt_disconnect_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="packet_too_large"} 0 +mqtt_disconnect_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="message_rate_too_high"} 0 +mqtt_disconnect_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="quota_exceeded"} 0 +mqtt_disconnect_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="administrative_action"} 0 +mqtt_disconnect_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="payload_format_invalid"} 0 +mqtt_disconnect_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="retain_not_supported"} 0 +mqtt_disconnect_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="qos_not_supported"} 0 +mqtt_disconnect_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="use_another_server"} 0 +mqtt_disconnect_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="server_moved"} 0 +mqtt_disconnect_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="shared_subs_not_supported"} 0 +mqtt_disconnect_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="connection_rate_exceeded"} 0 +mqtt_disconnect_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="max_connect_time"} 0 +mqtt_disconnect_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="subscription_ids_not_supported"} 0 +mqtt_disconnect_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="wildcard_subs_not_supported"} 0 +mqtt_connack_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="success"} 0 +mqtt_connack_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="unspecified_error"} 0 +mqtt_connack_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="malformed_packet"} 0 +mqtt_connack_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="protocol_error"} 0 +mqtt_connack_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="impl_specific_error"} 0 +mqtt_connack_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="unsupported_protocol_version"} 0 +mqtt_connack_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="client_identifier_not_valid"} 0 +mqtt_connack_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="bad_username_or_password"} 0 +mqtt_connack_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="not_authorized"} 0 +mqtt_connack_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="server_unavailable"} 0 +mqtt_connack_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="server_busy"} 0 +mqtt_connack_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="banned"} 0 +mqtt_connack_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="bad_authentication_method"} 0 +mqtt_connack_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="topic_name_invalid"} 0 +mqtt_connack_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="packet_too_large"} 0 +mqtt_connack_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="quota_exceeded"} 0 +mqtt_connack_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="payload_format_invalid"} 0 +mqtt_connack_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="retain_not_supported"} 0 +mqtt_connack_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="qos_not_supported"} 0 +mqtt_connack_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="use_another_server"} 0 +mqtt_connack_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="server_moved"} 0 +mqtt_connack_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="connection_rate_exceeded"} 0 +mqtt_puback_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="success"} 0 +mqtt_puback_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="no_matching_subscribers"} 0 +mqtt_puback_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="unspecified_error"} 0 +mqtt_puback_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="impl_specific_error"} 0 +mqtt_puback_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="not_authorized"} 0 +mqtt_puback_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="topic_name_invalid"} 0 +mqtt_puback_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="packet_id_in_use"} 0 +mqtt_puback_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="quota_exceeded"} 0 +mqtt_puback_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="payload_format_invalid"} 0 +mqtt_puback_received{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="success"} 0 +mqtt_puback_received{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="no_matching_subscribers"} 0 +mqtt_puback_received{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="unspecified_error"} 0 +mqtt_puback_received{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="impl_specific_error"} 0 +mqtt_puback_received{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="not_authorized"} 0 +mqtt_puback_received{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="topic_name_invalid"} 0 +mqtt_puback_received{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="packet_id_in_use"} 0 +mqtt_puback_received{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="quota_exceeded"} 0 +mqtt_puback_received{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="payload_format_invalid"} 0 +mqtt_pubrec_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="success"} 0 +mqtt_pubrec_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="no_matching_subscribers"} 0 +mqtt_pubrec_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="unspecified_error"} 0 +mqtt_pubrec_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="impl_specific_error"} 0 +mqtt_pubrec_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="not_authorized"} 0 +mqtt_pubrec_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="topic_name_invalid"} 0 +mqtt_pubrec_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="packet_id_in_use"} 0 +mqtt_pubrec_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="quota_exceeded"} 0 +mqtt_pubrec_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="payload_format_invalid"} 0 +mqtt_pubrec_received{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="success"} 0 +mqtt_pubrec_received{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="no_matching_subscribers"} 0 +mqtt_pubrec_received{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="unspecified_error"} 0 +mqtt_pubrec_received{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="impl_specific_error"} 0 +mqtt_pubrec_received{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="not_authorized"} 0 +mqtt_pubrec_received{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="topic_name_invalid"} 0 +mqtt_pubrec_received{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="packet_id_in_use"} 0 +mqtt_pubrec_received{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="quota_exceeded"} 0 +mqtt_pubrec_received{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="payload_format_invalid"} 0 +mqtt_pubrel_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="success"} 0 +mqtt_pubrel_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="packet_id_not_found"} 0 +mqtt_pubrel_received{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="success"} 0 +mqtt_pubrel_received{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="packet_id_not_found"} 0 +mqtt_pubcomp_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="success"} 0 +mqtt_pubcomp_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="packet_id_not_found"} 0 +mqtt_pubcomp_received{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="success"} 0 +mqtt_pubcomp_received{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="packet_id_not_found"} 0 +# HELP mqtt_auth_sent The number of AUTH packets sent. +# TYPE mqtt_auth_sent counter +mqtt_auth_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="success"} 0 +mqtt_auth_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="continue_authentication"} 0 +mqtt_auth_sent{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="reauthenticate"} 0 +# HELP mqtt_auth_received The number of AUTH packets received. +# TYPE mqtt_auth_received counter +mqtt_auth_received{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="success"} 0 +mqtt_auth_received{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="continue_authentication"} 0 +mqtt_auth_received{node="VerneMQ@172.17.0.2",mqtt_version="5",reason_code="reauthenticate"} 0 +# HELP queue_processes The number of MQTT queue processes. +# TYPE queue_processes gauge +queue_processes{node="VerneMQ@172.17.0.2"} 0 +# HELP retain_memory The number of bytes used for storing retained messages. +# TYPE retain_memory gauge +retain_memory{node="VerneMQ@172.17.0.2"} 11344 +# HELP retain_messages The number of currently stored retained messages. +# TYPE retain_messages gauge +retain_messages{node="VerneMQ@172.17.0.2"} 0 +# HELP router_memory The number of bytes used by the routing table. +# TYPE router_memory gauge +router_memory{node="VerneMQ@172.17.0.2"} 12752 +# HELP router_subscriptions The number of subscriptions in the routing table. +# TYPE router_subscriptions gauge +router_subscriptions{node="VerneMQ@172.17.0.2"} 0 +# HELP netsplit_resolved The number of resolved netsplits. +# TYPE netsplit_resolved counter +netsplit_resolved{node="VerneMQ@172.17.0.2"} 0 +# HELP netsplit_detected The number of detected netsplits. +# TYPE netsplit_detected counter +netsplit_detected{node="VerneMQ@172.17.0.2"} 0 +# HELP system_utilization_scheduler_8 Scheduler 8 utilization (percentage) +# TYPE system_utilization_scheduler_8 gauge +system_utilization_scheduler_8{node="VerneMQ@172.17.0.2"} 0 +# HELP system_utilization_scheduler_7 Scheduler 7 utilization (percentage) +# TYPE system_utilization_scheduler_7 gauge +system_utilization_scheduler_7{node="VerneMQ@172.17.0.2"} 0 +# HELP system_utilization_scheduler_6 Scheduler 6 utilization (percentage) +# TYPE system_utilization_scheduler_6 gauge +system_utilization_scheduler_6{node="VerneMQ@172.17.0.2"} 0 +# HELP system_utilization_scheduler_5 Scheduler 5 utilization (percentage) +# TYPE system_utilization_scheduler_5 gauge +system_utilization_scheduler_5{node="VerneMQ@172.17.0.2"} 0 +# HELP system_utilization_scheduler_4 Scheduler 4 utilization (percentage) +# TYPE system_utilization_scheduler_4 gauge +system_utilization_scheduler_4{node="VerneMQ@172.17.0.2"} 19 +# HELP system_utilization_scheduler_3 Scheduler 3 utilization (percentage) +# TYPE system_utilization_scheduler_3 gauge +system_utilization_scheduler_3{node="VerneMQ@172.17.0.2"} 14 +# HELP system_utilization_scheduler_2 Scheduler 2 utilization (percentage) +# TYPE system_utilization_scheduler_2 gauge +system_utilization_scheduler_2{node="VerneMQ@172.17.0.2"} 8 +# HELP system_utilization_scheduler_1 Scheduler 1 utilization (percentage) +# TYPE system_utilization_scheduler_1 gauge +system_utilization_scheduler_1{node="VerneMQ@172.17.0.2"} 34 +# HELP system_utilization The average system (scheduler) utilization (percentage). +# TYPE system_utilization gauge +system_utilization{node="VerneMQ@172.17.0.2"} 9 +# HELP vm_memory_ets The amount of memory allocated for ETS tables. +# TYPE vm_memory_ets gauge +vm_memory_ets{node="VerneMQ@172.17.0.2"} 6065944 +# HELP vm_memory_code The amount of memory allocated for code. +# TYPE vm_memory_code gauge +vm_memory_code{node="VerneMQ@172.17.0.2"} 11372082 +# HELP vm_memory_binary The amount of memory allocated for binaries. +# TYPE vm_memory_binary gauge +vm_memory_binary{node="VerneMQ@172.17.0.2"} 1293672 +# HELP vm_memory_atom_used The amount of memory used by atoms. +# TYPE vm_memory_atom_used gauge +vm_memory_atom_used{node="VerneMQ@172.17.0.2"} 755998 +# HELP vm_memory_atom The amount of memory allocated for atoms. +# TYPE vm_memory_atom gauge +vm_memory_atom{node="VerneMQ@172.17.0.2"} 768953 +# HELP vm_memory_system The amount of memory allocated for the emulator. +# TYPE vm_memory_system gauge +vm_memory_system{node="VerneMQ@172.17.0.2"} 27051848 +# HELP vm_memory_processes_used The amount of memory used by processes. +# TYPE vm_memory_processes_used gauge +vm_memory_processes_used{node="VerneMQ@172.17.0.2"} 8671232 +# HELP vm_memory_processes The amount of memory allocated for processes. +# TYPE vm_memory_processes gauge +vm_memory_processes{node="VerneMQ@172.17.0.2"} 8673288 +# HELP vm_memory_total The total amount of memory allocated. +# TYPE vm_memory_total gauge +vm_memory_total{node="VerneMQ@172.17.0.2"} 35725136 +# HELP system_process_count The number of Erlang processes. +# TYPE system_process_count gauge +system_process_count{node="VerneMQ@172.17.0.2"} 329 +# HELP system_wallclock The number of milli-seconds passed since the node was started. +# TYPE system_wallclock counter +system_wallclock{node="VerneMQ@172.17.0.2"} 163457858 +# HELP system_runtime The sum of the runtime for all threads in the Erlang runtime system. +# TYPE system_runtime counter +system_runtime{node="VerneMQ@172.17.0.2"} 1775355 +# HELP system_run_queue The total number of processes and ports ready to run on all run-queues. +# TYPE system_run_queue gauge +system_run_queue{node="VerneMQ@172.17.0.2"} 0 +# HELP system_reductions The number of reductions performed in the VM since the node was started. +# TYPE system_reductions counter +system_reductions{node="VerneMQ@172.17.0.2"} 3857458067 +# HELP system_io_out The total number of bytes sent through ports. +# TYPE system_io_out counter +system_io_out{node="VerneMQ@172.17.0.2"} 961001488 +# HELP system_io_in The total number of bytes received through ports. +# TYPE system_io_in counter +system_io_in{node="VerneMQ@172.17.0.2"} 68998296 +# HELP system_words_reclaimed_by_gc The number of words reclaimed by the garbage collector. +# TYPE system_words_reclaimed_by_gc counter +system_words_reclaimed_by_gc{node="VerneMQ@172.17.0.2"} 7158470019 +# HELP system_gc_count The number of garbage collections performed. +# TYPE system_gc_count counter +system_gc_count{node="VerneMQ@172.17.0.2"} 12189976 +# HELP system_exact_reductions The exact number of reductions performed. +# TYPE system_exact_reductions counter +system_exact_reductions{node="VerneMQ@172.17.0.2"} 3854024620 +# HELP system_context_switches The total number of context switches. +# TYPE system_context_switches counter +system_context_switches{node="VerneMQ@172.17.0.2"} 39088198
\ No newline at end of file diff --git a/src/go/plugin/go.d/modules/vernemq/testdata/non_vernemq.txt b/src/go/plugin/go.d/modules/vernemq/testdata/non_vernemq.txt new file mode 100644 index 00000000..f5f0ae08 --- /dev/null +++ b/src/go/plugin/go.d/modules/vernemq/testdata/non_vernemq.txt @@ -0,0 +1,27 @@ +# HELP wmi_os_process_memory_limix_bytes OperatingSystem.MaxProcessMemorySize +# TYPE wmi_os_process_memory_limix_bytes gauge +wmi_os_process_memory_limix_bytes 1.40737488224256e+14 +# HELP wmi_os_processes OperatingSystem.NumberOfProcesses +# TYPE wmi_os_processes gauge +wmi_os_processes 124 +# HELP wmi_os_processes_limit OperatingSystem.MaxNumberOfProcesses +# TYPE wmi_os_processes_limit gauge +wmi_os_processes_limit 4.294967295e+09 +# HELP wmi_os_time OperatingSystem.LocalDateTime +# TYPE wmi_os_time gauge +wmi_os_time 1.57804974e+09 +# HELP wmi_os_timezone OperatingSystem.LocalDateTime +# TYPE wmi_os_timezone gauge +wmi_os_timezone{timezone="MSK"} 1 +# HELP wmi_os_users OperatingSystem.NumberOfUsers +# TYPE wmi_os_users gauge +wmi_os_users 2 +# HELP wmi_os_virtual_memory_bytes OperatingSystem.TotalVirtualMemorySize +# TYPE wmi_os_virtual_memory_bytes gauge +wmi_os_virtual_memory_bytes 5.770891264e+09 +# HELP wmi_os_virtual_memory_free_bytes OperatingSystem.FreeVirtualMemory +# TYPE wmi_os_virtual_memory_free_bytes gauge +wmi_os_virtual_memory_free_bytes 3.76489984e+09 +# HELP wmi_os_visible_memory_bytes OperatingSystem.TotalVisibleMemorySize +# TYPE wmi_os_visible_memory_bytes gauge +wmi_os_visible_memory_bytes 4.294496256e+09
\ No newline at end of file diff --git a/src/go/plugin/go.d/modules/vernemq/vernemq.go b/src/go/plugin/go.d/modules/vernemq/vernemq.go new file mode 100644 index 00000000..2f1de38f --- /dev/null +++ b/src/go/plugin/go.d/modules/vernemq/vernemq.go @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package vernemq + +import ( + _ "embed" + "errors" + "time" + + "github.com/netdata/netdata/go/plugins/plugin/go.d/agent/module" + "github.com/netdata/netdata/go/plugins/plugin/go.d/pkg/prometheus" + "github.com/netdata/netdata/go/plugins/plugin/go.d/pkg/web" +) + +//go:embed "config_schema.json" +var configSchema string + +func init() { + module.Register("vernemq", module.Creator{ + JobConfigSchema: configSchema, + Create: func() module.Module { return New() }, + Config: func() any { return &Config{} }, + }) +} + +func New() *VerneMQ { + return &VerneMQ{ + Config: Config{ + HTTP: web.HTTP{ + Request: web.Request{ + URL: "http://127.0.0.1:8888/metrics", + }, + Client: web.Client{ + Timeout: web.Duration(time.Second), + }, + }, + }, + charts: charts.Copy(), + cache: make(map[string]bool), + } +} + +type Config struct { + UpdateEvery int `yaml:"update_every,omitempty" json:"update_every"` + web.HTTP `yaml:",inline" json:""` +} + +type ( + VerneMQ struct { + module.Base + Config `yaml:",inline" json:""` + + charts *Charts + + prom prometheus.Prometheus + + cache map[string]bool + } +) + +func (v *VerneMQ) Configuration() any { + return v.Config +} + +func (v *VerneMQ) Init() error { + if err := v.validateConfig(); err != nil { + v.Errorf("error on validating config: %v", err) + return err + } + + prom, err := v.initPrometheusClient() + if err != nil { + v.Error(err) + return err + } + v.prom = prom + + return nil +} + +func (v *VerneMQ) Check() error { + mx, err := v.collect() + if err != nil { + v.Error(err) + return err + } + if len(mx) == 0 { + return errors.New("no metrics collected") + } + return nil +} + +func (v *VerneMQ) Charts() *Charts { + return v.charts +} + +func (v *VerneMQ) Collect() map[string]int64 { + mx, err := v.collect() + if err != nil { + v.Error(err) + } + + if len(mx) == 0 { + return nil + } + return mx +} + +func (v *VerneMQ) Cleanup() { + if v.prom != nil && v.prom.HTTPClient() != nil { + v.prom.HTTPClient().CloseIdleConnections() + } +} diff --git a/src/go/plugin/go.d/modules/vernemq/vernemq_test.go b/src/go/plugin/go.d/modules/vernemq/vernemq_test.go new file mode 100644 index 00000000..13eb3dce --- /dev/null +++ b/src/go/plugin/go.d/modules/vernemq/vernemq_test.go @@ -0,0 +1,578 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package vernemq + +import ( + "net/http" + "net/http/httptest" + "os" + "testing" + + "github.com/netdata/netdata/go/plugins/plugin/go.d/agent/module" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +var ( + dataConfigJSON, _ = os.ReadFile("testdata/config.json") + dataConfigYAML, _ = os.ReadFile("testdata/config.yaml") + + dataVer1101MQTTv5Metrics, _ = os.ReadFile("testdata/metrics-v1.10.1-mqtt5.txt") + dataUnexpectedMetrics, _ = os.ReadFile("testdata/non_vernemq.txt") +) + +func Test_testDataIsValid(t *testing.T) { + for name, data := range map[string][]byte{ + "dataConfigJSON": dataConfigJSON, + "dataConfigYAML": dataConfigYAML, + "dataVer1101MQTTv5Metrics": dataVer1101MQTTv5Metrics, + "dataUnexpectedMetrics": dataUnexpectedMetrics, + } { + require.NotNil(t, data, name) + } +} + +func TestVerneMQ_ConfigurationSerialize(t *testing.T) { + module.TestConfigurationSerialize(t, &VerneMQ{}, dataConfigJSON, dataConfigYAML) +} + +func TestVerneMQ_Init(t *testing.T) { + verneMQ := prepareVerneMQ() + + assert.NoError(t, verneMQ.Init()) +} + +func TestVerneMQ_Init_ReturnsFalseIfURLIsNotSet(t *testing.T) { + verneMQ := prepareVerneMQ() + verneMQ.URL = "" + + assert.Error(t, verneMQ.Init()) +} + +func TestVerneMQ_Init_ReturnsFalseIfClientWrongTLSCA(t *testing.T) { + verneMQ := prepareVerneMQ() + verneMQ.Client.TLSConfig.TLSCA = "testdata/tls" + + assert.Error(t, verneMQ.Init()) +} + +func TestVerneMQ_Check(t *testing.T) { + verneMQ, srv := prepareClientServerV1101(t) + defer srv.Close() + + assert.NoError(t, verneMQ.Check()) +} + +func TestVerneMQ_Check_ReturnsFalseIfConnectionRefused(t *testing.T) { + verneMQ := prepareVerneMQ() + require.NoError(t, verneMQ.Init()) + + assert.Error(t, verneMQ.Check()) +} + +func TestVerneMQ_Check_ReturnsFalseIfMetricsAreNotVerneMQ(t *testing.T) { + verneMQ, srv := prepareClientServerNotVerneMQ(t) + defer srv.Close() + require.NoError(t, verneMQ.Init()) + + assert.Error(t, verneMQ.Check()) +} + +func TestVerneMQ_Charts(t *testing.T) { + assert.NotNil(t, New().Charts()) +} + +func TestVerneMQ_Cleanup(t *testing.T) { + assert.NotPanics(t, New().Cleanup) +} + +func TestVerneMQ_Collect(t *testing.T) { + verneMQ, srv := prepareClientServerV1101(t) + defer srv.Close() + + collected := verneMQ.Collect() + assert.Equal(t, v1101ExpectedMetrics, collected) + testCharts(t, verneMQ, collected) +} + +func TestVerneMQ_Collect_ReturnsNilIfConnectionRefused(t *testing.T) { + verneMQ := prepareVerneMQ() + require.NoError(t, verneMQ.Init()) + + assert.Nil(t, verneMQ.Collect()) +} + +func TestVerneMQ_Collect_ReturnsNilIfMetricsAreNotVerneMQ(t *testing.T) { + verneMQ, srv := prepareClientServerNotVerneMQ(t) + defer srv.Close() + + assert.Nil(t, verneMQ.Collect()) +} + +func TestVerneMQ_Collect_ReturnsNilIfReceiveInvalidResponse(t *testing.T) { + verneMQ, ts := prepareClientServerInvalid(t) + defer ts.Close() + + assert.Nil(t, verneMQ.Collect()) +} + +func TestVerneMQ_Collect_ReturnsNilIfReceiveResponse404(t *testing.T) { + verneMQ, ts := prepareClientServerResponse404(t) + defer ts.Close() + + assert.Nil(t, verneMQ.Collect()) +} + +func testCharts(t *testing.T, verneMQ *VerneMQ, collected map[string]int64) { + ensureCollectedHasAllChartsDimsVarsIDs(t, verneMQ, collected) +} + +func ensureCollectedHasAllChartsDimsVarsIDs(t *testing.T, verneMQ *VerneMQ, collected map[string]int64) { + for _, chart := range *verneMQ.Charts() { + for _, dim := range chart.Dims { + _, ok := collected[dim.ID] + assert.Truef(t, ok, "collected metrics has no data for dim '%s' chart '%s'", dim.ID, chart.ID) + } + for _, v := range chart.Vars { + _, ok := collected[v.ID] + assert.Truef(t, ok, "collected metrics has no data for var '%s' chart '%s'", v.ID, chart.ID) + } + } +} + +func prepareVerneMQ() *VerneMQ { + verneMQ := New() + verneMQ.URL = "http://127.0.0.1:38001/metrics" + return verneMQ +} + +func prepareClientServerV1101(t *testing.T) (*VerneMQ, *httptest.Server) { + t.Helper() + ts := httptest.NewServer(http.HandlerFunc( + func(w http.ResponseWriter, r *http.Request) { + _, _ = w.Write(dataVer1101MQTTv5Metrics) + })) + + verneMQ := New() + verneMQ.URL = ts.URL + require.NoError(t, verneMQ.Init()) + + return verneMQ, ts +} + +func prepareClientServerNotVerneMQ(t *testing.T) (*VerneMQ, *httptest.Server) { + t.Helper() + ts := httptest.NewServer(http.HandlerFunc( + func(w http.ResponseWriter, r *http.Request) { + _, _ = w.Write(dataUnexpectedMetrics) + })) + + verneMQ := New() + verneMQ.URL = ts.URL + require.NoError(t, verneMQ.Init()) + + return verneMQ, ts +} + +func prepareClientServerInvalid(t *testing.T) (*VerneMQ, *httptest.Server) { + t.Helper() + ts := httptest.NewServer(http.HandlerFunc( + func(w http.ResponseWriter, r *http.Request) { + _, _ = w.Write([]byte("hello and\n goodbye")) + })) + + verneMQ := New() + verneMQ.URL = ts.URL + require.NoError(t, verneMQ.Init()) + + return verneMQ, ts +} + +func prepareClientServerResponse404(t *testing.T) (*VerneMQ, *httptest.Server) { + t.Helper() + ts := httptest.NewServer(http.HandlerFunc( + func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusNotFound) + })) + + verneMQ := New() + verneMQ.URL = ts.URL + require.NoError(t, verneMQ.Init()) + return verneMQ, ts +} + +var v1101ExpectedMetrics = map[string]int64{ + "bytes_received": 36796908, + "bytes_sent": 23361693, + "client_keepalive_expired": 1, + "cluster_bytes_dropped": 0, + "cluster_bytes_received": 0, + "cluster_bytes_sent": 0, + "mqtt_auth_received": 0, + "mqtt_auth_received_continue_authentication": 0, + "mqtt_auth_received_reauthenticate": 0, + "mqtt_auth_received_success": 0, + "mqtt_auth_received_v_5": 0, + "mqtt_auth_received_v_5_continue_authentication": 0, + "mqtt_auth_received_v_5_reauthenticate": 0, + "mqtt_auth_received_v_5_success": 0, + "mqtt_auth_sent": 0, + "mqtt_auth_sent_continue_authentication": 0, + "mqtt_auth_sent_reauthenticate": 0, + "mqtt_auth_sent_success": 0, + "mqtt_auth_sent_v_5": 0, + "mqtt_auth_sent_v_5_continue_authentication": 0, + "mqtt_auth_sent_v_5_reauthenticate": 0, + "mqtt_auth_sent_v_5_success": 0, + "mqtt_connack_sent": 338956, + "mqtt_connack_sent_bad_authentication_method": 0, + "mqtt_connack_sent_bad_username_or_password": 4, + "mqtt_connack_sent_banned": 0, + "mqtt_connack_sent_client_identifier_not_valid": 0, + "mqtt_connack_sent_connection_rate_exceeded": 0, + "mqtt_connack_sent_impl_specific_error": 0, + "mqtt_connack_sent_malformed_packet": 0, + "mqtt_connack_sent_not_authorized": 4, + "mqtt_connack_sent_packet_too_large": 0, + "mqtt_connack_sent_payload_format_invalid": 0, + "mqtt_connack_sent_protocol_error": 0, + "mqtt_connack_sent_qos_not_supported": 0, + "mqtt_connack_sent_quota_exceeded": 0, + "mqtt_connack_sent_retain_not_supported": 0, + "mqtt_connack_sent_server_busy": 0, + "mqtt_connack_sent_server_moved": 0, + "mqtt_connack_sent_server_unavailable": 0, + "mqtt_connack_sent_success": 338948, + "mqtt_connack_sent_topic_name_invalid": 0, + "mqtt_connack_sent_unspecified_error": 0, + "mqtt_connack_sent_unsupported_protocol_version": 0, + "mqtt_connack_sent_use_another_server": 0, + "mqtt_connack_sent_v_4": 338956, + "mqtt_connack_sent_v_4_bad_username_or_password": 4, + "mqtt_connack_sent_v_4_client_identifier_not_valid": 0, + "mqtt_connack_sent_v_4_not_authorized": 4, + "mqtt_connack_sent_v_4_server_unavailable": 0, + "mqtt_connack_sent_v_4_success": 338948, + "mqtt_connack_sent_v_4_unsupported_protocol_version": 0, + "mqtt_connack_sent_v_5": 0, + "mqtt_connack_sent_v_5_bad_authentication_method": 0, + "mqtt_connack_sent_v_5_bad_username_or_password": 0, + "mqtt_connack_sent_v_5_banned": 0, + "mqtt_connack_sent_v_5_client_identifier_not_valid": 0, + "mqtt_connack_sent_v_5_connection_rate_exceeded": 0, + "mqtt_connack_sent_v_5_impl_specific_error": 0, + "mqtt_connack_sent_v_5_malformed_packet": 0, + "mqtt_connack_sent_v_5_not_authorized": 0, + "mqtt_connack_sent_v_5_packet_too_large": 0, + "mqtt_connack_sent_v_5_payload_format_invalid": 0, + "mqtt_connack_sent_v_5_protocol_error": 0, + "mqtt_connack_sent_v_5_qos_not_supported": 0, + "mqtt_connack_sent_v_5_quota_exceeded": 0, + "mqtt_connack_sent_v_5_retain_not_supported": 0, + "mqtt_connack_sent_v_5_server_busy": 0, + "mqtt_connack_sent_v_5_server_moved": 0, + "mqtt_connack_sent_v_5_server_unavailable": 0, + "mqtt_connack_sent_v_5_success": 0, + "mqtt_connack_sent_v_5_topic_name_invalid": 0, + "mqtt_connack_sent_v_5_unspecified_error": 0, + "mqtt_connack_sent_v_5_unsupported_protocol_version": 0, + "mqtt_connack_sent_v_5_use_another_server": 0, + "mqtt_connect_received": 338956, + "mqtt_connect_received_v_4": 338956, + "mqtt_connect_received_v_5": 0, + "mqtt_disconnect_received": 107, + "mqtt_disconnect_received_administrative_action": 0, + "mqtt_disconnect_received_disconnect_with_will_msg": 0, + "mqtt_disconnect_received_impl_specific_error": 0, + "mqtt_disconnect_received_malformed_packet": 0, + "mqtt_disconnect_received_message_rate_too_high": 0, + "mqtt_disconnect_received_normal_disconnect": 0, + "mqtt_disconnect_received_packet_too_large": 0, + "mqtt_disconnect_received_payload_format_invalid": 0, + "mqtt_disconnect_received_protocol_error": 0, + "mqtt_disconnect_received_quota_exceeded": 0, + "mqtt_disconnect_received_receive_max_exceeded": 0, + "mqtt_disconnect_received_topic_alias_invalid": 0, + "mqtt_disconnect_received_topic_name_invalid": 0, + "mqtt_disconnect_received_unspecified_error": 0, + "mqtt_disconnect_received_v_4": 107, + "mqtt_disconnect_received_v_5": 0, + "mqtt_disconnect_received_v_5_administrative_action": 0, + "mqtt_disconnect_received_v_5_disconnect_with_will_msg": 0, + "mqtt_disconnect_received_v_5_impl_specific_error": 0, + "mqtt_disconnect_received_v_5_malformed_packet": 0, + "mqtt_disconnect_received_v_5_message_rate_too_high": 0, + "mqtt_disconnect_received_v_5_normal_disconnect": 0, + "mqtt_disconnect_received_v_5_packet_too_large": 0, + "mqtt_disconnect_received_v_5_payload_format_invalid": 0, + "mqtt_disconnect_received_v_5_protocol_error": 0, + "mqtt_disconnect_received_v_5_quota_exceeded": 0, + "mqtt_disconnect_received_v_5_receive_max_exceeded": 0, + "mqtt_disconnect_received_v_5_topic_alias_invalid": 0, + "mqtt_disconnect_received_v_5_topic_name_invalid": 0, + "mqtt_disconnect_received_v_5_unspecified_error": 0, + "mqtt_disconnect_sent": 0, + "mqtt_disconnect_sent_administrative_action": 0, + "mqtt_disconnect_sent_connection_rate_exceeded": 0, + "mqtt_disconnect_sent_impl_specific_error": 0, + "mqtt_disconnect_sent_keep_alive_timeout": 0, + "mqtt_disconnect_sent_malformed_packet": 0, + "mqtt_disconnect_sent_max_connect_time": 0, + "mqtt_disconnect_sent_message_rate_too_high": 0, + "mqtt_disconnect_sent_normal_disconnect": 0, + "mqtt_disconnect_sent_not_authorized": 0, + "mqtt_disconnect_sent_packet_too_large": 0, + "mqtt_disconnect_sent_payload_format_invalid": 0, + "mqtt_disconnect_sent_protocol_error": 0, + "mqtt_disconnect_sent_qos_not_supported": 0, + "mqtt_disconnect_sent_quota_exceeded": 0, + "mqtt_disconnect_sent_receive_max_exceeded": 0, + "mqtt_disconnect_sent_retain_not_supported": 0, + "mqtt_disconnect_sent_server_busy": 0, + "mqtt_disconnect_sent_server_moved": 0, + "mqtt_disconnect_sent_server_shutting_down": 0, + "mqtt_disconnect_sent_session_taken_over": 0, + "mqtt_disconnect_sent_shared_subs_not_supported": 0, + "mqtt_disconnect_sent_subscription_ids_not_supported": 0, + "mqtt_disconnect_sent_topic_alias_invalid": 0, + "mqtt_disconnect_sent_topic_filter_invalid": 0, + "mqtt_disconnect_sent_topic_name_invalid": 0, + "mqtt_disconnect_sent_unspecified_error": 0, + "mqtt_disconnect_sent_use_another_server": 0, + "mqtt_disconnect_sent_v_5": 0, + "mqtt_disconnect_sent_v_5_administrative_action": 0, + "mqtt_disconnect_sent_v_5_connection_rate_exceeded": 0, + "mqtt_disconnect_sent_v_5_impl_specific_error": 0, + "mqtt_disconnect_sent_v_5_keep_alive_timeout": 0, + "mqtt_disconnect_sent_v_5_malformed_packet": 0, + "mqtt_disconnect_sent_v_5_max_connect_time": 0, + "mqtt_disconnect_sent_v_5_message_rate_too_high": 0, + "mqtt_disconnect_sent_v_5_normal_disconnect": 0, + "mqtt_disconnect_sent_v_5_not_authorized": 0, + "mqtt_disconnect_sent_v_5_packet_too_large": 0, + "mqtt_disconnect_sent_v_5_payload_format_invalid": 0, + "mqtt_disconnect_sent_v_5_protocol_error": 0, + "mqtt_disconnect_sent_v_5_qos_not_supported": 0, + "mqtt_disconnect_sent_v_5_quota_exceeded": 0, + "mqtt_disconnect_sent_v_5_receive_max_exceeded": 0, + "mqtt_disconnect_sent_v_5_retain_not_supported": 0, + "mqtt_disconnect_sent_v_5_server_busy": 0, + "mqtt_disconnect_sent_v_5_server_moved": 0, + "mqtt_disconnect_sent_v_5_server_shutting_down": 0, + "mqtt_disconnect_sent_v_5_session_taken_over": 0, + "mqtt_disconnect_sent_v_5_shared_subs_not_supported": 0, + "mqtt_disconnect_sent_v_5_subscription_ids_not_supported": 0, + "mqtt_disconnect_sent_v_5_topic_alias_invalid": 0, + "mqtt_disconnect_sent_v_5_topic_filter_invalid": 0, + "mqtt_disconnect_sent_v_5_topic_name_invalid": 0, + "mqtt_disconnect_sent_v_5_unspecified_error": 0, + "mqtt_disconnect_sent_v_5_use_another_server": 0, + "mqtt_disconnect_sent_v_5_wildcard_subs_not_supported": 0, + "mqtt_disconnect_sent_wildcard_subs_not_supported": 0, + "mqtt_invalid_msg_size_error": 0, + "mqtt_invalid_msg_size_error_v_4": 0, + "mqtt_invalid_msg_size_error_v_5": 0, + "mqtt_pingreq_received": 205, + "mqtt_pingreq_received_v_4": 205, + "mqtt_pingreq_received_v_5": 0, + "mqtt_pingresp_sent": 205, + "mqtt_pingresp_sent_v_4": 205, + "mqtt_pingresp_sent_v_5": 0, + "mqtt_puback_invalid_error": 0, + "mqtt_puback_invalid_error_v_4": 0, + "mqtt_puback_invalid_error_v_5": 0, + "mqtt_puback_received": 525694, + "mqtt_puback_received_impl_specific_error": 0, + "mqtt_puback_received_no_matching_subscribers": 0, + "mqtt_puback_received_not_authorized": 0, + "mqtt_puback_received_packet_id_in_use": 0, + "mqtt_puback_received_payload_format_invalid": 0, + "mqtt_puback_received_quota_exceeded": 0, + "mqtt_puback_received_success": 0, + "mqtt_puback_received_topic_name_invalid": 0, + "mqtt_puback_received_unspecified_error": 0, + "mqtt_puback_received_v_4": 525694, + "mqtt_puback_received_v_5": 0, + "mqtt_puback_received_v_5_impl_specific_error": 0, + "mqtt_puback_received_v_5_no_matching_subscribers": 0, + "mqtt_puback_received_v_5_not_authorized": 0, + "mqtt_puback_received_v_5_packet_id_in_use": 0, + "mqtt_puback_received_v_5_payload_format_invalid": 0, + "mqtt_puback_received_v_5_quota_exceeded": 0, + "mqtt_puback_received_v_5_success": 0, + "mqtt_puback_received_v_5_topic_name_invalid": 0, + "mqtt_puback_received_v_5_unspecified_error": 0, + "mqtt_puback_sent": 537068, + "mqtt_puback_sent_impl_specific_error": 0, + "mqtt_puback_sent_no_matching_subscribers": 0, + "mqtt_puback_sent_not_authorized": 0, + "mqtt_puback_sent_packet_id_in_use": 0, + "mqtt_puback_sent_payload_format_invalid": 0, + "mqtt_puback_sent_quota_exceeded": 0, + "mqtt_puback_sent_success": 0, + "mqtt_puback_sent_topic_name_invalid": 0, + "mqtt_puback_sent_unspecified_error": 0, + "mqtt_puback_sent_v_4": 537068, + "mqtt_puback_sent_v_5": 0, + "mqtt_puback_sent_v_5_impl_specific_error": 0, + "mqtt_puback_sent_v_5_no_matching_subscribers": 0, + "mqtt_puback_sent_v_5_not_authorized": 0, + "mqtt_puback_sent_v_5_packet_id_in_use": 0, + "mqtt_puback_sent_v_5_payload_format_invalid": 0, + "mqtt_puback_sent_v_5_quota_exceeded": 0, + "mqtt_puback_sent_v_5_success": 0, + "mqtt_puback_sent_v_5_topic_name_invalid": 0, + "mqtt_puback_sent_v_5_unspecified_error": 0, + "mqtt_pubcomp_invalid_error": 0, + "mqtt_pubcomp_invalid_error_v_4": 0, + "mqtt_pubcomp_invalid_error_v_5": 0, + "mqtt_pubcomp_received": 0, + "mqtt_pubcomp_received_packet_id_not_found": 0, + "mqtt_pubcomp_received_success": 0, + "mqtt_pubcomp_received_v_4": 0, + "mqtt_pubcomp_received_v_5": 0, + "mqtt_pubcomp_received_v_5_packet_id_not_found": 0, + "mqtt_pubcomp_received_v_5_success": 0, + "mqtt_pubcomp_sent": 0, + "mqtt_pubcomp_sent_packet_id_not_found": 0, + "mqtt_pubcomp_sent_success": 0, + "mqtt_pubcomp_sent_v_4": 0, + "mqtt_pubcomp_sent_v_5": 0, + "mqtt_pubcomp_sent_v_5_packet_id_not_found": 0, + "mqtt_pubcomp_sent_v_5_success": 0, + "mqtt_publish_auth_error": 0, + "mqtt_publish_auth_error_v_4": 0, + "mqtt_publish_auth_error_v_5": 0, + "mqtt_publish_error": 0, + "mqtt_publish_error_v_4": 0, + "mqtt_publish_error_v_5": 0, + "mqtt_publish_received": 537088, + "mqtt_publish_received_v_4": 537088, + "mqtt_publish_received_v_5": 0, + "mqtt_publish_sent": 525721, + "mqtt_publish_sent_v_4": 525721, + "mqtt_publish_sent_v_5": 0, + "mqtt_pubrec_invalid_error": 0, + "mqtt_pubrec_invalid_error_v_4": 0, + "mqtt_pubrec_received": 0, + "mqtt_pubrec_received_impl_specific_error": 0, + "mqtt_pubrec_received_no_matching_subscribers": 0, + "mqtt_pubrec_received_not_authorized": 0, + "mqtt_pubrec_received_packet_id_in_use": 0, + "mqtt_pubrec_received_payload_format_invalid": 0, + "mqtt_pubrec_received_quota_exceeded": 0, + "mqtt_pubrec_received_success": 0, + "mqtt_pubrec_received_topic_name_invalid": 0, + "mqtt_pubrec_received_unspecified_error": 0, + "mqtt_pubrec_received_v_4": 0, + "mqtt_pubrec_received_v_5": 0, + "mqtt_pubrec_received_v_5_impl_specific_error": 0, + "mqtt_pubrec_received_v_5_no_matching_subscribers": 0, + "mqtt_pubrec_received_v_5_not_authorized": 0, + "mqtt_pubrec_received_v_5_packet_id_in_use": 0, + "mqtt_pubrec_received_v_5_payload_format_invalid": 0, + "mqtt_pubrec_received_v_5_quota_exceeded": 0, + "mqtt_pubrec_received_v_5_success": 0, + "mqtt_pubrec_received_v_5_topic_name_invalid": 0, + "mqtt_pubrec_received_v_5_unspecified_error": 0, + "mqtt_pubrec_sent": 0, + "mqtt_pubrec_sent_impl_specific_error": 0, + "mqtt_pubrec_sent_no_matching_subscribers": 0, + "mqtt_pubrec_sent_not_authorized": 0, + "mqtt_pubrec_sent_packet_id_in_use": 0, + "mqtt_pubrec_sent_payload_format_invalid": 0, + "mqtt_pubrec_sent_quota_exceeded": 0, + "mqtt_pubrec_sent_success": 0, + "mqtt_pubrec_sent_topic_name_invalid": 0, + "mqtt_pubrec_sent_unspecified_error": 0, + "mqtt_pubrec_sent_v_4": 0, + "mqtt_pubrec_sent_v_5": 0, + "mqtt_pubrec_sent_v_5_impl_specific_error": 0, + "mqtt_pubrec_sent_v_5_no_matching_subscribers": 0, + "mqtt_pubrec_sent_v_5_not_authorized": 0, + "mqtt_pubrec_sent_v_5_packet_id_in_use": 0, + "mqtt_pubrec_sent_v_5_payload_format_invalid": 0, + "mqtt_pubrec_sent_v_5_quota_exceeded": 0, + "mqtt_pubrec_sent_v_5_success": 0, + "mqtt_pubrec_sent_v_5_topic_name_invalid": 0, + "mqtt_pubrec_sent_v_5_unspecified_error": 0, + "mqtt_pubrel_received": 0, + "mqtt_pubrel_received_packet_id_not_found": 0, + "mqtt_pubrel_received_success": 0, + "mqtt_pubrel_received_v_4": 0, + "mqtt_pubrel_received_v_5": 0, + "mqtt_pubrel_received_v_5_packet_id_not_found": 0, + "mqtt_pubrel_received_v_5_success": 0, + "mqtt_pubrel_sent": 0, + "mqtt_pubrel_sent_packet_id_not_found": 0, + "mqtt_pubrel_sent_success": 0, + "mqtt_pubrel_sent_v_4": 0, + "mqtt_pubrel_sent_v_5": 0, + "mqtt_pubrel_sent_v_5_packet_id_not_found": 0, + "mqtt_pubrel_sent_v_5_success": 0, + "mqtt_suback_sent": 122, + "mqtt_suback_sent_v_4": 122, + "mqtt_suback_sent_v_5": 0, + "mqtt_subscribe_auth_error": 0, + "mqtt_subscribe_auth_error_v_4": 0, + "mqtt_subscribe_auth_error_v_5": 0, + "mqtt_subscribe_error": 0, + "mqtt_subscribe_error_v_4": 0, + "mqtt_subscribe_error_v_5": 0, + "mqtt_subscribe_received": 122, + "mqtt_subscribe_received_v_4": 122, + "mqtt_subscribe_received_v_5": 0, + "mqtt_unsuback_sent": 108, + "mqtt_unsuback_sent_v_4": 108, + "mqtt_unsuback_sent_v_5": 0, + "mqtt_unsubscribe_error": 0, + "mqtt_unsubscribe_error_v_4": 0, + "mqtt_unsubscribe_error_v_5": 0, + "mqtt_unsubscribe_received": 108, + "mqtt_unsubscribe_received_v_4": 108, + "mqtt_unsubscribe_received_v_5": 0, + "netsplit_detected": 0, + "netsplit_resolved": 0, + "netsplit_unresolved": 0, + "open_sockets": 0, + "queue_initialized_from_storage": 0, + "queue_message_drop": 0, + "queue_message_expired": 0, + "queue_message_in": 525722, + "queue_message_out": 525721, + "queue_message_unhandled": 1, + "queue_processes": 0, + "queue_setup": 338948, + "queue_teardown": 338948, + "retain_memory": 11344, + "retain_messages": 0, + "router_matches_local": 525722, + "router_matches_remote": 0, + "router_memory": 12752, + "router_subscriptions": 0, + "socket_close": 338956, + "socket_close_timeout": 0, + "socket_error": 0, + "socket_open": 338956, + "system_context_switches": 39088198, + "system_gc_count": 12189976, + "system_io_in": 68998296, + "system_io_out": 961001488, + "system_process_count": 329, + "system_reductions": 3857458067, + "system_run_queue": 0, + "system_utilization": 9, + "system_utilization_scheduler_1": 34, + "system_utilization_scheduler_2": 8, + "system_utilization_scheduler_3": 14, + "system_utilization_scheduler_4": 19, + "system_utilization_scheduler_5": 0, + "system_utilization_scheduler_6": 0, + "system_utilization_scheduler_7": 0, + "system_utilization_scheduler_8": 0, + "system_wallclock": 163457858, + "system_words_reclaimed_by_gc": 7158470019, + "vm_memory_processes": 8673288, + "vm_memory_system": 27051848, +} |