diff --git a/pkg/influxunifi/influxdb.go b/pkg/influxunifi/influxdb.go index 9bbe9c84..c88f7fbd 100644 --- a/pkg/influxunifi/influxdb.go +++ b/pkg/influxunifi/influxdb.go @@ -69,10 +69,13 @@ func (u *InfluxUnifi) PollController() { log.Printf("[INFO] Everything checks out! Poller started, InfluxDB interval: %v", interval) for u.LastCheck = range ticker.C { - metrics, err := u.Collector.Metrics() + metrics, ok, err := u.Collector.Metrics() if err != nil { u.Collector.LogErrorf("%v", err) - continue + + if !ok { + continue + } } report, err := u.ReportMetrics(metrics) diff --git a/pkg/inputunifi/input.go b/pkg/inputunifi/input.go index 2ddc1f4f..982da1b4 100644 --- a/pkg/inputunifi/input.go +++ b/pkg/inputunifi/input.go @@ -44,6 +44,7 @@ func init() { u := &InputUnifi{} poller.NewInput(&poller.InputPlugin{ + Name: "unifi", Input: u, // this library implements poller.Input interface for Metrics(). Config: u, // Defines our config data interface. }) diff --git a/pkg/inputunifi/interface.go b/pkg/inputunifi/interface.go index f9b437de..99ee7f51 100644 --- a/pkg/inputunifi/interface.go +++ b/pkg/inputunifi/interface.go @@ -47,15 +47,25 @@ func (u *InputUnifi) Initialize(l poller.Logger) error { } // Metrics grabs all the measurements from a UniFi controller and returns them. -func (u *InputUnifi) Metrics() (*poller.Metrics, error) { +func (u *InputUnifi) Metrics() (*poller.Metrics, bool, error) { + return u.MetricsFrom(poller.Filter{}) +} + +// MetricsFrom grabs all the measurements from a UniFi controller and returns them. +func (u *InputUnifi) MetricsFrom(filter poller.Filter) (*poller.Metrics, bool, error) { if u.Config.Disable { - return nil, nil + return nil, false, nil } errs := []string{} metrics := &poller.Metrics{} + ok := false for _, c := range u.Config.Controllers { + if filter.Term != "" && c.Name != filter.Term { + continue + } + m, err := u.collectController(c) if err != nil { errs = append(errs, err.Error()) @@ -65,6 +75,8 @@ func (u *InputUnifi) Metrics() (*poller.Metrics, error) { continue } + ok = true + metrics.Sites = append(metrics.Sites, m.Sites...) metrics.Clients = append(metrics.Clients, m.Clients...) metrics.IDSList = append(metrics.IDSList, m.IDSList...) @@ -84,10 +96,10 @@ func (u *InputUnifi) Metrics() (*poller.Metrics, error) { } if len(errs) > 0 { - return metrics, fmt.Errorf(strings.Join(errs, ", ")) + return metrics, ok, fmt.Errorf(strings.Join(errs, ", ")) } - return metrics, nil + return metrics, ok, nil } // RawMetrics returns API output from the first configured unifi controller. diff --git a/pkg/poller/inputs.go b/pkg/poller/inputs.go index f2d64efb..5d361166 100644 --- a/pkg/poller/inputs.go +++ b/pkg/poller/inputs.go @@ -15,13 +15,15 @@ var ( // Input plugins must implement this interface. type Input interface { - Initialize(Logger) error // Called once on startup to initialize the plugin. - Metrics() (*Metrics, error) // Called every time new metrics are requested. + Initialize(Logger) error // Called once on startup to initialize the plugin. + Metrics() (*Metrics, bool, error) // Called every time new metrics are requested. + MetricsFrom(Filter) (*Metrics, bool, error) // Called every time new metrics are requested. RawMetrics(Filter) ([]byte, error) } // InputPlugin describes an input plugin's consumable interface. type InputPlugin struct { + Name string Config interface{} // Each config is passed into an unmarshaller later. Input } @@ -61,12 +63,13 @@ func (u *UnifiPoller) InitializeInputs() error { } // Metrics aggregates all the measurements from all configured inputs and returns them. -func (u *UnifiPoller) Metrics() (*Metrics, error) { +func (u *UnifiPoller) Metrics() (*Metrics, bool, error) { errs := []string{} metrics := &Metrics{} + ok := false for _, input := range inputs { - m, err := input.Metrics() + m, _, err := input.Metrics() if err != nil { errs = append(errs, err.Error()) } @@ -75,6 +78,8 @@ func (u *UnifiPoller) Metrics() (*Metrics, error) { continue } + ok = true + metrics.Sites = append(metrics.Sites, m.Sites...) metrics.Clients = append(metrics.Clients, m.Clients...) metrics.IDSList = append(metrics.IDSList, m.IDSList...) @@ -99,5 +104,54 @@ func (u *UnifiPoller) Metrics() (*Metrics, error) { err = fmt.Errorf(strings.Join(errs, ", ")) } - return metrics, err + return metrics, ok, err +} + +// MetricsFrom aggregates all the measurements from all configured inputs and returns them. +func (u *UnifiPoller) MetricsFrom(filter Filter) (*Metrics, bool, error) { + errs := []string{} + metrics := &Metrics{} + ok := false + + for _, input := range inputs { + if input.Name != filter.Type { + continue + } + + m, _, err := input.MetricsFrom(filter) + if err != nil { + errs = append(errs, err.Error()) + } + + if m == nil { + continue + } + + ok = true + + metrics.Sites = append(metrics.Sites, m.Sites...) + metrics.Clients = append(metrics.Clients, m.Clients...) + metrics.IDSList = append(metrics.IDSList, m.IDSList...) + + if m.Devices == nil { + continue + } + + if metrics.Devices == nil { + metrics.Devices = &unifi.Devices{} + } + + metrics.UAPs = append(metrics.UAPs, m.UAPs...) + metrics.USGs = append(metrics.USGs, m.USGs...) + metrics.USWs = append(metrics.USWs, m.USWs...) + metrics.UDMs = append(metrics.UDMs, m.UDMs...) + } + + var err error + + if len(errs) > 0 { + err = fmt.Errorf(strings.Join(errs, ", ")) + } + + return metrics, ok, err } diff --git a/pkg/poller/outputs.go b/pkg/poller/outputs.go index 3bbcb72d..0672d92b 100644 --- a/pkg/poller/outputs.go +++ b/pkg/poller/outputs.go @@ -13,7 +13,8 @@ var ( // Collect is passed into output packages so they may collect metrics to output. // Output packages must implement this interface. type Collect interface { - Metrics() (*Metrics, error) + Metrics() (*Metrics, bool, error) + MetricsFrom(Filter) (*Metrics, bool, error) Logger } diff --git a/pkg/promunifi/collector.go b/pkg/promunifi/collector.go index a4aad9f3..694bfd4c 100644 --- a/pkg/promunifi/collector.go +++ b/pkg/promunifi/collector.go @@ -140,12 +140,17 @@ func (u *promUnifi) Describe(ch chan<- *prometheus.Desc) { func (u *promUnifi) Collect(ch chan<- prometheus.Metric) { var err error + ok := false + r := &Report{Config: u.Config, ch: make(chan []*metric, buffer), Start: time.Now()} defer r.close() - if r.Metrics, err = u.Collector.Metrics(); err != nil { + if r.Metrics, ok, err = u.Collector.Metrics(); err != nil { r.error(ch, prometheus.NewInvalidDesc(fmt.Errorf("metric fetch failed")), err) - return + + if !ok { + return + } } r.Fetch = time.Since(r.Start)