From efb20b1e31af4a4be2dade90de7048d40b2e4e34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan-Otto=20Kr=C3=B6pke?= Date: Sun, 6 Oct 2024 00:22:58 +0200 Subject: [PATCH] dns: Implement Perfdata collector (#1672) --- internal/collector/dns/const.go | 92 ++++++++++++++ internal/collector/dns/dns.go | 212 +++++++++++++++----------------- 2 files changed, 193 insertions(+), 111 deletions(-) create mode 100644 internal/collector/dns/const.go diff --git a/internal/collector/dns/const.go b/internal/collector/dns/const.go new file mode 100644 index 00000000..17a1fdf2 --- /dev/null +++ b/internal/collector/dns/const.go @@ -0,0 +1,92 @@ +package dns + +const ( + _ = "% User Time" + _ = "176" + _ = "Async Fast Reads/sec" + axfrRequestReceived = "AXFR Request Received" + axfrRequestSent = "AXFR Request Sent" + axfrResponseReceived = "AXFR Response Received" + axfrSuccessReceived = "AXFR Success Received" + axfrSuccessSent = "AXFR Success Sent" + cachingMemory = "Caching Memory" + _ = "Data Flush Pages/sec" + _ = "Data Flushes/sec" + databaseNodeMemory = "Database Node Memory" + dynamicUpdateNoOperation = "Dynamic Update NoOperation" + _ = "Dynamic Update NoOperation/sec" + dynamicUpdateQueued = "Dynamic Update Queued" + _ = "Dynamic Update Received" + _ = "Dynamic Update Received/sec" + dynamicUpdateRejected = "Dynamic Update Rejected" + dynamicUpdateTimeOuts = "Dynamic Update TimeOuts" + dynamicUpdateWrittenToDatabase = "Dynamic Update Written to Database" + _ = "Dynamic Update Written to Database/sec" + _ = "Enumerations Server/sec" + _ = "Fast Read Not Possibles/sec" + _ = "Fast Read Resource Misses/sec" + ixfrRequestReceived = "IXFR Request Received" + ixfrRequestSent = "IXFR Request Sent" + ixfrResponseReceived = "IXFR Response Received" + _ = "IXFR Success Received" + ixfrSuccessSent = "IXFR Success Sent" + ixfrTCPSuccessReceived = "IXFR TCP Success Received" + ixfrUDPSuccessReceived = "IXFR UDP Success Received" + _ = "Lazy Write Flushes/sec" + _ = "Lazy Write Pages/sec" + _ = "Level 2 TLB Fills/sec" + nbStatMemory = "Nbstat Memory" + notifyReceived = "Notify Received" + notifySent = "Notify Sent" + _ = "Query Dropped Bad Socket" + _ = "Query Dropped Bad Socket/sec" + _ = "Query Dropped By Policy" + _ = "Query Dropped By Policy/sec" + _ = "Query Dropped By Response Rate Limiting" + _ = "Query Dropped By Response Rate Limiting/sec" + _ = "Query Dropped Send" + _ = "Query Dropped Send/sec" + _ = "Query Dropped Total" + _ = "Query Dropped Total/sec" + recordFlowMemory = "Record Flow Memory" + recursiveQueries = "Recursive Queries" + _ = "Recursive Queries/sec" + recursiveQueryFailure = "Recursive Query Failure" + _ = "Recursive Query Failure/sec" + _ = "Recursive Send TimeOuts" + recursiveSendTimeOuts = "Recursive TimeOut/sec" + _ = "Responses Suppressed" + _ = "Responses Suppressed/sec" + secureUpdateFailure = "Secure Update Failure" + secureUpdateReceived = "Secure Update Received" + _ = "Secure Update Received/sec" + tcpMessageMemory = "TCP Message Memory" + tcpQueryReceived = "TCP Query Received" + _ = "TCP Query Received/sec" + tcpResponseSent = "TCP Response Sent" + _ = "TCP Response Sent/sec" + _ = "Total Query Received" + _ = "Total Query Received/sec" + _ = "Total Remote Inflight Queries" + _ = "Total Response Sent" + _ = "Total Response Sent/sec" + udpMessageMemory = "UDP Message Memory" + udpQueryReceived = "UDP Query Received" + _ = "UDP Query Received/sec" + udpResponseSent = "UDP Response Sent" + _ = "UDP Response Sent/sec" + unmatchedResponsesReceived = "Unmatched Responses Received" + _ = "Virtual Bytes" + winsLookupReceived = "WINS Lookup Received" + _ = "WINS Lookup Received/sec" + winsResponseSent = "WINS Response Sent" + _ = "WINS Response Sent/sec" + winsReverseLookupReceived = "WINS Reverse Lookup Received" + _ = "WINS Reverse Lookup Received/sec" + winsReverseResponseSent = "WINS Reverse Response Sent" + _ = "WINS Reverse Response Sent/sec" + zoneTransferFailure = "Zone Transfer Failure" + zoneTransferSOARequestSent = "Zone Transfer Request Received" + _ = "Zone Transfer SOA Request Sent" + _ = "Zone Transfer Success" +) diff --git a/internal/collector/dns/dns.go b/internal/collector/dns/dns.go index 97fdbb80..d83472f9 100644 --- a/internal/collector/dns/dns.go +++ b/internal/collector/dns/dns.go @@ -4,9 +4,12 @@ package dns import ( "errors" + "fmt" "log/slog" "github.com/alecthomas/kingpin/v2" + "github.com/prometheus-community/windows_exporter/internal/perfdata" + "github.com/prometheus-community/windows_exporter/internal/perfdata/perftypes" "github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus/client_golang/prometheus" "github.com/yusufpapurcu/wmi" @@ -20,8 +23,9 @@ var ConfigDefaults = Config{} // A Collector is a Prometheus Collector for WMI Win32_PerfRawData_DNS_DNS metrics. type Collector struct { - config Config - wmiClient *wmi.Client + config Config + + perfDataCollector perfdata.Collector dynamicUpdatesFailures *prometheus.Desc dynamicUpdatesQueued *prometheus.Desc @@ -75,12 +79,56 @@ func (c *Collector) Close(_ *slog.Logger) error { return nil } -func (c *Collector) Build(_ *slog.Logger, wmiClient *wmi.Client) error { - if wmiClient == nil || wmiClient.SWbemServicesClient == nil { - return errors.New("wmiClient or SWbemServicesClient is nil") +func (c *Collector) Build(_ *slog.Logger, _ *wmi.Client) error { + counters := []string{ + axfrRequestReceived, + axfrRequestSent, + axfrResponseReceived, + axfrSuccessReceived, + axfrSuccessSent, + cachingMemory, + databaseNodeMemory, + dynamicUpdateNoOperation, + dynamicUpdateQueued, + dynamicUpdateRejected, + dynamicUpdateTimeOuts, + dynamicUpdateWrittenToDatabase, + ixfrRequestReceived, + ixfrRequestSent, + ixfrResponseReceived, + ixfrSuccessSent, + ixfrTCPSuccessReceived, + ixfrUDPSuccessReceived, + nbStatMemory, + notifyReceived, + notifySent, + recordFlowMemory, + recursiveQueries, + recursiveQueryFailure, + recursiveSendTimeOuts, + secureUpdateFailure, + secureUpdateReceived, + tcpMessageMemory, + tcpQueryReceived, + tcpResponseSent, + udpMessageMemory, + udpQueryReceived, + udpResponseSent, + unmatchedResponsesReceived, + winsLookupReceived, + winsResponseSent, + winsReverseLookupReceived, + winsReverseResponseSent, + zoneTransferFailure, + zoneTransferSOARequestSent, } - c.wmiClient = wmiClient + var err error + + c.perfDataCollector, err = perfdata.NewCollector(perfdata.V1, "DNS", perfdata.AllInstances, counters) + if err != nil { + return fmt.Errorf("failed to create DNS collector: %w", err) + } c.zoneTransferRequestsReceived = prometheus.NewDesc( prometheus.BuildFQName(types.Namespace, Name, "zone_transfer_requests_received_total"), @@ -220,138 +268,80 @@ func (c *Collector) Build(_ *slog.Logger, wmiClient *wmi.Client) error { // Collect sends the metric values for each metric // to the provided prometheus Metric channel. -func (c *Collector) Collect(_ *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error { - logger = logger.With(slog.String("collector", Name)) - if err := c.collect(ch); err != nil { - logger.Error("failed collecting dns metrics", - slog.Any("err", err), - ) - - return err +func (c *Collector) Collect(_ *types.ScrapeContext, _ *slog.Logger, ch chan<- prometheus.Metric) error { + perfData, err := c.perfDataCollector.Collect() + if err != nil { + return fmt.Errorf("failed to collect DNS metrics: %w", err) } - return nil -} - -// Win32_PerfRawData_DNS_DNS docs: -// - https://msdn.microsoft.com/en-us/library/ms803992.aspx?f=255&MSPPError=-2147217396 -// - https://technet.microsoft.com/en-us/library/cc977686.aspx -type Win32_PerfRawData_DNS_DNS struct { - AXFRRequestReceived uint32 - AXFRRequestSent uint32 - AXFRResponseReceived uint32 - AXFRSuccessReceived uint32 - AXFRSuccessSent uint32 - CachingMemory uint32 - DatabaseNodeMemory uint32 - DynamicUpdateNoOperation uint32 - DynamicUpdateQueued uint32 - DynamicUpdateRejected uint32 - DynamicUpdateTimeOuts uint32 - DynamicUpdateWrittentoDatabase uint32 - IXFRRequestReceived uint32 - IXFRRequestSent uint32 - IXFRResponseReceived uint32 - IXFRSuccessSent uint32 - IXFRTCPSuccessReceived uint32 - IXFRUDPSuccessReceived uint32 - NbstatMemory uint32 - NotifyReceived uint32 - NotifySent uint32 - RecordFlowMemory uint32 - RecursiveQueries uint32 - RecursiveQueryFailure uint32 - RecursiveSendTimeOuts uint32 - SecureUpdateFailure uint32 - SecureUpdateReceived uint32 - TCPMessageMemory uint32 - TCPQueryReceived uint32 - TCPResponseSent uint32 - UDPMessageMemory uint32 - UDPQueryReceived uint32 - UDPResponseSent uint32 - UnmatchedResponsesReceived uint32 - WINSLookupReceived uint32 - WINSResponseSent uint32 - WINSReverseLookupReceived uint32 - WINSReverseResponseSent uint32 - ZoneTransferFailure uint32 - ZoneTransferSOARequestSent uint32 -} - -func (c *Collector) collect(ch chan<- prometheus.Metric) error { - var dst []Win32_PerfRawData_DNS_DNS - if err := c.wmiClient.Query("SELECT * FROM Win32_PerfRawData_DNS_DNS", &dst); err != nil { - return err - } - - if len(dst) == 0 { - return errors.New("WMI query returned empty result set") + data, ok := perfData[perftypes.EmptyInstance] + if !ok { + return errors.New("perflib query for DNS returned empty result set") } ch <- prometheus.MustNewConstMetric( c.zoneTransferRequestsReceived, prometheus.CounterValue, - float64(dst[0].AXFRRequestReceived), + data[axfrRequestReceived].FirstValue, "full", ) ch <- prometheus.MustNewConstMetric( c.zoneTransferRequestsReceived, prometheus.CounterValue, - float64(dst[0].IXFRRequestReceived), + data[ixfrRequestReceived].FirstValue, "incremental", ) ch <- prometheus.MustNewConstMetric( c.zoneTransferRequestsSent, prometheus.CounterValue, - float64(dst[0].AXFRRequestSent), + data[axfrRequestSent].FirstValue, "full", ) ch <- prometheus.MustNewConstMetric( c.zoneTransferRequestsSent, prometheus.CounterValue, - float64(dst[0].IXFRRequestSent), + data[ixfrRequestSent].FirstValue, "incremental", ) ch <- prometheus.MustNewConstMetric( c.zoneTransferRequestsSent, prometheus.CounterValue, - float64(dst[0].ZoneTransferSOARequestSent), + data[zoneTransferSOARequestSent].FirstValue, "soa", ) ch <- prometheus.MustNewConstMetric( c.zoneTransferResponsesReceived, prometheus.CounterValue, - float64(dst[0].AXFRResponseReceived), + data[axfrResponseReceived].FirstValue, "full", ) ch <- prometheus.MustNewConstMetric( c.zoneTransferResponsesReceived, prometheus.CounterValue, - float64(dst[0].IXFRResponseReceived), + data[ixfrResponseReceived].FirstValue, "incremental", ) ch <- prometheus.MustNewConstMetric( c.zoneTransferSuccessReceived, prometheus.CounterValue, - float64(dst[0].AXFRSuccessReceived), + data[axfrSuccessReceived].FirstValue, "full", "tcp", ) ch <- prometheus.MustNewConstMetric( c.zoneTransferSuccessReceived, prometheus.CounterValue, - float64(dst[0].IXFRTCPSuccessReceived), + data[ixfrTCPSuccessReceived].FirstValue, "incremental", "tcp", ) ch <- prometheus.MustNewConstMetric( c.zoneTransferSuccessReceived, prometheus.CounterValue, - float64(dst[0].IXFRTCPSuccessReceived), + data[ixfrTCPSuccessReceived].FirstValue, "incremental", "udp", ) @@ -359,183 +349,183 @@ func (c *Collector) collect(ch chan<- prometheus.Metric) error { ch <- prometheus.MustNewConstMetric( c.zoneTransferSuccessSent, prometheus.CounterValue, - float64(dst[0].AXFRSuccessSent), + data[axfrSuccessSent].FirstValue, "full", ) ch <- prometheus.MustNewConstMetric( c.zoneTransferSuccessSent, prometheus.CounterValue, - float64(dst[0].IXFRSuccessSent), + data[ixfrSuccessSent].FirstValue, "incremental", ) ch <- prometheus.MustNewConstMetric( c.zoneTransferFailures, prometheus.CounterValue, - float64(dst[0].ZoneTransferFailure), + data[zoneTransferFailure].FirstValue, ) ch <- prometheus.MustNewConstMetric( c.memoryUsedBytes, prometheus.GaugeValue, - float64(dst[0].CachingMemory), + data[cachingMemory].FirstValue, "caching", ) ch <- prometheus.MustNewConstMetric( c.memoryUsedBytes, prometheus.GaugeValue, - float64(dst[0].DatabaseNodeMemory), + data[databaseNodeMemory].FirstValue, "database_node", ) ch <- prometheus.MustNewConstMetric( c.memoryUsedBytes, prometheus.GaugeValue, - float64(dst[0].NbstatMemory), + data[nbStatMemory].FirstValue, "nbstat", ) ch <- prometheus.MustNewConstMetric( c.memoryUsedBytes, prometheus.GaugeValue, - float64(dst[0].RecordFlowMemory), + data[recordFlowMemory].FirstValue, "record_flow", ) ch <- prometheus.MustNewConstMetric( c.memoryUsedBytes, prometheus.GaugeValue, - float64(dst[0].TCPMessageMemory), + data[tcpMessageMemory].FirstValue, "tcp_message", ) ch <- prometheus.MustNewConstMetric( c.memoryUsedBytes, prometheus.GaugeValue, - float64(dst[0].UDPMessageMemory), + data[udpMessageMemory].FirstValue, "udp_message", ) ch <- prometheus.MustNewConstMetric( c.dynamicUpdatesReceived, prometheus.CounterValue, - float64(dst[0].DynamicUpdateNoOperation), + data[dynamicUpdateNoOperation].FirstValue, "noop", ) ch <- prometheus.MustNewConstMetric( c.dynamicUpdatesReceived, prometheus.CounterValue, - float64(dst[0].DynamicUpdateWrittentoDatabase), + data[dynamicUpdateWrittenToDatabase].FirstValue, "written", ) ch <- prometheus.MustNewConstMetric( c.dynamicUpdatesQueued, prometheus.GaugeValue, - float64(dst[0].DynamicUpdateQueued), + data[dynamicUpdateQueued].FirstValue, ) ch <- prometheus.MustNewConstMetric( c.dynamicUpdatesFailures, prometheus.CounterValue, - float64(dst[0].DynamicUpdateRejected), + data[dynamicUpdateRejected].FirstValue, "rejected", ) ch <- prometheus.MustNewConstMetric( c.dynamicUpdatesFailures, prometheus.CounterValue, - float64(dst[0].DynamicUpdateTimeOuts), + data[dynamicUpdateTimeOuts].FirstValue, "timeout", ) ch <- prometheus.MustNewConstMetric( c.notifyReceived, prometheus.CounterValue, - float64(dst[0].NotifyReceived), + data[notifyReceived].FirstValue, ) ch <- prometheus.MustNewConstMetric( c.notifySent, prometheus.CounterValue, - float64(dst[0].NotifySent), + data[notifySent].FirstValue, ) ch <- prometheus.MustNewConstMetric( c.recursiveQueries, prometheus.CounterValue, - float64(dst[0].RecursiveQueries), + data[recursiveQueries].FirstValue, ) ch <- prometheus.MustNewConstMetric( c.recursiveQueryFailures, prometheus.CounterValue, - float64(dst[0].RecursiveQueryFailure), + data[recursiveQueryFailure].FirstValue, ) ch <- prometheus.MustNewConstMetric( c.recursiveQuerySendTimeouts, prometheus.CounterValue, - float64(dst[0].RecursiveSendTimeOuts), + data[recursiveSendTimeOuts].FirstValue, ) ch <- prometheus.MustNewConstMetric( c.queries, prometheus.CounterValue, - float64(dst[0].TCPQueryReceived), + data[tcpQueryReceived].FirstValue, "tcp", ) ch <- prometheus.MustNewConstMetric( c.queries, prometheus.CounterValue, - float64(dst[0].UDPQueryReceived), + data[udpQueryReceived].FirstValue, "udp", ) ch <- prometheus.MustNewConstMetric( c.responses, prometheus.CounterValue, - float64(dst[0].TCPResponseSent), + data[tcpResponseSent].FirstValue, "tcp", ) ch <- prometheus.MustNewConstMetric( c.responses, prometheus.CounterValue, - float64(dst[0].UDPResponseSent), + data[udpResponseSent].FirstValue, "udp", ) ch <- prometheus.MustNewConstMetric( c.unmatchedResponsesReceived, prometheus.CounterValue, - float64(dst[0].UnmatchedResponsesReceived), + data[unmatchedResponsesReceived].FirstValue, ) ch <- prometheus.MustNewConstMetric( c.winsQueries, prometheus.CounterValue, - float64(dst[0].WINSLookupReceived), + data[winsLookupReceived].FirstValue, "forward", ) ch <- prometheus.MustNewConstMetric( c.winsQueries, prometheus.CounterValue, - float64(dst[0].WINSReverseLookupReceived), + data[winsReverseLookupReceived].FirstValue, "reverse", ) ch <- prometheus.MustNewConstMetric( c.winsResponses, prometheus.CounterValue, - float64(dst[0].WINSResponseSent), + data[winsResponseSent].FirstValue, "forward", ) ch <- prometheus.MustNewConstMetric( c.winsResponses, prometheus.CounterValue, - float64(dst[0].WINSReverseResponseSent), + data[winsReverseResponseSent].FirstValue, "reverse", ) ch <- prometheus.MustNewConstMetric( c.secureUpdateFailures, prometheus.CounterValue, - float64(dst[0].SecureUpdateFailure), + data[secureUpdateFailure].FirstValue, ) ch <- prometheus.MustNewConstMetric( c.secureUpdateReceived, prometheus.CounterValue, - float64(dst[0].SecureUpdateReceived), + data[secureUpdateReceived].FirstValue, ) return nil