From d5112d7766cc26bfc6e8f49641ab4311edaaf4ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan-Otto=20Kr=C3=B6pke?= Date: Sat, 15 Mar 2025 13:27:19 +0100 Subject: [PATCH] net: move net IP addresses from `windows_net_nic_info` to `windows_net_nic_address_info` and introduce mac addresses (#1940) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jan-Otto Kröpke --- docs/collector.net.md | 33 ++++++------ internal/collector/net/net.go | 99 +++++++++++++++++++++++------------ tools/e2e-output.txt | 3 +- tools/end-to-end-test.ps1 | 2 +- 4 files changed, 87 insertions(+), 50 deletions(-) diff --git a/docs/collector.net.md b/docs/collector.net.md index 112c1718..52dd118d 100644 --- a/docs/collector.net.md +++ b/docs/collector.net.md @@ -25,21 +25,24 @@ Comma-separated list of collectors to use. Defaults to all, if not specified. ## Metrics -Name | Description | Type | Labels ------|-------------|------|------- -`windows_net_bytes_received_total` | Total bytes received by interface | counter | `nic` -`windows_net_bytes_sent_total` | Total bytes transmitted by interface | counter | `nic` -`windows_net_bytes_total` | Total bytes received and transmitted by interface | counter | `nic` -`windows_net_output_queue_length_packets` | Length of the output packet queue (in packets). If this is longer than 2, delays occur. | gauge | `nic` -`windows_net_packets_outbound_discarded_total` | Total outbound packets that were chosen to be discarded even though no errors had been detected to prevent transmission | counter | `nic` -`windows_net_packets_outbound_errors_total` | Total packets that could not be transmitted due to errors | counter | `nic` -`windows_net_packets_received_discarded_total` | Total inbound packets that were chosen to be discarded even though no errors had been detected to prevent delivery | counter | `nic` -`windows_net_packets_received_errors_total` | Total packets that could not be received due to errors | counter | `nic` -`windows_net_packets_received_total` | Total packets received by interface | counter | `nic` -`windows_net_packets_received_unknown_total` | Total packets received by interface that were discarded because of an unknown or unsupported protocol | counter | `nic` -`windows_net_packets_total` | Total packets received and transmitted by interface | counter | `nic` -`windows_net_packets_sent_total` | Total packets transmitted by interface | counter | `nic` -`windows_net_current_bandwidth_bytes` | Estimate of the interface's current bandwidth in bytes per second | gauge | `nic` +| Name | Description | Type | Labels | +|------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------|---------|--------------------------------| +| `windows_net_bytes_received_total` | Total bytes received by interface | counter | `nic` | +| `windows_net_bytes_sent_total` | Total bytes transmitted by interface | counter | `nic` | +| `windows_net_bytes_total` | Total bytes received and transmitted by interface | counter | `nic` | +| `windows_net_output_queue_length_packets` | Length of the output packet queue (in packets). If this is longer than 2, delays occur. | gauge | `nic` | +| `windows_net_packets_outbound_discarded_total` | Total outbound packets that were chosen to be discarded even though no errors had been detected to prevent transmission | counter | `nic` | +| `windows_net_packets_outbound_errors_total` | Total packets that could not be transmitted due to errors | counter | `nic` | +| `windows_net_packets_received_discarded_total` | Total inbound packets that were chosen to be discarded even though no errors had been detected to prevent delivery | counter | `nic` | +| `windows_net_packets_received_errors_total` | Total packets that could not be received due to errors | counter | `nic` | +| `windows_net_packets_received_total` | Total packets received by interface | counter | `nic` | +| `windows_net_packets_received_unknown_total` | Total packets received by interface that were discarded because of an unknown or unsupported protocol | counter | `nic` | +| `windows_net_packets_total` | Total packets received and transmitted by interface | counter | `nic` | +| `windows_net_packets_sent_total` | Total packets transmitted by interface | counter | `nic` | +| `windows_net_current_bandwidth_bytes` | Estimate of the interface's current bandwidth in bytes per second | gauge | `nic` | +| `windows_net_nic_address_info` | A metric with a constant '1' value labeled with the network interface's address information. | gauge | `nic`, `address`, `family` | +| `windows_net_nic_info` | A metric with a constant '1' value labeled with the network interface's general information. | gauge | `nic`, `friendly_name`, `mac` | +| `windows_net_route_info` | A metric with a constant '1' value labeled with the network interface's route information. | gauge | `nic`, `src`, `dest`, `metric` | ### Example metric Query the rate of transmitted network traffic diff --git a/internal/collector/net/net.go b/internal/collector/net/net.go index 7e445c09..ba1e7046 100644 --- a/internal/collector/net/net.go +++ b/internal/collector/net/net.go @@ -33,7 +33,12 @@ import ( "golang.org/x/sys/windows" ) -const Name = "net" +const ( + Name = "net" + + subCollectorMetrics = "metrics" + subCollectorNicAddresses = "nic_addresses" +) type Config struct { NicExclude *regexp.Regexp `yaml:"nic_exclude"` @@ -46,8 +51,8 @@ var ConfigDefaults = Config{ NicExclude: types.RegExpEmpty, NicInclude: types.RegExpAny, CollectorsEnabled: []string{ - "metrics", - "nic_addresses", + subCollectorMetrics, + subCollectorNicAddresses, }, } @@ -72,8 +77,9 @@ type Collector struct { packetsSentTotal *prometheus.Desc currentBandwidth *prometheus.Desc - nicAddressInfo *prometheus.Desc - routeInfo *prometheus.Desc + nicIPAddressInfo *prometheus.Desc + nicInfo *prometheus.Desc + routeInfo *prometheus.Desc } func New(config *Config) *Collector { @@ -157,19 +163,6 @@ func (c *Collector) Close() error { } func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error { - var err error - - c.perfDataCollector, err = pdh.NewCollector[perfDataCounterValues](pdh.CounterTypeRaw, "Network Interface", pdh.InstancesAll) - if err != nil { - return fmt.Errorf("failed to create Network Interface collector: %w", err) - } - - if slices.Contains(c.config.CollectorsEnabled, "addresses") { - logger.Info("nic/addresses collector is in an experimental state! The configuration and metrics may change in future. Please report any issues.", - slog.String("collector", Name), - ) - } - c.bytesReceivedTotal = prometheus.NewDesc( prometheus.BuildFQName(types.Namespace, Name, "bytes_received_total"), "(Network.BytesReceivedPerSec)", @@ -248,10 +241,16 @@ func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error { []string{"nic"}, nil, ) - c.nicAddressInfo = prometheus.NewDesc( + c.nicIPAddressInfo = prometheus.NewDesc( prometheus.BuildFQName(types.Namespace, Name, "nic_address_info"), "A metric with a constant '1' value labeled with the network interface's address information.", - []string{"nic", "friendly_name", "address", "family"}, + []string{"nic", "address", "family"}, + nil, + ) + c.nicInfo = prometheus.NewDesc( + prometheus.BuildFQName(types.Namespace, Name, "nic_info"), + "A metric with a constant '1' value labeled with the network interface's general information.", + []string{"nic", "friendly_name", "mac"}, nil, ) c.routeInfo = prometheus.NewDesc( @@ -261,6 +260,19 @@ func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error { nil, ) + var err error + + c.perfDataCollector, err = pdh.NewCollector[perfDataCounterValues](pdh.CounterTypeRaw, "Network Interface", pdh.InstancesAll) + if err != nil { + return fmt.Errorf("failed to create Network Interface collector: %w", err) + } + + if slices.Contains(c.config.CollectorsEnabled, subCollectorNicAddresses) { + logger.Info("nic/addresses collector is in an experimental state! The configuration and metrics may change in future. Please report any issues.", + slog.String("collector", Name), + ) + } + return nil } @@ -269,13 +281,13 @@ func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error { func (c *Collector) Collect(ch chan<- prometheus.Metric) error { errs := make([]error, 0, 2) - if slices.Contains(c.config.CollectorsEnabled, "metrics") { + if slices.Contains(c.config.CollectorsEnabled, subCollectorMetrics) { if err := c.collect(ch); err != nil { errs = append(errs, fmt.Errorf("failed collecting metrics: %w", err)) } } - if slices.Contains(c.config.CollectorsEnabled, "nic_addresses") { + if slices.Contains(c.config.CollectorsEnabled, subCollectorNicAddresses) { if err := c.collectNICAddresses(ch); err != nil { errs = append(errs, fmt.Errorf("failed collecting net addresses: %w", err)) } @@ -393,16 +405,38 @@ func (c *Collector) collectNICAddresses(ch chan<- prometheus.Metric) error { convertNicName := strings.NewReplacer("(", "[", ")", "]", "#", "_") - for _, nicAdapterAddress := range nicAdapterAddresses { - friendlyName := windows.UTF16PtrToString(nicAdapterAddress.FriendlyName) - nicName := windows.UTF16PtrToString(nicAdapterAddress.Description) + for _, nicAdapter := range nicAdapterAddresses { + friendlyName := windows.UTF16PtrToString(nicAdapter.FriendlyName) + nicName := convertNicName.Replace(windows.UTF16PtrToString(nicAdapter.Description)) if c.config.NicExclude.MatchString(nicName) || !c.config.NicInclude.MatchString(nicName) { continue } - for address := nicAdapterAddress.FirstUnicastAddress; address != nil; address = address.Next { + macAddress := fmt.Sprintf("%02X:%02X:%02X:%02X:%02X:%02X", + nicAdapter.PhysicalAddress[0], + nicAdapter.PhysicalAddress[1], + nicAdapter.PhysicalAddress[2], + nicAdapter.PhysicalAddress[3], + nicAdapter.PhysicalAddress[4], + nicAdapter.PhysicalAddress[5], + ) + + ch <- prometheus.MustNewConstMetric( + c.nicInfo, + prometheus.GaugeValue, + 1, + nicName, + friendlyName, + macAddress, + ) + + if nicAdapter.OperStatus != windows.IfOperStatusUp { + continue + } + + for address := nicAdapter.FirstUnicastAddress; address != nil; address = address.Next { ipAddr := address.Address.IP() if ipAddr == nil || !ipAddr.IsGlobalUnicast() { @@ -410,17 +444,16 @@ func (c *Collector) collectNICAddresses(ch chan<- prometheus.Metric) error { } ch <- prometheus.MustNewConstMetric( - c.nicAddressInfo, + c.nicIPAddressInfo, prometheus.GaugeValue, 1, - convertNicName.Replace(nicName), - friendlyName, + nicName, ipAddr.String(), addressFamily[address.Address.Sockaddr.Addr.Family], ) } - for address := nicAdapterAddress.FirstAnycastAddress; address != nil; address = address.Next { + for address := nicAdapter.FirstAnycastAddress; address != nil; address = address.Next { ipAddr := address.Address.IP() if ipAddr == nil || !ipAddr.IsGlobalUnicast() { @@ -428,11 +461,10 @@ func (c *Collector) collectNICAddresses(ch chan<- prometheus.Metric) error { } ch <- prometheus.MustNewConstMetric( - c.nicAddressInfo, + c.nicIPAddressInfo, prometheus.GaugeValue, 1, - convertNicName.Replace(nicName), - friendlyName, + nicName, ipAddr.String(), addressFamily[address.Address.Sockaddr.Addr.Family], ) @@ -475,6 +507,7 @@ func adapterAddresses() ([]*windows.IpAdapterAddresses, error) { } var addresses []*windows.IpAdapterAddresses + for address := (*windows.IpAdapterAddresses)(unsafe.Pointer(&b[0])); address != nil; address = address.Next { addresses = append(addresses, address) } diff --git a/tools/e2e-output.txt b/tools/e2e-output.txt index a5dcfec0..8705d5ac 100644 --- a/tools/e2e-output.txt +++ b/tools/e2e-output.txt @@ -275,6 +275,8 @@ windows_exporter_collector_timeout{collector="udp"} 0 # TYPE windows_net_current_bandwidth_bytes gauge # HELP windows_net_nic_address_info A metric with a constant '1' value labeled with the network interface's address information. # TYPE windows_net_nic_address_info gauge +# HELP windows_net_nic_info A metric with a constant '1' value labeled with the network interface's general information. +# TYPE windows_net_nic_info gauge # HELP windows_net_output_queue_length_packets (Network.OutputQueueLength) # TYPE windows_net_output_queue_length_packets gauge # HELP windows_net_packets_outbound_discarded_total (Network.PacketsOutboundDiscarded) @@ -453,4 +455,3 @@ windows_service_state{name="Themes",state="stopped"} 0 # TYPE windows_udp_datagram_received_total gauge # HELP windows_udp_datagram_sent_total UDP datagrams are sent from the entity # TYPE windows_udp_datagram_sent_total counter - diff --git a/tools/end-to-end-test.ps1 b/tools/end-to-end-test.ps1 index 49de5b5a..0ecc27a8 100644 --- a/tools/end-to-end-test.ps1 +++ b/tools/end-to-end-test.ps1 @@ -66,7 +66,7 @@ try { throw $_ } -$output_diff = Compare-Object (Get-Content 'e2e-output.txt') (Get-Content "$($temp_dir)/e2e-output.txt") +$output_diff = Compare-Object ((Get-Content 'e2e-output.txt' | Out-String).Trim()) ((Get-Content "$($temp_dir)/e2e-output.txt" | Out-String).Trim()) # Fail if differences in output are detected if (-not ($null -eq $output_diff)) {