diff --git a/examples/up.conf.example b/examples/up.conf.example index c968b54a..0d7e4271 100644 --- a/examples/up.conf.example +++ b/examples/up.conf.example @@ -69,8 +69,8 @@ # How often to poll UniFi and report to Datadog. interval = "2m" - # To disable this output plugin - disable = true + # To enable this output plugin + enable = false # Datadog Custom Options @@ -84,7 +84,7 @@ # tags = [ "customer:abc_corp" ] # For more advanced options for very large amount of data collected see the upstream - # github.com/unpoller/datadogunifi repository README. + # github.com/unpoller/unpoller/pkg/datadogunifi repository README. # Unpoller has an optional web server. To turn it on, set enable to true. If you diff --git a/examples/up.json.example b/examples/up.json.example index e547f8c9..9d8857af 100644 --- a/examples/up.json.example +++ b/examples/up.json.example @@ -35,6 +35,15 @@ } }, + "datadog": { + "enable": false, + "address": "localhost:8125", + "namespace": "", + "tags": [ + "customer:abcde" + ] + } + "unifi": { "dynamic": false, "defaults": { diff --git a/examples/up.yaml.example b/examples/up.yaml.example index 9c44996a..4c85c1cc 100644 --- a/examples/up.yaml.example +++ b/examples/up.yaml.example @@ -36,6 +36,13 @@ webserver: accounts: captain: "$2a$04$mxw6i0LKH6u46oaLK2cq5eCTAAFkfNiRpzNbz.EyvJZZWNa2FzIlS" +datadog: + enable: false + address: localhost:8125 + namespace: "" + tags: + - customer:abcdef + unifi: dynamic: false defaults: diff --git a/pkg/datadogunifi/datadog.go b/pkg/datadogunifi/datadog.go index baa8066c..42ccde24 100644 --- a/pkg/datadogunifi/datadog.go +++ b/pkg/datadogunifi/datadog.go @@ -112,13 +112,15 @@ type DatadogUnifi struct { *Datadog } +var _ poller.OutputPlugin = &DatadogUnifi{} + func init() { // nolint: gochecknoinits u := &DatadogUnifi{Datadog: &Datadog{}, LastCheck: time.Now()} poller.NewOutput(&poller.Output{ - Name: "datadog", - Config: u.Datadog, - Method: u.Run, + Name: "datadog", + Config: u.Datadog, + OutputPlugin: u, }) } @@ -188,14 +190,26 @@ func (u *DatadogUnifi) setConfigDefaults() { } +func (u *DatadogUnifi) Enabled() bool { + if u == nil { + return false + } + if u.Enable == nil || u.Config == nil { + return false + } + if u.Collector == nil { + return false + } + return *u.Enable +} + // Run runs a ticker to poll the unifi server and update Datadog. func (u *DatadogUnifi) Run(c poller.Collect) error { - disabled := u == nil || u.Enable == nil || !(*u.Enable) || u.Config == nil - if disabled { - u.LogDebugf("Datadog config is disabled, output is disabled.") + u.Collector = c + if !u.Enabled() { + u.Logf("DataDog config missing (or disabled), DataDog output disabled!") return nil } - u.Collector = c u.Logf("Datadog is configured.") u.setConfigDefaults() diff --git a/pkg/influxunifi/influxdb.go b/pkg/influxunifi/influxdb.go index a0e199c2..1f3541da 100644 --- a/pkg/influxunifi/influxdb.go +++ b/pkg/influxunifi/influxdb.go @@ -77,6 +77,8 @@ type InfluxUnifi struct { *InfluxDB } +var _ poller.OutputPlugin = &InfluxUnifi{} + type metric struct { Table string Tags map[string]string @@ -88,9 +90,9 @@ func init() { // nolint: gochecknoinits u := &InfluxUnifi{InfluxDB: &InfluxDB{}, LastCheck: time.Now()} poller.NewOutput(&poller.Output{ - Name: PluginName, - Config: u.InfluxDB, - Method: u.Run, + Name: PluginName, + Config: u.InfluxDB, + OutputPlugin: u, }) } @@ -130,15 +132,29 @@ func (u *InfluxUnifi) PollController() { } } +func (u *InfluxUnifi) Enabled() bool { + if u == nil { + return false + } + if u.Config == nil { + return false + } + if u.Collector == nil { + return false + } + return !u.Disable +} + // Run runs a ticker to poll the unifi server and update influxdb. func (u *InfluxUnifi) Run(c poller.Collect) error { - var err error - - if u.Collector = c; u.Config == nil || u.Disable { + u.Collector = c + if !u.Enabled() { u.Logf("InfluxDB config missing (or disabled), InfluxDB output disabled!") return nil } + var err error + u.setConfigDefaults() if u.IsVersion2 { diff --git a/pkg/lokiunifi/loki.go b/pkg/lokiunifi/loki.go index 0f54c39e..f7965e05 100644 --- a/pkg/lokiunifi/loki.go +++ b/pkg/lokiunifi/loki.go @@ -46,6 +46,8 @@ type Loki struct { last time.Time } +var _ poller.OutputPlugin = &Loki{} + // init is how this modular code is initialized by the main app. // This module adds itself as an output module to the poller core. func init() { // nolint: gochecknoinits @@ -55,15 +57,26 @@ func init() { // nolint: gochecknoinits }} poller.NewOutput(&poller.Output{ - Name: PluginName, - Config: l, - Method: l.Run, + Name: PluginName, + Config: l, + OutputPlugin: l, }) } +func (l *Loki) Enabled() bool { + if l == nil { + return false + } + if l.Config == nil { + return false + } + return !l.Disable +} + // Run is fired from the poller library after the Config is unmarshalled. func (l *Loki) Run(collect poller.Collect) error { - if l.Collect = collect; l.Config == nil || l.URL == "" || l.Disable { + l.Collect = collect + if l.Config == nil || l.URL == "" || !l.Enabled() { l.Logf("Loki config missing (or disabled), Loki output disabled!") return nil } diff --git a/pkg/mysqlunifi/main.go b/pkg/mysqlunifi/main.go index be58ffb5..7fbb2d76 100644 --- a/pkg/mysqlunifi/main.go +++ b/pkg/mysqlunifi/main.go @@ -13,6 +13,8 @@ type plugin struct { poller.Collect } +var _ poller.OutputPlugin = &plugin{} + // Config represents the data that is unmarshalled from the up.conf config file for this plugins. // See up.conf.example.mysql for sample input data. type Config struct { @@ -48,16 +50,30 @@ func init() { u := &plugin{Config: &Config{}} poller.NewOutput(&poller.Output{ - Name: "mysql", - Config: u, // pass in the struct *above* your config (so it can see the struct tags). - Method: u.Run, + Name: "mysql", + Config: u, // pass in the struct *above* your config (so it can see the struct tags). + OutputPlugin: u, }) } +func (p *plugin) Enabled() bool { + if p == nil { + return false + } + if p.Config == nil { + return false + } + if p.Collect == nil { + return false + } + return !p.Disable +} + // Run gets called by poller core code. Return when the plugin stops working or has an error. // In other words, don't run your code in a go routine, it already is. func (p *plugin) Run(c poller.Collect) error { - if p.Collect = c; c == nil || p.Config == nil || p.Disable { + p.Collect = c + if p.Config == nil || !p.Enabled() { return nil // no config or disabled, bail out. } diff --git a/pkg/poller/outputs.go b/pkg/poller/outputs.go index a3a5a3ce..3225227a 100644 --- a/pkg/poller/outputs.go +++ b/pkg/poller/outputs.go @@ -24,12 +24,17 @@ type Collect interface { Outputs() []string } +type OutputPlugin interface { + Run(Collect) error + Enabled() bool +} + // Output defines the output data for a metric exporter like influx or prometheus. // Output packages should call NewOutput with this struct in init(). type Output struct { Name string - Config any // Each config is passed into an unmarshaller later. - Method func(Collect) error // Called on startup for each configured output. + Config any // Each config is passed into an unmarshaller later. + OutputPlugin } // NewOutput should be called by each output package's init function. @@ -37,8 +42,8 @@ func NewOutput(o *Output) { outputSync.Lock() defer outputSync.Unlock() - if o == nil || o.Method == nil { - panic("nil output or method passed to poller.NewOutput") + if o == nil { + panic("nil output passed to poller.NewOutput") } outputs = append(outputs, o) @@ -81,9 +86,11 @@ func (u *UnifiPoller) runOutputMethods() (int, chan error) { defer outputSync.RUnlock() for _, o := range outputs { - go func(o *Output) { - err <- o.Method(u) // Run each output plugin - }(o) + if o != nil && o.Enabled() { + go func(o *Output) { + err <- o.Run(u) // Run each output plugin + }(o) + } } return len(outputs), err diff --git a/pkg/promunifi/collector.go b/pkg/promunifi/collector.go index 795119de..3098cde2 100644 --- a/pkg/promunifi/collector.go +++ b/pkg/promunifi/collector.go @@ -46,6 +46,8 @@ type promUnifi struct { Collector poller.Collect } +var _ poller.OutputPlugin = &promUnifi{} + // Config is the input (config file) data used to initialize this output plugin. type Config struct { // If non-empty, each of the collected metrics is prefixed by the @@ -106,16 +108,30 @@ func init() { // nolint: gochecknoinits u := &promUnifi{Config: &Config{}} poller.NewOutput(&poller.Output{ - Name: PluginName, - Config: u, - Method: u.Run, + Name: PluginName, + Config: u, + OutputPlugin: u, }) } +func (u *promUnifi) Enabled() bool { + if u == nil { + return false + } + if u.Config == nil { + return false + } + if u.Collector == nil { + return false + } + return !u.Disable +} + // Run creates the collectors and starts the web server up. // Should be run in a Go routine. Returns nil if not configured. func (u *promUnifi) Run(c poller.Collect) error { - if u.Collector = c; u.Config == nil || u.Disable { + u.Collector = c + if u.Config == nil || !u.Enabled() { u.Logf("Prometheus config missing (or disabled), Prometheus HTTP listener disabled!") return nil } diff --git a/pkg/webserver/server.go b/pkg/webserver/server.go index 2ba2f2fc..a3cb622b 100644 --- a/pkg/webserver/server.go +++ b/pkg/webserver/server.go @@ -47,6 +47,8 @@ type Server struct { start time.Time } +var _ poller.OutputPlugin = &Server{} + // init is how this modular code is initialized by the main app. // This module adds itself as an output module to the poller core. func init() { // nolint: gochecknoinits @@ -58,15 +60,29 @@ func init() { // nolint: gochecknoinits plugins.Config = s.Config poller.NewOutput(&poller.Output{ - Name: PluginName, - Config: s, - Method: s.Run, + Name: PluginName, + Config: s, + OutputPlugin: s, }) } +func (s *Server) Enabled() bool { + if s == nil { + return false + } + if s.Config == nil { + return false + } + if s.Collect == nil { + return false + } + return s.Enable +} + // Run starts the server and gets things going. func (s *Server) Run(c poller.Collect) error { - if s.Collect = c; s.Config == nil || s.Port == 0 || s.HTMLPath == "" || !s.Enable { + s.Collect = c + if s.Config == nil || s.Port == 0 || s.HTMLPath == "" || !s.Enabled() { s.Logf("Internal web server disabled!") return nil }