diff --git a/integrations/influxunifi/Gopkg.lock b/integrations/influxunifi/Gopkg.lock
index ebe365dd..2c504530 100644
--- a/integrations/influxunifi/Gopkg.lock
+++ b/integrations/influxunifi/Gopkg.lock
@@ -9,6 +9,22 @@
revision = "3012a1dbe2e4bd1391d42b32f0577cb7bbc7f005"
version = "v0.3.1"
+[[projects]]
+ digest = "1:d6afaeed1502aa28e80a4ed0981d570ad91b2579193404256ce672ed0a609e0d"
+ name = "github.com/beorn7/perks"
+ packages = ["quantile"]
+ pruneopts = "UT"
+ revision = "37c8de3658fcb183f997c4e13e8337516ab753e6"
+ version = "v1.0.1"
+
+[[projects]]
+ digest = "1:573ca21d3669500ff845bdebee890eb7fc7f0f50c59f2132f2a0c6b03d85086a"
+ name = "github.com/golang/protobuf"
+ packages = ["proto"]
+ pruneopts = "UT"
+ revision = "6c65a5562fc06764971b7c5d05c76c75e84bdbf7"
+ version = "v1.3.2"
+
[[projects]]
branch = "master"
digest = "1:50708c8fc92aec981df5c446581cf9f90ba9e2a5692118e0ce75d4534aaa14a2"
@@ -21,6 +37,58 @@
pruneopts = "UT"
revision = "fc22c7df067eefd070157f157893fbce961d6359"
+[[projects]]
+ digest = "1:ff5ebae34cfbf047d505ee150de27e60570e8c394b3b8fdbb720ff6ac71985fc"
+ name = "github.com/matttproud/golang_protobuf_extensions"
+ packages = ["pbutil"]
+ pruneopts = "UT"
+ revision = "c12348ce28de40eed0136aa2b644d0ee0650e56c"
+ version = "v1.0.1"
+
+[[projects]]
+ digest = "1:eb04f69c8991e52eff33c428bd729e04208bf03235be88e4df0d88497c6861b9"
+ name = "github.com/prometheus/client_golang"
+ packages = [
+ "prometheus",
+ "prometheus/internal",
+ "prometheus/promhttp",
+ ]
+ pruneopts = "UT"
+ revision = "170205fb58decfd011f1550d4cfb737230d7ae4f"
+ version = "v1.1.0"
+
+[[projects]]
+ branch = "master"
+ digest = "1:2d5cd61daa5565187e1d96bae64dbbc6080dacf741448e9629c64fd93203b0d4"
+ name = "github.com/prometheus/client_model"
+ packages = ["go"]
+ pruneopts = "UT"
+ revision = "14fe0d1b01d4d5fc031dd4bec1823bd3ebbe8016"
+
+[[projects]]
+ digest = "1:f119e3205d3a1f0f19dbd7038eb37528e2c6f0933269dc344e305951fb87d632"
+ name = "github.com/prometheus/common"
+ packages = [
+ "expfmt",
+ "internal/bitbucket.org/ww/goautoneg",
+ "model",
+ ]
+ pruneopts = "UT"
+ revision = "287d3e634a1e550c9e463dd7e5a75a422c614505"
+ version = "v0.7.0"
+
+[[projects]]
+ digest = "1:3e363393b80d8f142984a811464eb7e34064700626cc111887373ea76f8ea0bf"
+ name = "github.com/prometheus/procfs"
+ packages = [
+ ".",
+ "internal/fs",
+ "internal/util",
+ ]
+ pruneopts = "UT"
+ revision = "8a055596020d692cf491851e47ba3e302d9f90ce"
+ version = "v0.0.6"
+
[[projects]]
digest = "1:524b71991fc7d9246cc7dc2d9e0886ccb97648091c63e30eef619e6862c955dd"
name = "github.com/spf13/pflag"
@@ -29,6 +97,14 @@
revision = "2e9d26c8c37aae03e3f9d4e90b7116f5accb7cab"
version = "v1.0.5"
+[[projects]]
+ branch = "master"
+ digest = "1:71b15a23c3c47b97dd98f97c6afde8da4de9f21dec38c34e2ac2e04dc7b09167"
+ name = "golang.org/x/sys"
+ packages = ["windows"]
+ pruneopts = "UT"
+ revision = "d32e6e3b99c40f2bfaea45ea9596ed539eed1c0d"
+
[[projects]]
digest = "1:e74d5f03545d51228b9539aaffc5eb8a692fcb22f38fa60253437b1fc063a73b"
name = "golift.io/unifi"
@@ -51,6 +127,7 @@
input-imports = [
"github.com/BurntSushi/toml",
"github.com/influxdata/influxdb1-client/v2",
+ "github.com/prometheus/client_golang/prometheus/promhttp",
"github.com/spf13/pflag",
"golift.io/unifi",
"gopkg.in/yaml.v2",
diff --git a/integrations/influxunifi/examples/MANUAL.md b/integrations/influxunifi/examples/MANUAL.md
index c9ecd0de..16038cf4 100644
--- a/integrations/influxunifi/examples/MANUAL.md
+++ b/integrations/influxunifi/examples/MANUAL.md
@@ -89,10 +89,10 @@ is provided so the application can be easily adapted to any environment.
mode default: "influx"
* Value: influx
This default mode runs this application as a daemon. It will poll
- the controller at the configured interval. Providing an invalid value
- will run in this default mode.
+ the controller at the configured interval and report measurements to
+ InfluxDB. Providing an invalid value will run in this default mode.
- * Value: influxlambda - (the only other available option right now)
+ * Value: influxlambda
Setting this value will invoke a run-once mode where the application
immediately polls the controller and reports the metrics to InfluxDB.
Then it exits. This mode is useful in an AWS Lambda or a crontab where
@@ -101,6 +101,16 @@ is provided so the application can be easily adapted to any environment.
This mode can also be combined with a "test database" in InfluxDB to
give yourself a "test config file" you may run ad-hoc to test changes.
+ * Value: prometheus
+ In this mode the application opens an http interface and exports the
+ measurements at /metrics for collection by prometheus. Enabling this
+ mode disables InfluxDB usage entirely.
+
+ http_listen default: 0.0.0.0:61317
+ This option controls the IP and port the http listener uses when the
+ mode is set to prometheus. This setting has no effect when other modes
+ are in use.
+
influx_url default: http://127.0.0.1:8086
This is the URL where the Influx web server is available.
diff --git a/integrations/influxunifi/examples/up.conf.example b/integrations/influxunifi/examples/up.conf.example
index ae6497e7..e702ec28 100644
--- a/integrations/influxunifi/examples/up.conf.example
+++ b/integrations/influxunifi/examples/up.conf.example
@@ -24,13 +24,21 @@ quiet = false
# an invalid mode will also result in "influx". In this default mode the application
# runs as a daemon and polls the controller at the configured interval.
#
-# There is only one other option at this time: "influxlambda"
+# There are two other options at this time: "influxlambda" and "prometheus"
#
# Lambda mode makes the application exit after collecting and reporting metrics
# to InfluxDB one time. This mode requires an external process like an AWS Lambda
# or a simple crontab to keep the timings accurate on UniFi Poller run intervals.
+#
+# Prometheus mode opens an HTTP server on port 61317 and exports the metrics at
+# /metrics for polling collection by a prometheus server. This disables influxdb.
mode = "influx"
+
+# This controls on which ip and port /metrics is exported when mode is "prometheus".
+# This has no effect in other modes. Must contain a colon and port.
+http_listen = "0.0.0.0:61317"
+
# InfluxDB does not require auth by default, so the user/password are probably unimportant.
influx_url = "http://127.0.0.1:8086"
influx_user = "unifi"
diff --git a/integrations/influxunifi/examples/up.json.example b/integrations/influxunifi/examples/up.json.example
index e59ec7c3..7b67ac5b 100644
--- a/integrations/influxunifi/examples/up.json.example
+++ b/integrations/influxunifi/examples/up.json.example
@@ -4,6 +4,7 @@
"debug": false,
"quiet": false,
"mode": "influx",
+ "http_listen": "0.0.0.0:61317",
"influx_url": "http://127.0.0.1:8086",
"influx_user": "unifi",
"influx_pass": "unifi",
diff --git a/integrations/influxunifi/examples/up.xml.example b/integrations/influxunifi/examples/up.xml.example
index 87f1cac5..f77503e5 100644
--- a/integrations/influxunifi/examples/up.xml.example
+++ b/integrations/influxunifi/examples/up.xml.example
@@ -40,14 +40,23 @@
# an invalid mode will also result in "influx". In this default mode the application
# runs as a daemon and polls the controller at the configured interval.
#
- # There is only one other option at this time: "influxlambda"
+ # There are two other options at this time: "influxlambda" and "prometheus"
#
# Lambda mode makes the application exit after collecting and reporting metrics
# to InfluxDB one time. This mode requires an external process like an AWS Lambda
# or a simple crontab to keep the timings accurate on UniFi Poller run intervals.
+ #
+ # Prometheus mode opens an HTTP server on port 61317 and exports the metrics at
+ # /metrics for polling collection by a prometheus server. This disables influxdb.
-->
influx
+
+ 0.0.0.0:61317
+
diff --git a/integrations/influxunifi/examples/up.yaml.example b/integrations/influxunifi/examples/up.yaml.example
index 1042c4e1..c55b8d95 100644
--- a/integrations/influxunifi/examples/up.yaml.example
+++ b/integrations/influxunifi/examples/up.yaml.example
@@ -25,13 +25,20 @@ quiet: false
# an invalid mode will also result in "influx". In this default mode the application
# runs as a daemon and polls the controller at the configured interval.
#
-# There is only one other option at this time: "influxlambda"
+# There are two other options at this time: "influxlambda" and "prometheus"
#
# Lambda mode makes the application exit after collecting and reporting metrics
# to InfluxDB one time. This mode requires an external process like an AWS Lambda
# or a simple crontab to keep the timings accurate on UniFi Poller run intervals.
+#
+# Prometheus mode opens an HTTP server on port 61317 and exports the metrics at
+# /metrics for polling collection by a prometheus server. This disables influxdb.
mode: "influx"
+# This controls on which ip and port /metrics is exported when mode is "prometheus".
+# This has no effect in other modes. Must contain a colon and port.
+http_listen: "0.0.0.0:61317"
+
# InfluxDB does not require auth by default, so the user/password are probably unimportant.
influx_url: "http://127.0.0.1:8086"
influx_user: "unifi"
diff --git a/integrations/influxunifi/unifipoller/config.go b/integrations/influxunifi/unifipoller/config.go
index 56516dda..7a4bdbfe 100644
--- a/integrations/influxunifi/unifipoller/config.go
+++ b/integrations/influxunifi/unifipoller/config.go
@@ -31,6 +31,7 @@ const (
defaultInfluxURL = "http://127.0.0.1:8086"
defaultUnifiUser = "influx"
defaultUnifiURL = "https://127.0.0.1:8443"
+ defaultHTTPListen = ":61317"
)
// ENVConfigPrefix is the prefix appended to an env variable tag
@@ -77,6 +78,7 @@ type Config struct {
ReAuth bool `json:"reauthenticate" toml:"reauthenticate" xml:"reauthenticate" yaml:"reauthenticate" env:"REAUTHENTICATE"`
InfxBadSSL bool `json:"influx_insecure_ssl" toml:"influx_insecure_ssl" xml:"influx_insecure_ssl" yaml:"influx_insecure_ssl" env:"INFLUX_INSECURE_SSL"`
Mode string `json:"mode" toml:"mode" xml:"mode" yaml:"mode" env:"POLLING_MODE"`
+ HTTPListen string `json:"http_listen" toml:"http_listen" xml:"http_listen" yaml:"http_listen" env:"HTTP_LISTEN"`
InfluxURL string `json:"influx_url,omitempty" toml:"influx_url,omitempty" xml:"influx_url" yaml:"influx_url" env:"INFLUX_URL"`
InfluxUser string `json:"influx_user,omitempty" toml:"influx_user,omitempty" xml:"influx_user" yaml:"influx_user" env:"INFLUX_USER"`
InfluxPass string `json:"influx_pass,omitempty" toml:"influx_pass,omitempty" xml:"influx_pass" yaml:"influx_pass" env:"INFLUX_PASS"`
diff --git a/integrations/influxunifi/unifipoller/start.go b/integrations/influxunifi/unifipoller/start.go
index 334119a1..d154cd88 100644
--- a/integrations/influxunifi/unifipoller/start.go
+++ b/integrations/influxunifi/unifipoller/start.go
@@ -4,11 +4,13 @@ import (
"crypto/tls"
"fmt"
"log"
+ "net/http"
"os"
"strings"
"time"
influx "github.com/influxdata/influxdb1-client/v2"
+ "github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/spf13/pflag"
"golift.io/unifi"
)
@@ -30,6 +32,7 @@ func Start() error {
UnifiBase: defaultUnifiURL,
Interval: Duration{defaultInterval},
Sites: []string{"all"},
+ HTTPListen: defaultHTTPListen,
}}
up.Flag.Parse(os.Args[1:])
if up.Flag.ShowVer {
@@ -83,14 +86,28 @@ func (u *UnifiPoller) Run() (err error) {
if err = u.GetInfluxDB(); err != nil {
return err
}
- u.Logf("Logging Measurements to InfluxDB at %s as user %s", u.Config.InfluxURL, u.Config.InfluxUser)
+
switch strings.ToLower(u.Config.Mode) {
case "influxlambda", "lambdainflux", "lambda_influx", "influx_lambda":
- u.LogDebugf("Lambda Mode Enabled")
+ u.Logf("Logging Measurements to InfluxDB at %s as user %s one time (lambda mode)",
+ u.Config.InfluxURL, u.Config.InfluxUser)
u.LastCheck = time.Now()
- return u.CollectAndReport()
+ return u.CollectAndProcess(u.ReportMetrics)
+ case "prometheus", "exporter":
+ u.Logf("Exporting Measurements at https://%s/metrics for Prometheus", u.Config.HTTPListen)
+ u.Config.Mode = "http exporter"
+ http.Handle("/metrics", promhttp.Handler())
+ go func() {
+ err = http.ListenAndServe(u.Config.HTTPListen, nil)
+ if err != http.ErrServerClosed {
+ log.Fatalf("[ERROR] http server: %v", err)
+ }
+ }()
+ return u.PollController(u.ExportMetrics)
default:
- return u.PollController()
+ u.Logf("Logging Measurements to InfluxDB at %s as user %s", u.Config.InfluxURL, u.Config.InfluxUser)
+ u.Config.Mode = "influx poller"
+ return u.PollController(u.ReportMetrics)
}
}
diff --git a/integrations/influxunifi/unifipoller/unifi.go b/integrations/influxunifi/unifipoller/unifi.go
index 57fd8c51..b74b7bc4 100644
--- a/integrations/influxunifi/unifipoller/unifi.go
+++ b/integrations/influxunifi/unifipoller/unifi.go
@@ -43,11 +43,12 @@ FIRST:
return nil
}
-// PollController runs forever, polling UniFi, and pushing to influx.
+// PollController runs forever, polling UniFi
+// and pushing to influx OR exporting for prometheus.
// This is started by Run() after everything checks out.
-func (u *UnifiPoller) PollController() error {
+func (u *UnifiPoller) PollController(process func(*Metrics) error) error {
interval := u.Config.Interval.Round(time.Second)
- log.Println("[INFO] Everything checks out! Poller started, interval:", interval)
+ log.Printf("[INFO] Everything checks out! Poller started in %v mode, interval: %v", u.Config.Mode, interval)
ticker := time.NewTicker(interval)
for u.LastCheck = range ticker.C {
var err error
@@ -60,7 +61,7 @@ func (u *UnifiPoller) PollController() error {
}
if err == nil {
// Only run this if the authentication procedure didn't return error.
- _ = u.CollectAndReport()
+ _ = u.CollectAndProcess(process)
}
if u.errorCount > 0 {
return fmt.Errorf("controller or influxdb errors, stopping poller")
@@ -69,12 +70,13 @@ func (u *UnifiPoller) PollController() error {
return nil
}
-// CollectAndReport collects measurements and reports them to influxdb.
+// CollectAndProcess collects measurements and then passese them into the
+// provided method. The method is either an http exporter or an influxdb update.
// Can be called once or in a ticker loop. This function and all the ones below
// handle their own logging. An error is returned so the calling function may
// determine if there was a read or write error and act on it. This is currently
// called in two places in this library. One returns an error, one does not.
-func (u *UnifiPoller) CollectAndReport() error {
+func (u *UnifiPoller) CollectAndProcess(process func(*Metrics) error) error {
metrics, err := u.CollectMetrics()
if err != nil {
return err
@@ -82,8 +84,8 @@ func (u *UnifiPoller) CollectAndReport() error {
if err := u.AugmentMetrics(metrics); err != nil {
return err
}
- err = u.ReportMetrics(metrics)
- u.LogError(err, "reporting metrics")
+ err = process(metrics)
+ u.LogError(err, "processing metrics")
return err
}
@@ -145,6 +147,15 @@ func (u *UnifiPoller) AugmentMetrics(metrics *Metrics) error {
return nil
}
+// ExportMetrics updates the internal metrics provided via
+// HTTP at /metrics for prometheus collection.
+func (u *UnifiPoller) ExportMetrics(metrics *Metrics) error {
+ /*
+ This is where it gets complicated, and probably deserves its own package.
+ */
+ return nil
+}
+
// ReportMetrics batches all the metrics and writes them to InfluxDB.
// Returns an error if the write to influx fails.
func (u *UnifiPoller) ReportMetrics(metrics *Metrics) error {