@@ -44,6 +44,17 @@ type wifiCollector struct {
44
44
stationTransmitFailedTotal * prometheus.Desc
45
45
stationBeaconLossTotal * prometheus.Desc
46
46
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
+
47
58
logger * slog.Logger
48
59
}
49
60
@@ -63,6 +74,7 @@ type wifiStater interface {
63
74
Close () error
64
75
Interfaces () ([]* wifi.Interface , error )
65
76
StationInfo (ifi * wifi.Interface ) ([]* wifi.StationInfo , error )
77
+ SurveyInfo (ifi * wifi.Interface ) ([]* wifi.SurveyInfo , error )
66
78
}
67
79
68
80
// NewWifiCollector returns a new Collector exposing Wifi statistics.
@@ -159,6 +171,77 @@ func NewWifiCollector(logger *slog.Logger) (Collector, error) {
159
171
labels ,
160
172
nil ,
161
173
),
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
+
162
245
logger : logger ,
163
246
}, nil
164
247
}
@@ -227,6 +310,19 @@ func (c *wifiCollector) Update(ch chan<- prometheus.Metric) error {
227
310
return fmt .Errorf ("failed to retrieve station info for device %q: %v" ,
228
311
ifi .Name , err )
229
312
}
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
+ }
230
326
}
231
327
232
328
return nil
@@ -327,6 +423,94 @@ func (c *wifiCollector) updateStationStats(ch chan<- prometheus.Metric, device s
327
423
)
328
424
}
329
425
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
+
330
514
func mHzToHz (mHz int ) float64 {
331
515
return float64 (mHz ) * 1000 * 1000
332
516
}
@@ -404,3 +588,14 @@ func (s *mockWifiStater) StationInfo(ifi *wifi.Interface) ([]*wifi.StationInfo,
404
588
405
589
return stations , nil
406
590
}
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