Merge pull request #155 from davidnewhall/dn2_dont_die
Prevent poller from dying from an error
This commit is contained in:
commit
740249d1de
|
|
@ -27,7 +27,7 @@
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
digest = "1:50708c8fc92aec981df5c446581cf9f90ba9e2a5692118e0ce75d4534aaa14a2"
|
digest = "1:00e5ad58045d6d2a6c9e65d1809ff2594bc396e911712ae892a93976fdece115"
|
||||||
name = "github.com/influxdata/influxdb1-client"
|
name = "github.com/influxdata/influxdb1-client"
|
||||||
packages = [
|
packages = [
|
||||||
"models",
|
"models",
|
||||||
|
|
@ -35,7 +35,7 @@
|
||||||
"v2",
|
"v2",
|
||||||
]
|
]
|
||||||
pruneopts = "UT"
|
pruneopts = "UT"
|
||||||
revision = "fc22c7df067eefd070157f157893fbce961d6359"
|
revision = "8bf82d3c094dc06be9da8e5bf9d3589b6ea032ae"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:ff5ebae34cfbf047d505ee150de27e60570e8c394b3b8fdbb720ff6ac71985fc"
|
digest = "1:ff5ebae34cfbf047d505ee150de27e60570e8c394b3b8fdbb720ff6ac71985fc"
|
||||||
|
|
@ -103,15 +103,15 @@
|
||||||
name = "golang.org/x/sys"
|
name = "golang.org/x/sys"
|
||||||
packages = ["windows"]
|
packages = ["windows"]
|
||||||
pruneopts = "UT"
|
pruneopts = "UT"
|
||||||
revision = "ce4227a45e2eb77e5c847278dcc6a626742e2945"
|
revision = "ac6580df4449443a05718fd7858c1f91ad5f8d20"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:87738e338f505d3e3be1f80d36b53f3c4e73be9b7ad4ccae46abbe9ef04f3f71"
|
digest = "1:2883cea734f2766f41ff9c9d4aefccccc53e3d44f5c8b08893b9c218cf666722"
|
||||||
name = "golift.io/unifi"
|
name = "golift.io/unifi"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
pruneopts = "UT"
|
pruneopts = "UT"
|
||||||
revision = "ba857a3a04311fed362cb43fa7bf4066bc3a7e55"
|
revision = "a607fe940c6a563c6994f2c945394b19d2183b1c"
|
||||||
version = "v4.1.5"
|
version = "v4.1.6"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:b75b3deb2bce8bc079e16bb2aecfe01eb80098f5650f9e93e5643ca8b7b73737"
|
digest = "1:b75b3deb2bce8bc079e16bb2aecfe01eb80098f5650f9e93e5643ca8b7b73737"
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,8 @@ import (
|
||||||
// batchUAP generates Wireless-Access-Point datapoints for InfluxDB.
|
// batchUAP generates Wireless-Access-Point datapoints for InfluxDB.
|
||||||
// These points can be passed directly to influx.
|
// These points can be passed directly to influx.
|
||||||
func (u *InfluxUnifi) batchUAP(r report, s *unifi.UAP) {
|
func (u *InfluxUnifi) batchUAP(r report, s *unifi.UAP) {
|
||||||
if s.Stat.Ap == nil {
|
if !s.Adopted.Val || s.Locating.Val {
|
||||||
s.Stat.Ap = &unifi.Ap{}
|
return
|
||||||
}
|
}
|
||||||
tags := map[string]string{
|
tags := map[string]string{
|
||||||
"mac": s.Mac,
|
"mac": s.Mac,
|
||||||
|
|
@ -36,6 +36,9 @@ func (u *InfluxUnifi) batchUAP(r report, s *unifi.UAP) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *InfluxUnifi) processUAPstats(ap *unifi.Ap) map[string]interface{} {
|
func (u *InfluxUnifi) processUAPstats(ap *unifi.Ap) map[string]interface{} {
|
||||||
|
if ap == nil {
|
||||||
|
return map[string]interface{}{}
|
||||||
|
}
|
||||||
// Accumulative Statistics.
|
// Accumulative Statistics.
|
||||||
return map[string]interface{}{
|
return map[string]interface{}{
|
||||||
"stat_user-rx_packets": ap.UserRxPackets.Val,
|
"stat_user-rx_packets": ap.UserRxPackets.Val,
|
||||||
|
|
|
||||||
|
|
@ -33,11 +33,8 @@ func (u *InfluxUnifi) batchSysStats(s unifi.SysStats, ss unifi.SystemStats) map[
|
||||||
// batchUDM generates Unifi Gateway datapoints for InfluxDB.
|
// batchUDM generates Unifi Gateway datapoints for InfluxDB.
|
||||||
// These points can be passed directly to influx.
|
// These points can be passed directly to influx.
|
||||||
func (u *InfluxUnifi) batchUDM(r report, s *unifi.UDM) {
|
func (u *InfluxUnifi) batchUDM(r report, s *unifi.UDM) {
|
||||||
if s.Stat.Sw == nil {
|
if !s.Adopted.Val || s.Locating.Val {
|
||||||
s.Stat.Sw = &unifi.Sw{}
|
return
|
||||||
}
|
|
||||||
if s.Stat.Gw == nil {
|
|
||||||
s.Stat.Gw = &unifi.Gw{}
|
|
||||||
}
|
}
|
||||||
tags := map[string]string{
|
tags := map[string]string{
|
||||||
"mac": s.Mac,
|
"mac": s.Mac,
|
||||||
|
|
@ -81,28 +78,18 @@ func (u *InfluxUnifi) batchUDM(r report, s *unifi.UDM) {
|
||||||
"serial": s.Serial,
|
"serial": s.Serial,
|
||||||
"type": s.Type,
|
"type": s.Type,
|
||||||
}
|
}
|
||||||
fields = map[string]interface{}{
|
fields = Combine(
|
||||||
"guest-num_sta": s.GuestNumSta.Val,
|
u.batchUSWstat(s.Stat.Sw),
|
||||||
"ip": s.IP,
|
map[string]interface{}{
|
||||||
"bytes": s.Bytes.Val,
|
"guest-num_sta": s.GuestNumSta.Val,
|
||||||
"last_seen": s.LastSeen.Val,
|
"ip": s.IP,
|
||||||
"rx_bytes": s.RxBytes.Val,
|
"bytes": s.Bytes.Val,
|
||||||
"tx_bytes": s.TxBytes.Val,
|
"last_seen": s.LastSeen.Val,
|
||||||
"uptime": s.Uptime.Val,
|
"rx_bytes": s.RxBytes.Val,
|
||||||
"state": s.State.Val,
|
"tx_bytes": s.TxBytes.Val,
|
||||||
"stat_bytes": s.Stat.Sw.Bytes.Val,
|
"uptime": s.Uptime.Val,
|
||||||
"stat_rx_bytes": s.Stat.Sw.RxBytes.Val,
|
"state": s.State.Val,
|
||||||
"stat_rx_crypts": s.Stat.Sw.RxCrypts.Val,
|
})
|
||||||
"stat_rx_dropped": s.Stat.Sw.RxDropped.Val,
|
|
||||||
"stat_rx_errors": s.Stat.Sw.RxErrors.Val,
|
|
||||||
"stat_rx_frags": s.Stat.Sw.RxFrags.Val,
|
|
||||||
"stat_rx_packets": s.Stat.Sw.TxPackets.Val,
|
|
||||||
"stat_tx_bytes": s.Stat.Sw.TxBytes.Val,
|
|
||||||
"stat_tx_dropped": s.Stat.Sw.TxDropped.Val,
|
|
||||||
"stat_tx_errors": s.Stat.Sw.TxErrors.Val,
|
|
||||||
"stat_tx_packets": s.Stat.Sw.TxPackets.Val,
|
|
||||||
"stat_tx_retries": s.Stat.Sw.TxRetries.Val,
|
|
||||||
}
|
|
||||||
r.send(&metric{Table: "usw", Tags: tags, Fields: fields})
|
r.send(&metric{Table: "usw", Tags: tags, Fields: fields})
|
||||||
u.batchPortTable(r, tags, s.PortTable)
|
u.batchPortTable(r, tags, s.PortTable)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,8 @@ import (
|
||||||
// batchUSG generates Unifi Gateway datapoints for InfluxDB.
|
// batchUSG generates Unifi Gateway datapoints for InfluxDB.
|
||||||
// These points can be passed directly to influx.
|
// These points can be passed directly to influx.
|
||||||
func (u *InfluxUnifi) batchUSG(r report, s *unifi.USG) {
|
func (u *InfluxUnifi) batchUSG(r report, s *unifi.USG) {
|
||||||
if s.Stat.Gw == nil {
|
if !s.Adopted.Val || s.Locating.Val {
|
||||||
s.Stat.Gw = &unifi.Gw{}
|
return
|
||||||
}
|
}
|
||||||
tags := map[string]string{
|
tags := map[string]string{
|
||||||
"mac": s.Mac,
|
"mac": s.Mac,
|
||||||
|
|
@ -74,6 +74,9 @@ func (u *InfluxUnifi) batchUSG(r report, s *unifi.USG) {
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
func (u *InfluxUnifi) batchUSGstat(ss unifi.SpeedtestStatus, gw *unifi.Gw, ul unifi.Uplink) map[string]interface{} {
|
func (u *InfluxUnifi) batchUSGstat(ss unifi.SpeedtestStatus, gw *unifi.Gw, ul unifi.Uplink) map[string]interface{} {
|
||||||
|
if gw == nil {
|
||||||
|
return map[string]interface{}{}
|
||||||
|
}
|
||||||
return map[string]interface{}{
|
return map[string]interface{}{
|
||||||
"uplink_latency": ul.Latency.Val,
|
"uplink_latency": ul.Latency.Val,
|
||||||
"uplink_speed": ul.Speed.Val,
|
"uplink_speed": ul.Speed.Val,
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,10 @@ import (
|
||||||
// batchUSW generates Unifi Switch datapoints for InfluxDB.
|
// batchUSW generates Unifi Switch datapoints for InfluxDB.
|
||||||
// These points can be passed directly to influx.
|
// These points can be passed directly to influx.
|
||||||
func (u *InfluxUnifi) batchUSW(r report, s *unifi.USW) {
|
func (u *InfluxUnifi) batchUSW(r report, s *unifi.USW) {
|
||||||
if s.Stat.Sw == nil {
|
if !s.Adopted.Val || s.Locating.Val {
|
||||||
s.Stat.Sw = &unifi.Sw{}
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
tags := map[string]string{
|
tags := map[string]string{
|
||||||
"mac": s.Mac,
|
"mac": s.Mac,
|
||||||
"site_name": s.SiteName,
|
"site_name": s.SiteName,
|
||||||
|
|
@ -19,35 +20,45 @@ func (u *InfluxUnifi) batchUSW(r report, s *unifi.USW) {
|
||||||
"serial": s.Serial,
|
"serial": s.Serial,
|
||||||
"type": s.Type,
|
"type": s.Type,
|
||||||
}
|
}
|
||||||
fields := Combine(map[string]interface{}{
|
fields := Combine(
|
||||||
"guest-num_sta": s.GuestNumSta.Val,
|
u.batchUSWstat(s.Stat.Sw),
|
||||||
"ip": s.IP,
|
u.batchSysStats(s.SysStats, s.SystemStats),
|
||||||
"bytes": s.Bytes.Val,
|
map[string]interface{}{
|
||||||
"fan_level": s.FanLevel.Val,
|
"guest-num_sta": s.GuestNumSta.Val,
|
||||||
"general_temperature": s.GeneralTemperature.Val,
|
"ip": s.IP,
|
||||||
"last_seen": s.LastSeen.Val,
|
"bytes": s.Bytes.Val,
|
||||||
"rx_bytes": s.RxBytes.Val,
|
"fan_level": s.FanLevel.Val,
|
||||||
"tx_bytes": s.TxBytes.Val,
|
"general_temperature": s.GeneralTemperature.Val,
|
||||||
"uptime": s.Uptime.Val,
|
"last_seen": s.LastSeen.Val,
|
||||||
"state": s.State.Val,
|
"rx_bytes": s.RxBytes.Val,
|
||||||
"user-num_sta": s.UserNumSta.Val,
|
"tx_bytes": s.TxBytes.Val,
|
||||||
"stat_bytes": s.Stat.Sw.Bytes.Val,
|
"uptime": s.Uptime.Val,
|
||||||
"stat_rx_bytes": s.Stat.Sw.RxBytes.Val,
|
"state": s.State.Val,
|
||||||
"stat_rx_crypts": s.Stat.Sw.RxCrypts.Val,
|
"user-num_sta": s.UserNumSta.Val,
|
||||||
"stat_rx_dropped": s.Stat.Sw.RxDropped.Val,
|
})
|
||||||
"stat_rx_errors": s.Stat.Sw.RxErrors.Val,
|
|
||||||
"stat_rx_frags": s.Stat.Sw.RxFrags.Val,
|
|
||||||
"stat_rx_packets": s.Stat.Sw.TxPackets.Val,
|
|
||||||
"stat_tx_bytes": s.Stat.Sw.TxBytes.Val,
|
|
||||||
"stat_tx_dropped": s.Stat.Sw.TxDropped.Val,
|
|
||||||
"stat_tx_errors": s.Stat.Sw.TxErrors.Val,
|
|
||||||
"stat_tx_packets": s.Stat.Sw.TxPackets.Val,
|
|
||||||
"stat_tx_retries": s.Stat.Sw.TxRetries.Val,
|
|
||||||
}, u.batchSysStats(s.SysStats, s.SystemStats))
|
|
||||||
r.send(&metric{Table: "usw", Tags: tags, Fields: fields})
|
r.send(&metric{Table: "usw", Tags: tags, Fields: fields})
|
||||||
u.batchPortTable(r, tags, s.PortTable)
|
u.batchPortTable(r, tags, s.PortTable)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *InfluxUnifi) batchUSWstat(sw *unifi.Sw) map[string]interface{} {
|
||||||
|
if sw == nil {
|
||||||
|
return map[string]interface{}{}
|
||||||
|
}
|
||||||
|
return map[string]interface{}{
|
||||||
|
"stat_bytes": sw.Bytes.Val,
|
||||||
|
"stat_rx_bytes": sw.RxBytes.Val,
|
||||||
|
"stat_rx_crypts": sw.RxCrypts.Val,
|
||||||
|
"stat_rx_dropped": sw.RxDropped.Val,
|
||||||
|
"stat_rx_errors": sw.RxErrors.Val,
|
||||||
|
"stat_rx_frags": sw.RxFrags.Val,
|
||||||
|
"stat_rx_packets": sw.TxPackets.Val,
|
||||||
|
"stat_tx_bytes": sw.TxBytes.Val,
|
||||||
|
"stat_tx_dropped": sw.TxDropped.Val,
|
||||||
|
"stat_tx_errors": sw.TxErrors.Val,
|
||||||
|
"stat_tx_packets": sw.TxPackets.Val,
|
||||||
|
"stat_tx_retries": sw.TxRetries.Val,
|
||||||
|
}
|
||||||
|
}
|
||||||
func (u *InfluxUnifi) batchPortTable(r report, t map[string]string, pt []unifi.Port) {
|
func (u *InfluxUnifi) batchPortTable(r report, t map[string]string, pt []unifi.Port) {
|
||||||
for _, p := range pt {
|
for _, p := range pt {
|
||||||
if !p.Up.Val || !p.Enable.Val {
|
if !p.Up.Val || !p.Enable.Val {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,13 @@
|
||||||
package poller
|
package poller
|
||||||
|
|
||||||
|
/*
|
||||||
|
I consider this file the pinacle example of how to allow a Go application to be configured from a file.
|
||||||
|
You can put your configuration into any file format: XML, YAML, JSON, TOML, and you can override any
|
||||||
|
struct member using an environment variable. The Duration type is also supported. All of the Config{}
|
||||||
|
and Duration{} types and methods are reusable in other projects. Just adjust the data in the struct to
|
||||||
|
meet your app's needs. See the New() procedure and Start() method in start.go for example usage.
|
||||||
|
*/
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"encoding/xml"
|
"encoding/xml"
|
||||||
|
|
@ -10,6 +18,7 @@ import (
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/BurntSushi/toml"
|
"github.com/BurntSushi/toml"
|
||||||
|
|
@ -45,8 +54,8 @@ type UnifiPoller struct {
|
||||||
Unifi *unifi.Unifi
|
Unifi *unifi.Unifi
|
||||||
Flag *Flag
|
Flag *Flag
|
||||||
Config *Config
|
Config *Config
|
||||||
errorCount int
|
|
||||||
LastCheck time.Time
|
LastCheck time.Time
|
||||||
|
sync.Mutex // locks the Unifi struct member when re-authing to unifi.
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flag represents the CLI args available and their settings.
|
// Flag represents the CLI args available and their settings.
|
||||||
|
|
@ -110,44 +119,50 @@ func (c *Config) ParseFile(configFile string) error {
|
||||||
// ParseENV copies environment variables into configuration values.
|
// ParseENV copies environment variables into configuration values.
|
||||||
// This is useful for Docker users that find it easier to pass ENV variables
|
// This is useful for Docker users that find it easier to pass ENV variables
|
||||||
// than a specific configuration file. Uses reflection to find struct tags.
|
// than a specific configuration file. Uses reflection to find struct tags.
|
||||||
|
// This method uses the json struct tag member to match environment variables.
|
||||||
|
// Use a custom tag name by changing "json" below, but that's overkill for this app.
|
||||||
func (c *Config) ParseENV() error {
|
func (c *Config) ParseENV() error {
|
||||||
t := reflect.TypeOf(Config{}) // Get tag names from the Config struct.
|
t := reflect.TypeOf(*c) // Get "types" from the Config struct.
|
||||||
// Loop each Config struct member; get reflect tag & env var value; update config.
|
for i := 0; i < t.NumField(); i++ { // Loop each Config struct member
|
||||||
for i := 0; i < t.NumField(); i++ {
|
|
||||||
tag := t.Field(i).Tag.Get("json") // Get the ENV variable name from "json" struct tag
|
tag := t.Field(i).Tag.Get("json") // Get the ENV variable name from "json" struct tag
|
||||||
tag = strings.Split(strings.ToUpper(tag), ",")[0] // Capitalize and remove ,omitempty suffix
|
tag = strings.Split(strings.ToUpper(tag), ",")[0] // Capitalize and remove ,omitempty suffix
|
||||||
env := os.Getenv(ENVConfigPrefix + tag) // Then pull value from OS.
|
env := os.Getenv(ENVConfigPrefix + tag) // Then pull value from OS.
|
||||||
if tag == "" || env == "" {
|
if tag == "" || env == "" { // Skip if either are empty.
|
||||||
continue // Skip if either are empty.
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reflect and update the u.Config struct member at position i.
|
// Reflect and update the u.Config struct member at position i.
|
||||||
switch c := reflect.ValueOf(c).Elem().Field(i); c.Type().String() {
|
switch field := reflect.ValueOf(c).Elem().Field(i); field.Type().String() {
|
||||||
// Handle each member type appropriately (differently).
|
// Handle each member type appropriately (differently).
|
||||||
case "string":
|
case "string":
|
||||||
// This is a reflect package method to update a struct member by index.
|
// This is a reflect package method to update a struct member by index.
|
||||||
c.SetString(env)
|
field.SetString(env)
|
||||||
|
|
||||||
case "int":
|
case "int":
|
||||||
val, err := strconv.Atoi(env)
|
val, err := strconv.Atoi(env)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("%s: %v", tag, err)
|
return fmt.Errorf("%s: %v", tag, err)
|
||||||
}
|
}
|
||||||
c.Set(reflect.ValueOf(val))
|
field.Set(reflect.ValueOf(val))
|
||||||
|
|
||||||
case "[]string":
|
case "[]string":
|
||||||
c.Set(reflect.ValueOf(strings.Split(env, ",")))
|
field.Set(reflect.ValueOf(strings.Split(env, ",")))
|
||||||
|
|
||||||
case path.Base(t.PkgPath()) + ".Duration":
|
case path.Base(t.PkgPath()) + ".Duration":
|
||||||
val, err := time.ParseDuration(env)
|
val, err := time.ParseDuration(env)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("%s: %v", tag, err)
|
return fmt.Errorf("%s: %v", tag, err)
|
||||||
}
|
}
|
||||||
c.Set(reflect.ValueOf(Duration{val}))
|
field.Set(reflect.ValueOf(Duration{val}))
|
||||||
|
|
||||||
case "bool":
|
case "bool":
|
||||||
val, err := strconv.ParseBool(env)
|
val, err := strconv.ParseBool(env)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("%s: %v", tag, err)
|
return fmt.Errorf("%s: %v", tag, err)
|
||||||
}
|
}
|
||||||
c.SetBool(val)
|
field.SetBool(val)
|
||||||
}
|
}
|
||||||
|
// Add more types here if more types are added to the config struct.
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
||||||
|
|
@ -35,9 +35,9 @@ func (u *UnifiPoller) DumpJSONPayload() (err error) {
|
||||||
case err != nil:
|
case err != nil:
|
||||||
return err
|
return err
|
||||||
case StringInSlice(u.Flag.DumpJSON, []string{"d", "device", "devices"}):
|
case StringInSlice(u.Flag.DumpJSON, []string{"d", "device", "devices"}):
|
||||||
return u.dumpSitesJSON(unifi.DevicePath, "Devices", sites)
|
return u.dumpSitesJSON(unifi.APIDevicePath, "Devices", sites)
|
||||||
case StringInSlice(u.Flag.DumpJSON, []string{"client", "clients", "c"}):
|
case StringInSlice(u.Flag.DumpJSON, []string{"client", "clients", "c"}):
|
||||||
return u.dumpSitesJSON(unifi.ClientPath, "Clients", sites)
|
return u.dumpSitesJSON(unifi.APIClientPath, "Clients", sites)
|
||||||
case strings.HasPrefix(u.Flag.DumpJSON, "other "):
|
case strings.HasPrefix(u.Flag.DumpJSON, "other "):
|
||||||
apiPath := strings.SplitN(u.Flag.DumpJSON, " ", 2)[1]
|
apiPath := strings.SplitN(u.Flag.DumpJSON, " ", 2)[1]
|
||||||
_, _ = fmt.Fprintf(os.Stderr, "[INFO] Dumping Path '%s':\n", apiPath)
|
_, _ = fmt.Fprintf(os.Stderr, "[INFO] Dumping Path '%s':\n", apiPath)
|
||||||
|
|
|
||||||
|
|
@ -8,15 +8,6 @@ import (
|
||||||
|
|
||||||
const callDepth = 2
|
const callDepth = 2
|
||||||
|
|
||||||
// LogError logs an error and increments the error counter.
|
|
||||||
// Should be used in the poller loop.
|
|
||||||
func (u *UnifiPoller) LogError(err error, prefix string) {
|
|
||||||
if err != nil {
|
|
||||||
u.errorCount++
|
|
||||||
_ = log.Output(callDepth, fmt.Sprintf("[ERROR] %v: %v", prefix, err))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// StringInSlice returns true if a string is in a slice.
|
// StringInSlice returns true if a string is in a slice.
|
||||||
func StringInSlice(str string, slice []string) bool {
|
func StringInSlice(str string, slice []string) bool {
|
||||||
for _, s := range slice {
|
for _, s := range slice {
|
||||||
|
|
@ -41,7 +32,7 @@ func (u *UnifiPoller) LogDebugf(m string, v ...interface{}) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// LogErrorf prints an error log entry. This is used for external library logging.
|
// LogErrorf prints an error log entry.
|
||||||
func (u *UnifiPoller) LogErrorf(m string, v ...interface{}) {
|
func (u *UnifiPoller) LogErrorf(m string, v ...interface{}) {
|
||||||
_ = log.Output(callDepth, fmt.Sprintf("[ERROR] "+m, v...))
|
_ = log.Output(callDepth, fmt.Sprintf("[ERROR] "+m, v...))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ func (u *UnifiPoller) GetInfluxDB() (err error) {
|
||||||
if u.Influx != nil {
|
if u.Influx != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
u.Influx, err = influxunifi.New(&influxunifi.Config{
|
u.Influx, err = influxunifi.New(&influxunifi.Config{
|
||||||
Database: u.Config.InfluxDB,
|
Database: u.Config.InfluxDB,
|
||||||
User: u.Config.InfluxUser,
|
User: u.Config.InfluxUser,
|
||||||
|
|
@ -22,7 +23,9 @@ func (u *UnifiPoller) GetInfluxDB() (err error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("influxdb: %v", err)
|
return fmt.Errorf("influxdb: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
u.Logf("Logging Measurements to InfluxDB at %s as user %s", u.Config.InfluxURL, u.Config.InfluxUser)
|
u.Logf("Logging Measurements to InfluxDB at %s as user %s", u.Config.InfluxURL, u.Config.InfluxUser)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -35,16 +38,19 @@ func (u *UnifiPoller) CollectAndProcess() error {
|
||||||
if err := u.GetInfluxDB(); err != nil {
|
if err := u.GetInfluxDB(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
metrics, err := u.CollectMetrics()
|
metrics, err := u.CollectMetrics()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
u.AugmentMetrics(metrics)
|
u.AugmentMetrics(metrics)
|
||||||
|
|
||||||
report, err := u.Influx.ReportMetrics(metrics)
|
report, err := u.Influx.ReportMetrics(metrics)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
u.LogError(err, "processing metrics")
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
u.LogInfluxReport(report)
|
u.LogInfluxReport(report)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -52,9 +58,11 @@ func (u *UnifiPoller) CollectAndProcess() error {
|
||||||
// LogInfluxReport writes a log message after exporting to influxdb.
|
// LogInfluxReport writes a log message after exporting to influxdb.
|
||||||
func (u *UnifiPoller) LogInfluxReport(r *influxunifi.Report) {
|
func (u *UnifiPoller) LogInfluxReport(r *influxunifi.Report) {
|
||||||
idsMsg := ""
|
idsMsg := ""
|
||||||
|
|
||||||
if u.Config.SaveIDS {
|
if u.Config.SaveIDS {
|
||||||
idsMsg = fmt.Sprintf("IDS Events: %d, ", len(r.Metrics.IDSList))
|
idsMsg = fmt.Sprintf("IDS Events: %d, ", len(r.Metrics.IDSList))
|
||||||
}
|
}
|
||||||
|
|
||||||
u.Logf("UniFi Metrics Recorded. Sites: %d, Clients: %d, "+
|
u.Logf("UniFi Metrics Recorded. Sites: %d, Clients: %d, "+
|
||||||
"UAP: %d, USG/UDM: %d, USW: %d, %sPoints: %d, Fields: %d, Errs: %d, Elapsed: %v",
|
"UAP: %d, USG/UDM: %d, USW: %d, %sPoints: %d, Fields: %d, Errs: %d, Elapsed: %v",
|
||||||
len(r.Metrics.Sites), len(r.Metrics.Clients), len(r.Metrics.UAPs),
|
len(r.Metrics.Sites), len(r.Metrics.Clients), len(r.Metrics.UAPs),
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ const oneDecimalPoint = 10
|
||||||
|
|
||||||
// RunPrometheus starts the web server and registers the collector.
|
// RunPrometheus starts the web server and registers the collector.
|
||||||
func (u *UnifiPoller) RunPrometheus() error {
|
func (u *UnifiPoller) RunPrometheus() error {
|
||||||
u.Logf("Exporting Measurements at https://%s/metrics for Prometheus", u.Config.HTTPListen)
|
u.Logf("Exporting Measurements for Prometheus at https://%s/metrics", u.Config.HTTPListen)
|
||||||
http.Handle("/metrics", promhttp.Handler())
|
http.Handle("/metrics", promhttp.Handler())
|
||||||
prometheus.MustRegister(promunifi.NewUnifiCollector(promunifi.UnifiCollectorCnfg{
|
prometheus.MustRegister(promunifi.NewUnifiCollector(promunifi.UnifiCollectorCnfg{
|
||||||
Namespace: strings.Replace(u.Config.Namespace, "-", "", -1),
|
Namespace: strings.Replace(u.Config.Namespace, "-", "", -1),
|
||||||
|
|
@ -23,6 +23,7 @@ func (u *UnifiPoller) RunPrometheus() error {
|
||||||
LoggingFn: u.LogExportReport,
|
LoggingFn: u.LogExportReport,
|
||||||
ReportErrors: true, // XXX: Does this need to be configurable?
|
ReportErrors: true, // XXX: Does this need to be configurable?
|
||||||
}))
|
}))
|
||||||
|
|
||||||
return http.ListenAndServe(u.Config.HTTPListen, nil)
|
return http.ListenAndServe(u.Config.HTTPListen, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -34,8 +35,9 @@ func (u *UnifiPoller) ExportMetrics() (*metrics.Metrics, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
u.LogErrorf("collecting metrics: %v", err)
|
u.LogErrorf("collecting metrics: %v", err)
|
||||||
u.Logf("Re-authenticating to UniFi Controller")
|
u.Logf("Re-authenticating to UniFi Controller")
|
||||||
if err := u.Unifi.Login(); err != nil {
|
|
||||||
u.LogError(err, "re-authenticating")
|
if err := u.GetUnifi(); err != nil {
|
||||||
|
u.LogErrorf("re-authenticating: %v", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,10 @@ func New() *UnifiPoller {
|
||||||
SaveSites: true,
|
SaveSites: true,
|
||||||
HTTPListen: defaultHTTPListen,
|
HTTPListen: defaultHTTPListen,
|
||||||
Namespace: appName,
|
Namespace: appName,
|
||||||
}, Flag: &Flag{ConfigFile: DefaultConfFile},
|
},
|
||||||
|
Flag: &Flag{
|
||||||
|
ConfigFile: DefaultConfFile,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -36,6 +39,7 @@ func New() *UnifiPoller {
|
||||||
// Parses cli flags, parses config file, parses env vars, sets up logging, then:
|
// Parses cli flags, parses config file, parses env vars, sets up logging, then:
|
||||||
// - dumps a json payload OR - executes Run().
|
// - dumps a json payload OR - executes Run().
|
||||||
func (u *UnifiPoller) Start() error {
|
func (u *UnifiPoller) Start() error {
|
||||||
|
log.SetOutput(os.Stdout)
|
||||||
log.SetFlags(log.LstdFlags)
|
log.SetFlags(log.LstdFlags)
|
||||||
u.Flag.Parse(os.Args[1:])
|
u.Flag.Parse(os.Args[1:])
|
||||||
|
|
||||||
|
|
@ -92,63 +96,44 @@ func (f *Flag) Parse(args []string) {
|
||||||
// 2. Run the collector one time and report the metrics to influxdb. (lambda)
|
// 2. Run the collector one time and report the metrics to influxdb. (lambda)
|
||||||
// 3. Start a web server and wait for Prometheus to poll the application for metrics.
|
// 3. Start a web server and wait for Prometheus to poll the application for metrics.
|
||||||
func (u *UnifiPoller) Run() error {
|
func (u *UnifiPoller) Run() error {
|
||||||
if err := u.GetUnifi(); err != nil {
|
switch err := u.GetUnifi(); err {
|
||||||
return err
|
case nil:
|
||||||
|
u.Logf("Polling UniFi Controller at %s v%s as user %s. Sites: %v",
|
||||||
|
u.Config.UnifiBase, u.Unifi.ServerVersion, u.Config.UnifiUser, u.Config.Sites)
|
||||||
|
default:
|
||||||
|
u.LogErrorf("Controller Auth or Connection failed, but continuing to retry! %v", err)
|
||||||
}
|
}
|
||||||
u.Logf("Polling UniFi Controller at %s v%s as user %s. Sites: %v",
|
|
||||||
u.Config.UnifiBase, u.Unifi.ServerVersion, u.Config.UnifiUser, u.Config.Sites)
|
|
||||||
|
|
||||||
switch strings.ToLower(u.Config.Mode) {
|
switch strings.ToLower(u.Config.Mode) {
|
||||||
default:
|
default:
|
||||||
return u.PollController()
|
u.PollController()
|
||||||
|
return nil
|
||||||
case "influxlambda", "lambdainflux", "lambda_influx", "influx_lambda":
|
case "influxlambda", "lambdainflux", "lambda_influx", "influx_lambda":
|
||||||
u.LastCheck = time.Now()
|
u.LastCheck = time.Now()
|
||||||
return u.CollectAndProcess()
|
return u.CollectAndProcess()
|
||||||
|
case "both":
|
||||||
|
go u.PollController()
|
||||||
|
fallthrough
|
||||||
case "prometheus", "exporter":
|
case "prometheus", "exporter":
|
||||||
return u.RunPrometheus()
|
return u.RunPrometheus()
|
||||||
case "both":
|
|
||||||
return u.RunBoth()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// RunBoth starts the prometheus exporter and influxdb exporter at the same time.
|
|
||||||
// This will likely double the amount of polls your controller receives.
|
|
||||||
func (u *UnifiPoller) RunBoth() error {
|
|
||||||
e := make(chan error)
|
|
||||||
defer close(e)
|
|
||||||
go func() {
|
|
||||||
e <- u.RunPrometheus()
|
|
||||||
}()
|
|
||||||
go func() {
|
|
||||||
e <- u.PollController()
|
|
||||||
}()
|
|
||||||
// If either method returns an error (even nil), bail out.
|
|
||||||
return <-e
|
|
||||||
}
|
|
||||||
|
|
||||||
// PollController runs forever, polling UniFi and pushing to InfluxDB
|
// PollController runs forever, polling UniFi and pushing to InfluxDB
|
||||||
// This is started by Run() or RunBoth() after everything checks out.
|
// This is started by Run() or RunBoth() after everything checks out.
|
||||||
func (u *UnifiPoller) PollController() error {
|
func (u *UnifiPoller) PollController() {
|
||||||
interval := u.Config.Interval.Round(time.Second)
|
interval := u.Config.Interval.Round(time.Second)
|
||||||
log.Printf("[INFO] Everything checks out! Poller started, interval: %v", interval)
|
log.Printf("[INFO] Everything checks out! Poller started, InfluxDB interval: %v", interval)
|
||||||
ticker := time.NewTicker(interval)
|
|
||||||
defer ticker.Stop()
|
|
||||||
|
|
||||||
|
ticker := time.NewTicker(interval)
|
||||||
for u.LastCheck = range ticker.C {
|
for u.LastCheck = range ticker.C {
|
||||||
// Some users need to re-auth every interval because the cookie times out.
|
if err := u.CollectAndProcess(); err != nil {
|
||||||
if u.Config.ReAuth {
|
u.LogErrorf("%v", err)
|
||||||
u.LogDebugf("Re-authenticating to UniFi Controller")
|
|
||||||
if err := u.Unifi.Login(); err != nil {
|
if u.Unifi != nil {
|
||||||
return err
|
u.Unifi.CloseIdleConnections()
|
||||||
|
u.Unifi = nil // trigger re-auth in unifi.go.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := u.CollectAndProcess(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// check for errors from the unifi polls.
|
|
||||||
if u.errorCount > 0 {
|
|
||||||
return fmt.Errorf("too many errors, stopping poller")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,13 @@ import (
|
||||||
|
|
||||||
// GetUnifi returns a UniFi controller interface.
|
// GetUnifi returns a UniFi controller interface.
|
||||||
func (u *UnifiPoller) GetUnifi() (err error) {
|
func (u *UnifiPoller) GetUnifi() (err error) {
|
||||||
|
u.Lock()
|
||||||
|
defer u.Unlock()
|
||||||
|
|
||||||
|
if u.Unifi != nil {
|
||||||
|
u.Unifi.CloseIdleConnections()
|
||||||
|
}
|
||||||
|
|
||||||
// Create an authenticated session to the Unifi Controller.
|
// Create an authenticated session to the Unifi Controller.
|
||||||
u.Unifi, err = unifi.NewUnifi(&unifi.Config{
|
u.Unifi, err = unifi.NewUnifi(&unifi.Config{
|
||||||
User: u.Config.UnifiUser,
|
User: u.Config.UnifiUser,
|
||||||
|
|
@ -21,8 +28,10 @@ func (u *UnifiPoller) GetUnifi() (err error) {
|
||||||
DebugLog: u.LogDebugf, // Log debug messages.
|
DebugLog: u.LogDebugf, // Log debug messages.
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
u.Unifi = nil
|
||||||
return fmt.Errorf("unifi controller: %v", err)
|
return fmt.Errorf("unifi controller: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
u.LogDebugf("Authenticated with controller successfully")
|
u.LogDebugf("Authenticated with controller successfully")
|
||||||
|
|
||||||
return u.CheckSites()
|
return u.CheckSites()
|
||||||
|
|
@ -34,20 +43,26 @@ func (u *UnifiPoller) CheckSites() error {
|
||||||
if strings.Contains(strings.ToLower(u.Config.Mode), "lambda") {
|
if strings.Contains(strings.ToLower(u.Config.Mode), "lambda") {
|
||||||
return nil // Skip this in lambda mode.
|
return nil // Skip this in lambda mode.
|
||||||
}
|
}
|
||||||
|
|
||||||
u.LogDebugf("Checking Controller Sites List")
|
u.LogDebugf("Checking Controller Sites List")
|
||||||
|
|
||||||
sites, err := u.Unifi.GetSites()
|
sites, err := u.Unifi.GetSites()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
msg := []string{}
|
msg := []string{}
|
||||||
|
|
||||||
for _, site := range sites {
|
for _, site := range sites {
|
||||||
msg = append(msg, site.Name+" ("+site.Desc+")")
|
msg = append(msg, site.Name+" ("+site.Desc+")")
|
||||||
}
|
}
|
||||||
u.Logf("Found %d site(s) on controller: %v", len(msg), strings.Join(msg, ", "))
|
u.Logf("Found %d site(s) on controller: %v", len(msg), strings.Join(msg, ", "))
|
||||||
|
|
||||||
if StringInSlice("all", u.Config.Sites) {
|
if StringInSlice("all", u.Config.Sites) {
|
||||||
u.Config.Sites = []string{"all"}
|
u.Config.Sites = []string{"all"}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
FIRST:
|
FIRST:
|
||||||
for _, s := range u.Config.Sites {
|
for _, s := range u.Config.Sites {
|
||||||
for _, site := range sites {
|
for _, site := range sites {
|
||||||
|
|
@ -58,26 +73,44 @@ FIRST:
|
||||||
// This is fine, it may get added later.
|
// This is fine, it may get added later.
|
||||||
u.LogErrorf("configured site not found on controller: %v", s)
|
u.LogErrorf("configured site not found on controller: %v", s)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// CollectMetrics grabs all the measurements from a UniFi controller and returns them.
|
// CollectMetrics grabs all the measurements from a UniFi controller and returns them.
|
||||||
func (u *UnifiPoller) CollectMetrics() (*metrics.Metrics, error) {
|
func (u *UnifiPoller) CollectMetrics() (*metrics.Metrics, error) {
|
||||||
m := &metrics.Metrics{TS: u.LastCheck} // At this point, it's the Current Check.
|
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
|
if u.Unifi == nil || u.Config.ReAuth {
|
||||||
|
// Some users need to re-auth every interval because the cookie times out.
|
||||||
|
// Sometimes we hit this path when the controller dies.
|
||||||
|
u.Logf("Re-authenticating to UniFi Controller")
|
||||||
|
if err := u.GetUnifi(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m := &metrics.Metrics{TS: u.LastCheck} // At this point, it's the Current Check.
|
||||||
// Get the sites we care about.
|
// Get the sites we care about.
|
||||||
m.Sites, err = u.GetFilteredSites()
|
if m.Sites, err = u.GetFilteredSites(); err != nil {
|
||||||
u.LogError(err, "unifi.GetSites()")
|
return m, fmt.Errorf("unifi.GetSites(): %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
if u.Config.SaveIDS {
|
if u.Config.SaveIDS {
|
||||||
m.IDSList, err = u.Unifi.GetIDS(m.Sites, time.Now().Add(u.Config.Interval.Duration), time.Now())
|
m.IDSList, err = u.Unifi.GetIDS(m.Sites, time.Now().Add(u.Config.Interval.Duration), time.Now())
|
||||||
u.LogError(err, "unifi.GetIDS()")
|
return m, fmt.Errorf("unifi.GetIDS(): %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get all the points.
|
// Get all the points.
|
||||||
m.Clients, err = u.Unifi.GetClients(m.Sites)
|
if m.Clients, err = u.Unifi.GetClients(m.Sites); err != nil {
|
||||||
u.LogError(err, "unifi.GetClients()")
|
return m, fmt.Errorf("unifi.GetClients(): %v", err)
|
||||||
m.Devices, err = u.Unifi.GetDevices(m.Sites)
|
}
|
||||||
u.LogError(err, "unifi.GetDevices()")
|
|
||||||
return m, err
|
if m.Devices, err = u.Unifi.GetDevices(m.Sites); err != nil {
|
||||||
|
return m, fmt.Errorf("unifi.GetDevices(): %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return m, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// AugmentMetrics is our middleware layer between collecting metrics and writing them.
|
// AugmentMetrics is our middleware layer between collecting metrics and writing them.
|
||||||
|
|
@ -87,23 +120,29 @@ func (u *UnifiPoller) AugmentMetrics(metrics *metrics.Metrics) {
|
||||||
if metrics == nil || metrics.Devices == nil || metrics.Clients == nil {
|
if metrics == nil || metrics.Devices == nil || metrics.Clients == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
devices := make(map[string]string)
|
devices := make(map[string]string)
|
||||||
bssdIDs := make(map[string]string)
|
bssdIDs := make(map[string]string)
|
||||||
|
|
||||||
for _, r := range metrics.UAPs {
|
for _, r := range metrics.UAPs {
|
||||||
devices[r.Mac] = r.Name
|
devices[r.Mac] = r.Name
|
||||||
for _, v := range r.VapTable {
|
for _, v := range r.VapTable {
|
||||||
bssdIDs[v.Bssid] = fmt.Sprintf("%s %s %s:", r.Name, v.Radio, v.RadioName)
|
bssdIDs[v.Bssid] = fmt.Sprintf("%s %s %s:", r.Name, v.Radio, v.RadioName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, r := range metrics.USGs {
|
for _, r := range metrics.USGs {
|
||||||
devices[r.Mac] = r.Name
|
devices[r.Mac] = r.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, r := range metrics.USWs {
|
for _, r := range metrics.USWs {
|
||||||
devices[r.Mac] = r.Name
|
devices[r.Mac] = r.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, r := range metrics.UDMs {
|
for _, r := range metrics.UDMs {
|
||||||
devices[r.Mac] = r.Name
|
devices[r.Mac] = r.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
// These come blank, so set them here.
|
// These come blank, so set them here.
|
||||||
for i, c := range metrics.Clients {
|
for i, c := range metrics.Clients {
|
||||||
metrics.Clients[i].SwName = devices[c.SwMac]
|
metrics.Clients[i].SwName = devices[c.SwMac]
|
||||||
|
|
@ -111,6 +150,7 @@ func (u *UnifiPoller) AugmentMetrics(metrics *metrics.Metrics) {
|
||||||
metrics.Clients[i].GwName = devices[c.GwMac]
|
metrics.Clients[i].GwName = devices[c.GwMac]
|
||||||
metrics.Clients[i].RadioDescription = bssdIDs[metrics.Clients[i].Bssid] + metrics.Clients[i].RadioProto
|
metrics.Clients[i].RadioDescription = bssdIDs[metrics.Clients[i].Bssid] + metrics.Clients[i].RadioProto
|
||||||
}
|
}
|
||||||
|
|
||||||
if !u.Config.SaveSites {
|
if !u.Config.SaveSites {
|
||||||
metrics.Sites = nil
|
metrics.Sites = nil
|
||||||
}
|
}
|
||||||
|
|
@ -120,13 +160,15 @@ func (u *UnifiPoller) AugmentMetrics(metrics *metrics.Metrics) {
|
||||||
// Omits requested but unconfigured sites. Grabs the full list from the
|
// Omits requested but unconfigured sites. Grabs the full list from the
|
||||||
// controller and returns the sites provided in the config file.
|
// controller and returns the sites provided in the config file.
|
||||||
func (u *UnifiPoller) GetFilteredSites() (unifi.Sites, error) {
|
func (u *UnifiPoller) GetFilteredSites() (unifi.Sites, error) {
|
||||||
|
var i int
|
||||||
|
|
||||||
sites, err := u.Unifi.GetSites()
|
sites, err := u.Unifi.GetSites()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if len(u.Config.Sites) < 1 || StringInSlice("all", u.Config.Sites) {
|
} else if len(u.Config.Sites) < 1 || StringInSlice("all", u.Config.Sites) {
|
||||||
return sites, nil
|
return sites, nil
|
||||||
}
|
}
|
||||||
var i int
|
|
||||||
for _, s := range sites {
|
for _, s := range sites {
|
||||||
// Only include valid sites in the request filter.
|
// Only include valid sites in the request filter.
|
||||||
if StringInSlice(s.Name, u.Config.Sites) {
|
if StringInSlice(s.Name, u.Config.Sites) {
|
||||||
|
|
@ -134,5 +176,6 @@ func (u *UnifiPoller) GetFilteredSites() (unifi.Sites, error) {
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return sites[:i], nil
|
return sites[:i], nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -159,6 +159,9 @@ func descUAP(ns string) *uap {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *promUnifi) exportUAP(r report, d *unifi.UAP) {
|
func (u *promUnifi) exportUAP(r report, d *unifi.UAP) {
|
||||||
|
if !d.Adopted.Val || d.Locating.Val {
|
||||||
|
return
|
||||||
|
}
|
||||||
labels := []string{d.Type, d.SiteName, d.Name}
|
labels := []string{d.Type, d.SiteName, d.Name}
|
||||||
infoLabels := []string{d.Version, d.Model, d.Serial, d.Mac, d.IP, d.ID, d.Bytes.Txt, d.Uptime.Txt}
|
infoLabels := []string{d.Version, d.Model, d.Serial, d.Mac, d.IP, d.ID, d.Bytes.Txt, d.Uptime.Txt}
|
||||||
u.exportUAPstats(r, labels, d.Stat.Ap, d.BytesD, d.TxBytesD, d.RxBytesD, d.BytesR)
|
u.exportUAPstats(r, labels, d.Stat.Ap, d.BytesD, d.TxBytesD, d.RxBytesD, d.BytesR)
|
||||||
|
|
@ -175,6 +178,9 @@ func (u *promUnifi) exportUAP(r report, d *unifi.UAP) {
|
||||||
|
|
||||||
// udm doesn't have these stats exposed yet, so pass 2 or 6 metrics.
|
// udm doesn't have these stats exposed yet, so pass 2 or 6 metrics.
|
||||||
func (u *promUnifi) exportUAPstats(r report, labels []string, ap *unifi.Ap, bytes ...unifi.FlexInt) {
|
func (u *promUnifi) exportUAPstats(r report, labels []string, ap *unifi.Ap, bytes ...unifi.FlexInt) {
|
||||||
|
if ap == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
labelU := []string{"user", labels[1], labels[2]}
|
labelU := []string{"user", labels[1], labels[2]}
|
||||||
labelG := []string{"guest", labels[1], labels[2]}
|
labelG := []string{"guest", labels[1], labels[2]}
|
||||||
r.send([]*metric{
|
r.send([]*metric{
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,9 @@ func descDevice(ns string) *unifiDevice {
|
||||||
|
|
||||||
// UDM is a collection of stats from USG, USW and UAP. It has no unique stats.
|
// UDM is a collection of stats from USG, USW and UAP. It has no unique stats.
|
||||||
func (u *promUnifi) exportUDM(r report, d *unifi.UDM) {
|
func (u *promUnifi) exportUDM(r report, d *unifi.UDM) {
|
||||||
|
if !d.Adopted.Val || d.Locating.Val {
|
||||||
|
return
|
||||||
|
}
|
||||||
labels := []string{d.Type, d.SiteName, d.Name}
|
labels := []string{d.Type, d.SiteName, d.Name}
|
||||||
infoLabels := []string{d.Version, d.Model, d.Serial, d.Mac, d.IP, d.ID, d.Bytes.Txt, d.Uptime.Txt}
|
infoLabels := []string{d.Version, d.Model, d.Serial, d.Mac, d.IP, d.ID, d.Bytes.Txt, d.Uptime.Txt}
|
||||||
// Shared data (all devices do this).
|
// Shared data (all devices do this).
|
||||||
|
|
|
||||||
|
|
@ -69,6 +69,9 @@ func descUSG(ns string) *usg {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *promUnifi) exportUSG(r report, d *unifi.USG) {
|
func (u *promUnifi) exportUSG(r report, d *unifi.USG) {
|
||||||
|
if !d.Adopted.Val || d.Locating.Val {
|
||||||
|
return
|
||||||
|
}
|
||||||
labels := []string{d.Type, d.SiteName, d.Name}
|
labels := []string{d.Type, d.SiteName, d.Name}
|
||||||
infoLabels := []string{d.Version, d.Model, d.Serial, d.Mac, d.IP, d.ID, d.Bytes.Txt, d.Uptime.Txt}
|
infoLabels := []string{d.Version, d.Model, d.Serial, d.Mac, d.IP, d.ID, d.Bytes.Txt, d.Uptime.Txt}
|
||||||
// Gateway System Data.
|
// Gateway System Data.
|
||||||
|
|
@ -85,6 +88,9 @@ func (u *promUnifi) exportUSG(r report, d *unifi.USG) {
|
||||||
|
|
||||||
// Gateway States
|
// Gateway States
|
||||||
func (u *promUnifi) exportUSGstats(r report, labels []string, gw *unifi.Gw, st unifi.SpeedtestStatus, ul unifi.Uplink) {
|
func (u *promUnifi) exportUSGstats(r report, labels []string, gw *unifi.Gw, st unifi.SpeedtestStatus, ul unifi.Uplink) {
|
||||||
|
if gw == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
labelLan := []string{"lan", labels[1], labels[2]}
|
labelLan := []string{"lan", labels[1], labels[2]}
|
||||||
labelWan := []string{"all", labels[1], labels[2]}
|
labelWan := []string{"all", labels[1], labels[2]}
|
||||||
r.send([]*metric{
|
r.send([]*metric{
|
||||||
|
|
|
||||||
|
|
@ -91,6 +91,9 @@ func descUSW(ns string) *usw {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *promUnifi) exportUSW(r report, d *unifi.USW) {
|
func (u *promUnifi) exportUSW(r report, d *unifi.USW) {
|
||||||
|
if !d.Adopted.Val || d.Locating.Val {
|
||||||
|
return
|
||||||
|
}
|
||||||
labels := []string{d.Type, d.SiteName, d.Name}
|
labels := []string{d.Type, d.SiteName, d.Name}
|
||||||
infoLabels := []string{d.Version, d.Model, d.Serial, d.Mac, d.IP, d.ID, d.Bytes.Txt, d.Uptime.Txt}
|
infoLabels := []string{d.Version, d.Model, d.Serial, d.Mac, d.IP, d.ID, d.Bytes.Txt, d.Uptime.Txt}
|
||||||
u.exportUSWstats(r, labels, d.Stat.Sw)
|
u.exportUSWstats(r, labels, d.Stat.Sw)
|
||||||
|
|
@ -116,6 +119,9 @@ func (u *promUnifi) exportUSW(r report, d *unifi.USW) {
|
||||||
|
|
||||||
// Switch Stats
|
// Switch Stats
|
||||||
func (u *promUnifi) exportUSWstats(r report, labels []string, sw *unifi.Sw) {
|
func (u *promUnifi) exportUSWstats(r report, labels []string, sw *unifi.Sw) {
|
||||||
|
if sw == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
labelS := labels[1:]
|
labelS := labels[1:]
|
||||||
r.send([]*metric{
|
r.send([]*metric{
|
||||||
{u.USW.SwRxPackets, counter, sw.RxPackets, labelS},
|
{u.USW.SwRxPackets, counter, sw.RxPackets, labelS},
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue