From 69368b7f9c2a97aeef313aa5ea2b2267877d20dd Mon Sep 17 00:00:00 2001 From: Matt Layher Date: Mon, 13 Mar 2017 16:20:42 -0400 Subject: [PATCH] Add synthetic node_wifi_station_info metric for BSS information --- collector/fixtures/e2e-output.txt | 3 ++ collector/fixtures/wifi/wlan0/bss.json | 5 +++ collector/wifi_linux.go | 52 ++++++++++++++++++++++++++ 3 files changed, 60 insertions(+) create mode 100644 collector/fixtures/wifi/wlan0/bss.json diff --git a/collector/fixtures/e2e-output.txt b/collector/fixtures/e2e-output.txt index feac6c7c..a6171cae 100644 --- a/collector/fixtures/e2e-output.txt +++ b/collector/fixtures/e2e-output.txt @@ -2158,6 +2158,9 @@ node_wifi_station_connected_seconds_total{device="wlan0"} 30 # HELP node_wifi_station_inactive_seconds The number of seconds since any wireless activity has occurred on a station. # TYPE node_wifi_station_inactive_seconds gauge node_wifi_station_inactive_seconds{device="wlan0"} 0.4 +# HELP node_wifi_station_info Labeled WiFi interface station information as provided by the operating system. +# TYPE node_wifi_station_info gauge +node_wifi_station_info{bssid="00:11:22:33:44:55",device="wlan0",mode="client",ssid="Example"} 1 # HELP node_wifi_station_receive_bits_per_second The current WiFi receive bitrate of a station, in bits per second. # TYPE node_wifi_station_receive_bits_per_second gauge node_wifi_station_receive_bits_per_second{device="wlan0"} 1.28e+08 diff --git a/collector/fixtures/wifi/wlan0/bss.json b/collector/fixtures/wifi/wlan0/bss.json new file mode 100644 index 00000000..f9dd4778 --- /dev/null +++ b/collector/fixtures/wifi/wlan0/bss.json @@ -0,0 +1,5 @@ +{ + "ssid": "Example", + "bssid": "ABEiM0RV", + "status": 1 +} diff --git a/collector/wifi_linux.go b/collector/wifi_linux.go index eeaeac80..b8596c76 100644 --- a/collector/wifi_linux.go +++ b/collector/wifi_linux.go @@ -28,6 +28,7 @@ import ( type wifiCollector struct { InterfaceFrequencyHertz *prometheus.Desc + StationInfo *prometheus.Desc StationConnectedSecondsTotal *prometheus.Desc StationInactiveSeconds *prometheus.Desc @@ -51,6 +52,7 @@ var _ wifiStater = &wifi.Client{} // wifiStater is an interface used to swap out a *wifi.Client for end to end tests. type wifiStater interface { + BSS(ifi *wifi.Interface) (*wifi.BSS, error) Close() error Interfaces() ([]*wifi.Interface, error) StationInfo(ifi *wifi.Interface) (*wifi.StationInfo, error) @@ -74,6 +76,13 @@ func NewWifiCollector() (Collector, error) { nil, ), + StationInfo: prometheus.NewDesc( + prometheus.BuildFQName(Namespace, subsystem, "station_info"), + "Labeled WiFi interface station information as provided by the operating system.", + []string{"device", "bssid", "ssid", "mode"}, + nil, + ), + StationConnectedSecondsTotal: prometheus.NewDesc( prometheus.BuildFQName(Namespace, subsystem, "station_connected_seconds_total"), "The total number of seconds a station has been connected to an access point.", @@ -163,6 +172,27 @@ func (c *wifiCollector) Update(ch chan<- prometheus.Metric) error { ifi.Name, ) + bss, err := stat.BSS(ifi) + if err != nil { + if os.IsNotExist(err) { + continue + } + + return fmt.Errorf("failed to retrieve BSS for device %s: %v", + ifi.Name, err) + } + + // Synthetic metric which provides WiFi station info, such as SSID, BSSID, etc. + ch <- prometheus.MustNewConstMetric( + c.StationInfo, + prometheus.GaugeValue, + 1, + ifi.Name, + bss.BSSID.String(), + bss.SSID, + bssStatusMode(bss.Status), + ) + info, err := stat.StationInfo(ifi) if err != nil { if os.IsNotExist(err) { @@ -241,6 +271,17 @@ func mHzToHz(mHz int) float64 { return float64(mHz) * 1000 * 1000 } +func bssStatusMode(status wifi.BSSStatus) string { + switch status { + case wifi.BSSStatusAuthenticated, wifi.BSSStatusAssociated: + return "client" + case wifi.BSSStatusIBSSJoined: + return "ad-hoc" + default: + return "unknown" + } +} + // All code below this point is used to assist with end-to-end tests for // the wifi collector, since wifi devices are not available in CI. @@ -273,6 +314,17 @@ func (s *mockWifiStater) unmarshalJSONFile(filename string, v interface{}) error func (s *mockWifiStater) Close() error { return nil } +func (s *mockWifiStater) BSS(ifi *wifi.Interface) (*wifi.BSS, error) { + p := filepath.Join(ifi.Name, "bss.json") + + var bss wifi.BSS + if err := s.unmarshalJSONFile(p, &bss); err != nil { + return nil, err + } + + return &bss, nil +} + func (s *mockWifiStater) Interfaces() ([]*wifi.Interface, error) { var ifis []*wifi.Interface if err := s.unmarshalJSONFile("interfaces.json", &ifis); err != nil {