From f91ececd637f3f3ed5b2eae938c2259ab36ffc6e Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Thu, 28 Nov 2019 20:43:06 -0800 Subject: [PATCH] add an interface for testing --- promunifi/clients.go | 12 ++++++------ promunifi/collector.go | 29 +++++++++++++++++++++++++---- promunifi/site.go | 12 ++++++------ promunifi/uap.go | 34 +++++++++++++++++----------------- promunifi/udm.go | 24 ++++++++++++------------ promunifi/usg.go | 18 +++++++++--------- promunifi/usw.go | 22 +++++++++++----------- 7 files changed, 86 insertions(+), 65 deletions(-) diff --git a/promunifi/clients.go b/promunifi/clients.go index ce8843ff..4cc1fbb1 100644 --- a/promunifi/clients.go +++ b/promunifi/clients.go @@ -87,20 +87,20 @@ func descClient(ns string) *uclient { } } -func (u *unifiCollector) exportClients(r *Report) { - if r.Metrics == nil || len(r.Metrics.Clients) < 1 { +func (u *unifiCollector) exportClients(r report) { + if r.metrics() == nil || len(r.metrics().Clients) < 1 { return } - r.wg.Add(one) + r.add() go func() { - defer r.wg.Done() - for _, c := range r.Metrics.Clients { + defer r.done() + for _, c := range r.metrics().Clients { u.exportClient(r, c) } }() } -func (u *unifiCollector) exportClient(r *Report, c *unifi.Client) { +func (u *unifiCollector) exportClient(r report, c *unifi.Client) { labels := []string{c.Name, c.Mac, c.SiteName, c.GwMac, c.GwName, c.SwMac, c.SwName, c.Vlan.Txt, c.IP, c.Oui, c.Network} labelWired := append([]string{c.SwPort.Txt}, labels...) labelWireless := append([]string{c.ApMac, c.ApName, c.RadioName, c.Radio, c.RadioProto, c.Channel.Txt, c.Essid, c.Bssid, c.RadioDescription}, labels...) diff --git a/promunifi/collector.go b/promunifi/collector.go index 7b1842b5..6ed313f2 100644 --- a/promunifi/collector.go +++ b/promunifi/collector.go @@ -4,6 +4,7 @@ package promunifi import ( "fmt" "reflect" + "strings" "sync" "time" @@ -12,9 +13,6 @@ import ( "golift.io/unifi" ) -// satisfy gomnd -const one = 1 - // channel buffer, fits at least one batch. const buffer = 50 @@ -65,13 +63,21 @@ type Report struct { wg sync.WaitGroup } +// internal interface used to "process metrics" - can be mocked and overridden for tests. +type report interface { + send([]*metricExports) + add() + done() + metrics() *metrics.Metrics +} + // NewUnifiCollector returns a prometheus collector that will export any available // UniFi metrics. You must provide a collection function in the opts. func NewUnifiCollector(opts UnifiCollectorCnfg) prometheus.Collector { if opts.CollectFn == nil { panic("nil collector function") } - if opts.Namespace += "_"; opts.Namespace == "_" { + if opts.Namespace = strings.Trim(opts.Namespace, "_") + "_"; opts.Namespace == "_" { opts.Namespace = "" } return &unifiCollector{ @@ -175,6 +181,21 @@ func (u *unifiCollector) exportMetrics(r *Report, ch chan<- prometheus.Metric) { u.Config.LoggingFn(r) } +func (r *Report) metrics() *metrics.Metrics { + return r.Metrics +} + +// satisfy gomnd +const one = 1 + +func (r *Report) add() { + r.wg.Add(one) +} + +func (r *Report) done() { + r.wg.Done() +} + func (r *Report) send(m []*metricExports) { r.wg.Add(one) r.ch <- m diff --git a/promunifi/site.go b/promunifi/site.go index e810c16e..5f9f81cc 100644 --- a/promunifi/site.go +++ b/promunifi/site.go @@ -64,20 +64,20 @@ func descSite(ns string) *site { } } -func (u *unifiCollector) exportSites(r *Report) { - if r.Metrics == nil || len(r.Metrics.Sites) < 1 { +func (u *unifiCollector) exportSites(r report) { + if r.metrics() == nil || len(r.metrics().Sites) < 1 { return } - r.wg.Add(one) + r.add() go func() { - defer r.wg.Done() - for _, s := range r.Metrics.Sites { + defer r.done() + for _, s := range r.metrics().Sites { u.exportSite(r, s) } }() } -func (u *unifiCollector) exportSite(r *Report, s *unifi.Site) { +func (u *unifiCollector) exportSite(r report, s *unifi.Site) { labels := []string{s.Name, s.Desc, s.SiteName} for _, h := range s.Health { l := append([]string{h.Subsystem, h.Status}, labels...) diff --git a/promunifi/uap.go b/promunifi/uap.go index 5219675a..262d1d14 100644 --- a/promunifi/uap.go +++ b/promunifi/uap.go @@ -165,20 +165,20 @@ func descUAP(ns string) *uap { } } -func (u *unifiCollector) exportUAPs(r *Report) { - if r.Metrics == nil || r.Metrics.Devices == nil || len(r.Metrics.Devices.UAPs) < 1 { +func (u *unifiCollector) exportUAPs(r report) { + if r.metrics() == nil || r.metrics().Devices == nil || len(r.metrics().Devices.UAPs) < 1 { return } - r.wg.Add(one) + r.add() go func() { - defer r.wg.Done() - for _, d := range r.Metrics.Devices.UAPs { + defer r.done() + for _, d := range r.metrics().Devices.UAPs { u.exportUAP(r, d) } }() } -func (u *unifiCollector) exportUAP(r *Report, d *unifi.UAP) { +func (u *unifiCollector) exportUAP(r report, d *unifi.UAP) { labels := []string{d.IP, d.Type, d.Version, d.SiteName, d.Mac, d.Model, d.Name, d.Serial} // AP data. r.send([]*metricExports{ @@ -202,15 +202,15 @@ func (u *unifiCollector) exportUAP(r *Report, d *unifi.UAP) { {u.Device.CPU, prometheus.GaugeValue, d.SystemStats.CPU, labels}, {u.Device.Mem, prometheus.GaugeValue, d.SystemStats.Mem, labels}, }) - u.exportUAPstats(r, labels[2:], d.Stat.Ap) - u.exportVAPtable(r, labels[2:], d.VapTable) - u.exportRadtable(r, labels[2:], d.RadioTable, d.RadioTableStats) + u.exportUAPstats(r, labels, d.Stat.Ap) + u.exportVAPtable(r, labels, d.VapTable) + u.exportRadtable(r, labels, d.RadioTable, d.RadioTableStats) } -func (u *unifiCollector) exportUAPstats(r *Report, labels []string, ap *unifi.Ap) { - labelA := append([]string{"all"}, labels...) - labelU := append([]string{"user"}, labels...) - labelG := append([]string{"guest"}, labels...) +func (u *unifiCollector) exportUAPstats(r report, labels []string, ap *unifi.Ap) { + labelA := append([]string{"all"}, labels[2:]...) + labelU := append([]string{"user"}, labels[2:]...) + labelG := append([]string{"guest"}, labels[2:]...) r.send([]*metricExports{ // all {u.UAP.ApWifiTxDropped, prometheus.CounterValue, ap.WifiTxDropped, labelA}, @@ -260,13 +260,13 @@ func (u *unifiCollector) exportUAPstats(r *Report, labels []string, ap *unifi.Ap }) } -func (u *unifiCollector) exportVAPtable(r *Report, labels []string, vt unifi.VapTable) { +func (u *unifiCollector) exportVAPtable(r report, labels []string, vt unifi.VapTable) { // vap table stats for _, v := range vt { if !v.Up.Val { continue } - labelV := append([]string{v.Name, v.Bssid, v.RadioName, v.Essid, v.Usage}, labels...) + labelV := append([]string{v.Name, v.Bssid, v.RadioName, v.Essid, v.Usage}, labels[2:]...) r.send([]*metricExports{ {u.UAP.VAPCcq, prometheus.GaugeValue, v.Ccq, labelV}, {u.UAP.VAPMacFilterRejections, prometheus.CounterValue, v.MacFilterRejections, labelV}, @@ -309,10 +309,10 @@ func (u *unifiCollector) exportVAPtable(r *Report, labels []string, vt unifi.Vap } } -func (u *unifiCollector) exportRadtable(r *Report, labels []string, rt unifi.RadioTable, rts unifi.RadioTableStats) { +func (u *unifiCollector) exportRadtable(r report, labels []string, rt unifi.RadioTable, rts unifi.RadioTableStats) { // radio table for _, p := range rt { - labelR := append([]string{p.Name, p.Radio}, labels...) + labelR := append([]string{p.Name, p.Radio}, labels[2:]...) r.send([]*metricExports{ {u.UAP.RadioCurrentAntennaGain, prometheus.GaugeValue, p.CurrentAntennaGain, labelR}, {u.UAP.RadioHt, prometheus.GaugeValue, p.Ht, labelR}, diff --git a/promunifi/udm.go b/promunifi/udm.go index 1586addd..c3f62b3b 100644 --- a/promunifi/udm.go +++ b/promunifi/udm.go @@ -67,21 +67,21 @@ func descDevice(ns string) *unifiDevice { } } -func (u *unifiCollector) exportUDMs(r *Report) { - if r.Metrics == nil || r.Metrics.Devices == nil || len(r.Metrics.Devices.UDMs) < 1 { +func (u *unifiCollector) exportUDMs(r report) { + if r.metrics() == nil || r.metrics().Devices == nil || len(r.metrics().Devices.UDMs) < 1 { return } - r.wg.Add(one) + r.add() go func() { - defer r.wg.Done() - for _, d := range r.Metrics.Devices.UDMs { + defer r.done() + for _, d := range r.metrics().Devices.UDMs { u.exportUDM(r, d) } }() } // UDM is a collection of stats from USG, USW and UAP. It has no unique stats. -func (u *unifiCollector) exportUDM(r *Report, d *unifi.UDM) { +func (u *unifiCollector) exportUDM(r report, d *unifi.UDM) { labels := []string{d.IP, d.Type, d.Version, d.SiteName, d.Mac, d.Model, d.Name, d.Serial} // Gateway System Data. r.send([]*metricExports{ @@ -104,14 +104,14 @@ func (u *unifiCollector) exportUDM(r *Report, d *unifi.UDM) { {u.Device.CPU, prometheus.GaugeValue, d.SystemStats.CPU, labels}, {u.Device.Mem, prometheus.GaugeValue, d.SystemStats.Mem, labels}, }) - u.exportUSWstats(r, d.Stat.Sw, labels) - u.exportUSGstats(r, d.Stat.Gw, d.SpeedtestStatus, labels) + u.exportUSWstats(r, labels, d.Stat.Sw) + u.exportUSGstats(r, labels, d.Stat.Gw, d.SpeedtestStatus) u.exportWANPorts(r, labels, d.Wan1, d.Wan2) - u.exportPortTable(r, d.PortTable, labels[4:]) + u.exportPortTable(r, labels, d.PortTable) if d.Stat.Ap != nil && d.VapTable != nil { // UDM Pro does not have these. UDM non-Pro does. - u.exportUAPstats(r, labels[2:], d.Stat.Ap) - u.exportVAPtable(r, labels[2:], *d.VapTable) - u.exportRadtable(r, labels[2:], *d.RadioTable, *d.RadioTableStats) + u.exportUAPstats(r, labels, d.Stat.Ap) + u.exportVAPtable(r, labels, *d.VapTable) + u.exportRadtable(r, labels, *d.RadioTable, *d.RadioTableStats) } } diff --git a/promunifi/usg.go b/promunifi/usg.go index b5d7211a..99e7f410 100644 --- a/promunifi/usg.go +++ b/promunifi/usg.go @@ -65,20 +65,20 @@ func descUSG(ns string) *usg { } } -func (u *unifiCollector) exportUSGs(r *Report) { - if r.Metrics == nil || r.Metrics.Devices == nil || len(r.Metrics.Devices.USGs) < 1 { +func (u *unifiCollector) exportUSGs(r report) { + if r.metrics() == nil || r.metrics().Devices == nil || len(r.metrics().Devices.USGs) < 1 { return } - r.wg.Add(one) + r.add() go func() { - defer r.wg.Done() - for _, d := range r.Metrics.Devices.USGs { + defer r.done() + for _, d := range r.metrics().Devices.USGs { u.exportUSG(r, d) } }() } -func (u *unifiCollector) exportUSG(r *Report, d *unifi.USG) { +func (u *unifiCollector) exportUSG(r report, d *unifi.USG) { labels := []string{d.IP, d.Type, d.Version, d.SiteName, d.Mac, d.Model, d.Name, d.Serial} // Gateway System Data. r.send([]*metricExports{ @@ -102,10 +102,10 @@ func (u *unifiCollector) exportUSG(r *Report, d *unifi.USG) { {u.Device.Mem, prometheus.GaugeValue, d.SystemStats.Mem, labels}, }) u.exportWANPorts(r, labels, d.Wan1, d.Wan2) - u.exportUSGstats(r, d.Stat.Gw, d.SpeedtestStatus, labels) + u.exportUSGstats(r, labels, d.Stat.Gw, d.SpeedtestStatus) } -func (u *unifiCollector) exportUSGstats(r *Report, gw *unifi.Gw, st unifi.SpeedtestStatus, labels []string) { +func (u *unifiCollector) exportUSGstats(r report, labels []string, gw *unifi.Gw, st unifi.SpeedtestStatus) { labelWan := append([]string{"all"}, labels...) r.send([]*metricExports{ // Combined Port Stats @@ -128,7 +128,7 @@ func (u *unifiCollector) exportUSGstats(r *Report, gw *unifi.Gw, st unifi.Speedt }) } -func (u *unifiCollector) exportWANPorts(r *Report, labels []string, wans ...unifi.Wan) { +func (u *unifiCollector) exportWANPorts(r report, labels []string, wans ...unifi.Wan) { for _, wan := range wans { if !wan.Up.Val { continue // only record UP interfaces. diff --git a/promunifi/usw.go b/promunifi/usw.go index f1e5fe13..a79f4092 100644 --- a/promunifi/usw.go +++ b/promunifi/usw.go @@ -91,20 +91,20 @@ func descUSW(ns string) *usw { } } -func (u *unifiCollector) exportUSWs(r *Report) { - if r.Metrics == nil || r.Metrics.Devices == nil || len(r.Metrics.Devices.USWs) < 1 { +func (u *unifiCollector) exportUSWs(r report) { + if r.metrics() == nil || r.metrics().Devices == nil || len(r.metrics().Devices.USWs) < 1 { return } - r.wg.Add(one) + r.add() go func() { - defer r.wg.Done() - for _, d := range r.Metrics.Devices.USWs { + defer r.done() + for _, d := range r.metrics().Devices.USWs { u.exportUSW(r, d) } }() } -func (u *unifiCollector) exportUSW(r *Report, d *unifi.USW) { +func (u *unifiCollector) exportUSW(r report, d *unifi.USW) { labels := []string{d.IP, d.Type, d.Version, d.SiteName, d.Mac, d.Model, d.Name, d.Serial} if d.HasTemperature.Val { r.send([]*metricExports{{u.Device.Temperature, prometheus.GaugeValue, d.GeneralTemperature, labels}}) @@ -132,11 +132,11 @@ func (u *unifiCollector) exportUSW(r *Report, d *unifi.USW) { {u.Device.CPU, prometheus.GaugeValue, d.SystemStats.CPU, labels}, {u.Device.Mem, prometheus.GaugeValue, d.SystemStats.Mem, labels}, }) - u.exportPortTable(r, d.PortTable, labels[4:]) - u.exportUSWstats(r, d.Stat.Sw, labels) + u.exportPortTable(r, labels, d.PortTable) + u.exportUSWstats(r, labels, d.Stat.Sw) } -func (u *unifiCollector) exportUSWstats(r *Report, sw *unifi.Sw, labels []string) { +func (u *unifiCollector) exportUSWstats(r report, labels []string, sw *unifi.Sw) { r.send([]*metricExports{ {u.USW.SwRxPackets, prometheus.CounterValue, sw.RxPackets, labels}, {u.USW.SwRxBytes, prometheus.CounterValue, sw.RxBytes, labels}, @@ -157,14 +157,14 @@ func (u *unifiCollector) exportUSWstats(r *Report, sw *unifi.Sw, labels []string }) } -func (u *unifiCollector) exportPortTable(r *Report, pt []unifi.Port, labels []string) { +func (u *unifiCollector) exportPortTable(r report, labels []string, pt []unifi.Port) { // Per-port data on a switch for _, p := range pt { if !p.Up.Val { continue } // Copy labels, and add four new ones. - l := append([]string{p.PortIdx.Txt, p.Name, p.Mac, p.IP}, labels...) + l := append([]string{p.PortIdx.Txt, p.Name, p.Mac, p.IP}, labels[4:]...) if p.PoeEnable.Val && p.PortPoe.Val { r.send([]*metricExports{ {u.USW.PoeCurrent, prometheus.GaugeValue, p.PoeCurrent, l},