feat(promunifi): add mac label to per-VAP and per-radio metrics

unifi_device_vap_* and unifi_device_radio_* previously exposed only
(site_name, name, source) as per-device identifiers, none of which is a
stable primary key (name is user-editable, source is the controller
hostname). The device MAC is already available on the parent UAP/UDM/UDB/UBB
struct, so this threads d.Mac through exportVAPtable / exportRADtable and
adds it as a label on every series those functions emit.

This lets downstream consumers join VAP/radio series directly against
unifi_device_info (which already carries mac) without going through the
(site_name, name, source) intersection.

Applied at all four call sites: UAP, UDM, UDB, UBB.
This commit is contained in:
Miguel Deus
2026-06-09 08:26:06 -05:00
committed by Cody Lee
parent 107b47d529
commit 4ec6fa2010
4 changed files with 14 additions and 14 deletions
+8 -8
View File
@@ -112,8 +112,8 @@ func descRogueAP(ns string) *rogueap {
func descUAP(ns string) *uap { // nolint: funlen
labelA := []string{"stat", "site_name", "name", "source", "tag"} // stat + labels[1:]
labelV := []string{"vap_name", "bssid", "radio", "radio_name", "essid", "usage", "site_name", "name", "source", "tag"}
labelR := []string{"radio_name", "radio", "site_name", "name", "source", "tag"}
labelV := []string{"vap_name", "bssid", "radio", "radio_name", "essid", "usage", "mac", "site_name", "name", "source", "tag"}
labelR := []string{"radio_name", "radio", "mac", "site_name", "name", "source", "tag"}
nd := prometheus.NewDesc
return &uap{
@@ -224,12 +224,12 @@ func (u *promUnifi) exportUAP(r report, d *unifi.UAP) {
infoLabels := append(baseInfoLabels, tag)
u.exportUAPstats(r, labels, d.Stat.Ap, d.BytesD, d.TxBytesD, d.RxBytesD, d.BytesR)
u.exportVAPtable(r, labels, d.VapTable)
u.exportVAPtable(r, labels, d.VapTable, d.Mac)
u.exportPRTtable(r, labels, d.PortTable)
u.exportBYTstats(r, labels, d.TxBytes, d.RxBytes)
u.exportSYSstats(r, labels, d.SysStats, d.SystemStats)
u.exportSTAcount(r, labels, d.UserNumSta, d.GuestNumSta)
u.exportRADtable(r, labels, d.RadioTable, d.RadioTableStats)
u.exportRADtable(r, labels, d.RadioTable, d.RadioTableStats, d.Mac)
// UAP uplink metrics. The uplink "type" (e.g. "wire" / "wireless")
// is encoded as the first label, matching the convention used by
// USG/USW/UBB/UDB so dashboards can group by port.
@@ -292,14 +292,14 @@ func (u *promUnifi) exportUAPstats(r report, labels []string, ap *unifi.Ap, byte
}
// UAP VAP Table.
func (u *promUnifi) exportVAPtable(r report, labels []string, vt unifi.VapTable) {
func (u *promUnifi) exportVAPtable(r report, labels []string, vt unifi.VapTable, mac string) {
// vap table stats
for _, v := range vt {
if !v.Up.Val {
continue
}
labelV := []string{v.Name, v.Bssid, v.Radio, v.RadioName, v.Essid, v.Usage, labels[1], labels[2], labels[3], labels[4]}
labelV := []string{v.Name, v.Bssid, v.Radio, v.RadioName, v.Essid, v.Usage, mac, labels[1], labels[2], labels[3], labels[4]}
r.send([]*metric{
{u.UAP.VAPCcq, gauge, float64(v.Ccq) / 1000.0, labelV},
{u.UAP.VAPMacFilterRejections, counter, v.MacFilterRejections, labelV},
@@ -343,10 +343,10 @@ func (u *promUnifi) exportVAPtable(r report, labels []string, vt unifi.VapTable)
}
// UAP Radio Table.
func (u *promUnifi) exportRADtable(r report, labels []string, rt unifi.RadioTable, rts unifi.RadioTableStats) {
func (u *promUnifi) exportRADtable(r report, labels []string, rt unifi.RadioTable, rts unifi.RadioTableStats, mac string) {
// radio table
for _, p := range rt {
labelR := []string{p.Name, p.Radio, labels[1], labels[2], labels[3], labels[4]}
labelR := []string{p.Name, p.Radio, mac, labels[1], labels[2], labels[3], labels[4]}
labelRUser := append(labelR, "user")
labelRGuest := append(labelR, "guest")
+2 -2
View File
@@ -25,10 +25,10 @@ func (u *promUnifi) exportUBB(r report, d *unifi.UBB) {
u.exportUBBstats(r, labels, d.Stat)
// Export VAP table (Virtual Access Point table - wireless interface stats)
u.exportVAPtable(r, labels, d.VapTable)
u.exportVAPtable(r, labels, d.VapTable, d.Mac)
// Export Radio tables (includes 5GHz wifi0 and 60GHz terra2/ad radios)
u.exportRADtable(r, labels, d.RadioTable, d.RadioTableStats)
u.exportRADtable(r, labels, d.RadioTable, d.RadioTableStats, d.Mac)
// Shared device stats
u.exportBYTstats(r, labels, d.TxBytes, d.RxBytes)
+2 -2
View File
@@ -24,8 +24,8 @@ func (u *promUnifi) exportUDB(r report, d *unifi.UDB) {
u.exportPRTtable(r, labels, d.PortTable)
// Export wireless stats (reuse UAP functions)
u.exportVAPtable(r, labels, d.VapTable)
u.exportRADtable(r, labels, d.RadioTable, d.RadioTableStats)
u.exportVAPtable(r, labels, d.VapTable, d.Mac)
u.exportRADtable(r, labels, d.RadioTable, d.RadioTableStats, d.Mac)
// Common device stats
u.exportBYTstats(r, labels, d.TxBytes, d.RxBytes)
+2 -2
View File
@@ -130,8 +130,8 @@ func (u *promUnifi) exportUDM(r report, d *unifi.UDM) {
tag := tagLabels[0]
labels := append(baseLabels, tag)
u.exportUAPstats(r, labels, d.Stat.Ap, d.BytesD, d.TxBytesD, d.RxBytesD, d.BytesR)
u.exportVAPtable(r, labels, *d.VapTable)
u.exportRADtable(r, labels, *d.RadioTable, *d.RadioTableStats)
u.exportVAPtable(r, labels, *d.VapTable, d.Mac)
u.exportRADtable(r, labels, *d.RadioTable, *d.RadioTableStats, d.Mac)
})
}
}