@@ -44,6 +44,17 @@ type wifiCollector struct {
4444 stationTransmitFailedTotal * prometheus.Desc
4545 stationBeaconLossTotal * prometheus.Desc
4646
47+ surveyNoiseDBM * prometheus.Desc
48+ surveyChannelTimeSeconds * prometheus.Desc
49+ surveyChannelTimeActiveSeconds * prometheus.Desc
50+ surveyChannelTimeBusySeconds * prometheus.Desc
51+ surveyChannelTimeExtBusySeconds * prometheus.Desc
52+ surveyChannelTimeBssRxSeconds * prometheus.Desc
53+ surveyChannelTimeRxSeconds * prometheus.Desc
54+ surveyChannelTimeTxSeconds * prometheus.Desc
55+ surveyChannelTimeScanSeconds * prometheus.Desc
56+ surveyInUse * prometheus.Desc
57+
4758 logger * slog.Logger
4859}
4960
@@ -63,6 +74,7 @@ type wifiStater interface {
6374 Close () error
6475 Interfaces () ([]* wifi.Interface , error )
6576 StationInfo (ifi * wifi.Interface ) ([]* wifi.StationInfo , error )
77+ SurveyInfo (ifi * wifi.Interface ) ([]* wifi.SurveyInfo , error )
6678}
6779
6880// NewWifiCollector returns a new Collector exposing Wifi statistics.
@@ -159,6 +171,77 @@ func NewWifiCollector(logger *slog.Logger) (Collector, error) {
159171 labels ,
160172 nil ,
161173 ),
174+
175+ surveyNoiseDBM : prometheus .NewDesc (
176+ prometheus .BuildFQName (namespace , subsystem , "survey_noise_dbm" ),
177+ "The noise level in decibel-milliwatts (dBm)." ,
178+ []string {"device" , "frequency_mhz" },
179+ nil ,
180+ ),
181+
182+ surveyChannelTimeSeconds : prometheus .NewDesc (
183+ prometheus .BuildFQName (namespace , subsystem , "survey_channel_time_seconds" ),
184+ "The time the radio spent on the channel in seconds." ,
185+ []string {"device" , "frequency_mhz" },
186+ nil ,
187+ ),
188+
189+ surveyChannelTimeActiveSeconds : prometheus .NewDesc (
190+ prometheus .BuildFQName (namespace , subsystem , "survey_channel_time_active_seconds" ),
191+ "The time the radio spent on the channel while it was active in seconds." ,
192+ []string {"device" , "frequency_mhz" },
193+ nil ,
194+ ),
195+
196+ surveyChannelTimeBusySeconds : prometheus .NewDesc (
197+ prometheus .BuildFQName (namespace , subsystem , "survey_channel_time_busy_seconds" ),
198+ "The time the radio spent on the channel while it was busy in seconds." ,
199+ []string {"device" , "frequency_mhz" },
200+ nil ,
201+ ),
202+
203+ surveyChannelTimeExtBusySeconds : prometheus .NewDesc (
204+ prometheus .BuildFQName (namespace , subsystem , "survey_channel_time_ext_busy_seconds" ),
205+ "The time the radio spent on the channel while it was busy with external traffic in seconds." ,
206+ []string {"device" , "frequency_mhz" },
207+ nil ,
208+ ),
209+
210+ surveyChannelTimeBssRxSeconds : prometheus .NewDesc (
211+ prometheus .BuildFQName (namespace , subsystem , "survey_channel_time_bss_rx_seconds" ),
212+ "The time the radio spent on the channel receiving data from a BSS in seconds." ,
213+ []string {"device" , "frequency_mhz" },
214+ nil ,
215+ ),
216+
217+ surveyChannelTimeRxSeconds : prometheus .NewDesc (
218+ prometheus .BuildFQName (namespace , subsystem , "survey_channel_time_rx_seconds" ),
219+ "The time the radio spent on the channel receiving data in seconds." ,
220+ []string {"device" , "frequency_mhz" },
221+ nil ,
222+ ),
223+
224+ surveyChannelTimeTxSeconds : prometheus .NewDesc (
225+ prometheus .BuildFQName (namespace , subsystem , "survey_channel_time_tx_seconds" ),
226+ "The time the radio spent on the channel transmitting data in seconds." ,
227+ []string {"device" , "frequency_mhz" },
228+ nil ,
229+ ),
230+
231+ surveyChannelTimeScanSeconds : prometheus .NewDesc (
232+ prometheus .BuildFQName (namespace , subsystem , "survey_channel_time_scan_seconds" ),
233+ "The time the radio spent on the channel while it was scanning in seconds." ,
234+ []string {"device" , "frequency_mhz" },
235+ nil ,
236+ ),
237+
238+ surveyInUse : prometheus .NewDesc (
239+ prometheus .BuildFQName (namespace , subsystem , "survey_in_use" ),
240+ "Indicates if the channel is currently in use (1 for in use, 0 for not in use)." ,
241+ []string {"device" , "frequency_mhz" },
242+ nil ,
243+ ),
244+
162245 logger : logger ,
163246 }, nil
164247}
@@ -227,6 +310,19 @@ func (c *wifiCollector) Update(ch chan<- prometheus.Metric) error {
227310 return fmt .Errorf ("failed to retrieve station info for device %q: %v" ,
228311 ifi .Name , err )
229312 }
313+
314+ surveys , err := stat .SurveyInfo (ifi )
315+ switch {
316+ case err == nil :
317+ for _ , survey := range surveys {
318+ c .updateSurveyStats (ch , ifi .Name , survey )
319+ }
320+ case errors .Is (err , os .ErrNotExist ):
321+ c .logger .Debug ("survey information not found for wifi device" , "name" , ifi .Name )
322+ default :
323+ return fmt .Errorf ("failed to retrieve survey info for device %q: %v" ,
324+ ifi .Name , err )
325+ }
230326 }
231327
232328 return nil
@@ -327,6 +423,94 @@ func (c *wifiCollector) updateStationStats(ch chan<- prometheus.Metric, device s
327423 )
328424}
329425
426+ func (c * wifiCollector ) updateSurveyStats (ch chan <- prometheus.Metric , device string , info * wifi.SurveyInfo ) {
427+ frequencyMHz := fmt .Sprintf ("%d" , info .Frequency )
428+
429+ ch <- prometheus .MustNewConstMetric (
430+ c .surveyNoiseDBM ,
431+ prometheus .GaugeValue ,
432+ float64 (info .Noise ),
433+ device ,
434+ frequencyMHz ,
435+ )
436+
437+ ch <- prometheus .MustNewConstMetric (
438+ c .surveyChannelTimeSeconds ,
439+ prometheus .CounterValue ,
440+ info .ChannelTime .Seconds (),
441+ device ,
442+ frequencyMHz ,
443+ )
444+
445+ ch <- prometheus .MustNewConstMetric (
446+ c .surveyChannelTimeActiveSeconds ,
447+ prometheus .CounterValue ,
448+ info .ChannelTimeActive .Seconds (),
449+ device ,
450+ frequencyMHz ,
451+ )
452+
453+ ch <- prometheus .MustNewConstMetric (
454+ c .surveyChannelTimeBusySeconds ,
455+ prometheus .CounterValue ,
456+ info .ChannelTimeBusy .Seconds (),
457+ device ,
458+ frequencyMHz ,
459+ )
460+
461+ ch <- prometheus .MustNewConstMetric (
462+ c .surveyChannelTimeExtBusySeconds ,
463+ prometheus .CounterValue ,
464+ info .ChannelTimeExtBusy .Seconds (),
465+ device ,
466+ frequencyMHz ,
467+ )
468+
469+ ch <- prometheus .MustNewConstMetric (
470+ c .surveyChannelTimeBssRxSeconds ,
471+ prometheus .CounterValue ,
472+ info .ChannelTimeBssRx .Seconds (),
473+ device ,
474+ frequencyMHz ,
475+ )
476+
477+ ch <- prometheus .MustNewConstMetric (
478+ c .surveyChannelTimeRxSeconds ,
479+ prometheus .CounterValue ,
480+ info .ChannelTimeRx .Seconds (),
481+ device ,
482+ frequencyMHz ,
483+ )
484+
485+ ch <- prometheus .MustNewConstMetric (
486+ c .surveyChannelTimeTxSeconds ,
487+ prometheus .CounterValue ,
488+ info .ChannelTimeTx .Seconds (),
489+ device ,
490+ frequencyMHz ,
491+ )
492+
493+ ch <- prometheus .MustNewConstMetric (
494+ c .surveyChannelTimeScanSeconds ,
495+ prometheus .CounterValue ,
496+ info .ChannelTimeScan .Seconds (),
497+ device ,
498+ frequencyMHz ,
499+ )
500+
501+ var inUseValue float64
502+ if info .InUse {
503+ inUseValue = 1
504+ }
505+ ch <- prometheus .MustNewConstMetric (
506+ c .surveyInUse ,
507+ prometheus .GaugeValue ,
508+ inUseValue ,
509+ device ,
510+ frequencyMHz ,
511+ )
512+ }
513+
330514func mHzToHz (mHz int ) float64 {
331515 return float64 (mHz ) * 1000 * 1000
332516}
@@ -404,3 +588,14 @@ func (s *mockWifiStater) StationInfo(ifi *wifi.Interface) ([]*wifi.StationInfo,
404588
405589 return stations , nil
406590}
591+
592+ func (s * mockWifiStater ) SurveyInfo (ifi * wifi.Interface ) ([]* wifi.SurveyInfo , error ) {
593+ p := filepath .Join (ifi .Name , "surveyinfo.json" )
594+
595+ var surveyInfo []* wifi.SurveyInfo
596+ if err := s .unmarshalJSONFile (p , & surveyInfo ); err != nil {
597+ return nil , err
598+ }
599+
600+ return surveyInfo , nil
601+ }
0 commit comments