convert input to plugin
This commit is contained in:
parent
4e48247f54
commit
0b8473657e
|
|
@ -11,7 +11,7 @@ HBREPO="golift/homebrew-mugs"
|
||||||
MAINT="David Newhall II <david at sleepers dot pro>"
|
MAINT="David Newhall II <david at sleepers dot pro>"
|
||||||
VENDOR="Go Lift <code at golift dot io>"
|
VENDOR="Go Lift <code at golift dot io>"
|
||||||
DESC="Polls a UniFi controller, exports metrics to InfluxDB and Prometheus"
|
DESC="Polls a UniFi controller, exports metrics to InfluxDB and Prometheus"
|
||||||
GOLANGCI_LINT_ARGS="--enable-all -D gochecknoglobals -D dupl -D lll -D funlen -D wsl -e G402 -D gochecknoinits"
|
GOLANGCI_LINT_ARGS="--enable-all -D gochecknoglobals -D funlen -e G402 -D gochecknoinits"
|
||||||
# Example must exist at examples/$CONFIG_FILE.example
|
# Example must exist at examples/$CONFIG_FILE.example
|
||||||
CONFIG_FILE="up.conf"
|
CONFIG_FILE="up.conf"
|
||||||
LICENSE="MIT"
|
LICENSE="MIT"
|
||||||
|
|
|
||||||
4
main.go
4
main.go
|
|
@ -4,7 +4,9 @@ import (
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
"github.com/davidnewhall/unifi-poller/pkg/poller"
|
"github.com/davidnewhall/unifi-poller/pkg/poller"
|
||||||
// Enable output plugins!
|
// Load input plugins!
|
||||||
|
_ "github.com/davidnewhall/unifi-poller/pkg/inputunifi"
|
||||||
|
// Load output plugins!
|
||||||
_ "github.com/davidnewhall/unifi-poller/pkg/influxunifi"
|
_ "github.com/davidnewhall/unifi-poller/pkg/influxunifi"
|
||||||
_ "github.com/davidnewhall/unifi-poller/pkg/promunifi"
|
_ "github.com/davidnewhall/unifi-poller/pkg/promunifi"
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -66,14 +66,7 @@ func (u *InfluxUnifi) batchClient(r report, s *unifi.Client) {
|
||||||
"wired-tx_bytes": s.WiredTxBytes,
|
"wired-tx_bytes": s.WiredTxBytes,
|
||||||
"wired-tx_bytes-r": s.WiredTxBytesR,
|
"wired-tx_bytes-r": s.WiredTxBytesR,
|
||||||
"wired-tx_packets": s.WiredTxPackets,
|
"wired-tx_packets": s.WiredTxPackets,
|
||||||
/*
|
|
||||||
"dpi_app": c.DpiStats.App.Val,
|
|
||||||
"dpi_cat": c.DpiStats.Cat.Val,
|
|
||||||
"dpi_rx_bytes": c.DpiStats.RxBytes.Val,
|
|
||||||
"dpi_rx_packets": c.DpiStats.RxPackets.Val,
|
|
||||||
"dpi_tx_bytes": c.DpiStats.TxBytes.Val,
|
|
||||||
"dpi_tx_packets": c.DpiStats.TxPackets.Val,
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
r.send(&metric{Table: "clients", Tags: tags, Fields: fields})
|
r.send(&metric{Table: "clients", Tags: tags, Fields: fields})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,5 +35,6 @@ func (u *InfluxUnifi) batchIDS(r report, i *unifi.IDS) {
|
||||||
"srcipASN": i.SrcipASN,
|
"srcipASN": i.SrcipASN,
|
||||||
"usgipASN": i.UsgipASN,
|
"usgipASN": i.UsgipASN,
|
||||||
}
|
}
|
||||||
|
|
||||||
r.send(&metric{Table: "intrusion_detect", Tags: tags, Fields: fields})
|
r.send(&metric{Table: "intrusion_detect", Tags: tags, Fields: fields})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ const (
|
||||||
defaultInterval = 30 * time.Second
|
defaultInterval = 30 * time.Second
|
||||||
minimumInterval = 10 * time.Second
|
minimumInterval = 10 * time.Second
|
||||||
defaultInfluxDB = "unifi"
|
defaultInfluxDB = "unifi"
|
||||||
defaultInfluxUser = "unifi"
|
defaultInfluxUser = "unifipoller"
|
||||||
defaultInfluxURL = "http://127.0.0.1:8086"
|
defaultInfluxURL = "http://127.0.0.1:8086"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -53,6 +53,7 @@ type metric struct {
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
u := &InfluxUnifi{InfluxDB: &InfluxDB{}, LastCheck: time.Now()}
|
u := &InfluxUnifi{InfluxDB: &InfluxDB{}, LastCheck: time.Now()}
|
||||||
|
|
||||||
poller.NewOutput(&poller.Output{
|
poller.NewOutput(&poller.Output{
|
||||||
Name: "influxdb",
|
Name: "influxdb",
|
||||||
Config: u.InfluxDB,
|
Config: u.InfluxDB,
|
||||||
|
|
@ -143,9 +144,12 @@ func (u *InfluxUnifi) setConfigDefaults() {
|
||||||
func (u *InfluxUnifi) ReportMetrics(m *poller.Metrics) (*Report, error) {
|
func (u *InfluxUnifi) ReportMetrics(m *poller.Metrics) (*Report, error) {
|
||||||
r := &Report{Metrics: m, ch: make(chan *metric), Start: time.Now()}
|
r := &Report{Metrics: m, ch: make(chan *metric), Start: time.Now()}
|
||||||
defer close(r.ch)
|
defer close(r.ch)
|
||||||
// Make a new Influx Points Batcher.
|
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
|
// Make a new Influx Points Batcher.
|
||||||
r.bp, err = influx.NewBatchPoints(influx.BatchPointsConfig{Database: u.Config.DB})
|
r.bp, err = influx.NewBatchPoints(influx.BatchPointsConfig{Database: u.Config.DB})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("influx.NewBatchPoints: %v", err)
|
return nil, fmt.Errorf("influx.NewBatchPoints: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -159,7 +163,9 @@ func (u *InfluxUnifi) ReportMetrics(m *poller.Metrics) (*Report, error) {
|
||||||
if err = u.influx.Write(r.bp); err != nil {
|
if err = u.influx.Write(r.bp); err != nil {
|
||||||
return nil, fmt.Errorf("influxdb.Write(points): %v", err)
|
return nil, fmt.Errorf("influxdb.Write(points): %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
r.Elapsed = time.Since(r.Start)
|
r.Elapsed = time.Since(r.Start)
|
||||||
|
|
||||||
return r, nil
|
return r, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -172,6 +178,7 @@ func (u *InfluxUnifi) collect(r report, ch chan *metric) {
|
||||||
} else {
|
} else {
|
||||||
r.batch(m, pt)
|
r.batch(m, pt)
|
||||||
}
|
}
|
||||||
|
|
||||||
r.done()
|
r.done()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -182,24 +189,28 @@ func (u *InfluxUnifi) loopPoints(r report) {
|
||||||
m := r.metrics()
|
m := r.metrics()
|
||||||
|
|
||||||
r.add()
|
r.add()
|
||||||
|
r.add()
|
||||||
|
r.add()
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
defer r.done()
|
defer r.done()
|
||||||
|
|
||||||
for _, s := range m.Sites {
|
for _, s := range m.Sites {
|
||||||
u.batchSite(r, s)
|
u.batchSite(r, s)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
r.add()
|
|
||||||
go func() {
|
go func() {
|
||||||
defer r.done()
|
defer r.done()
|
||||||
|
|
||||||
for _, s := range m.Clients {
|
for _, s := range m.Clients {
|
||||||
u.batchClient(r, s)
|
u.batchClient(r, s)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
r.add()
|
|
||||||
go func() {
|
go func() {
|
||||||
defer r.done()
|
defer r.done()
|
||||||
|
|
||||||
for _, s := range m.IDSList {
|
for _, s := range m.IDSList {
|
||||||
u.batchIDS(r, s)
|
u.batchIDS(r, s)
|
||||||
}
|
}
|
||||||
|
|
@ -209,33 +220,44 @@ func (u *InfluxUnifi) loopPoints(r report) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u.loopDevicePoints(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *InfluxUnifi) loopDevicePoints(r report) {
|
||||||
|
m := r.metrics()
|
||||||
|
|
||||||
r.add()
|
r.add()
|
||||||
|
r.add()
|
||||||
|
r.add()
|
||||||
|
r.add()
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
defer r.done()
|
defer r.done()
|
||||||
|
|
||||||
for _, s := range m.UAPs {
|
for _, s := range m.UAPs {
|
||||||
u.batchUAP(r, s)
|
u.batchUAP(r, s)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
r.add()
|
|
||||||
go func() {
|
go func() {
|
||||||
defer r.done()
|
defer r.done()
|
||||||
|
|
||||||
for _, s := range m.USGs {
|
for _, s := range m.USGs {
|
||||||
u.batchUSG(r, s)
|
u.batchUSG(r, s)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
r.add()
|
|
||||||
go func() {
|
go func() {
|
||||||
defer r.done()
|
defer r.done()
|
||||||
|
|
||||||
for _, s := range m.USWs {
|
for _, s := range m.USWs {
|
||||||
u.batchUSW(r, s)
|
u.batchUSW(r, s)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
r.add()
|
|
||||||
go func() {
|
go func() {
|
||||||
defer r.done()
|
defer r.done()
|
||||||
|
|
||||||
for _, s := range m.UDMs {
|
for _, s := range m.UDMs {
|
||||||
u.batchUDM(r, s)
|
u.batchUDM(r, s)
|
||||||
}
|
}
|
||||||
|
|
@ -51,6 +51,7 @@ func (u *InfluxUnifi) batchSite(r report, s *unifi.Site) {
|
||||||
"remote_user_tx_packets": h.RemoteUserTxPackets.Val,
|
"remote_user_tx_packets": h.RemoteUserTxPackets.Val,
|
||||||
"num_new_alarms": s.NumNewAlarms.Val,
|
"num_new_alarms": s.NumNewAlarms.Val,
|
||||||
}
|
}
|
||||||
|
|
||||||
r.send(&metric{Table: "subsystems", Tags: tags, Fields: fields})
|
r.send(&metric{Table: "subsystems", Tags: tags, Fields: fields})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ func (u *InfluxUnifi) batchUAP(r report, s *unifi.UAP) {
|
||||||
if !s.Adopted.Val || s.Locating.Val {
|
if !s.Adopted.Val || s.Locating.Val {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
tags := map[string]string{
|
tags := map[string]string{
|
||||||
"mac": s.Mac,
|
"mac": s.Mac,
|
||||||
"site_name": s.SiteName,
|
"site_name": s.SiteName,
|
||||||
|
|
@ -30,6 +31,7 @@ func (u *InfluxUnifi) batchUAP(r report, s *unifi.UAP) {
|
||||||
fields["user-num_sta"] = int(s.UserNumSta.Val)
|
fields["user-num_sta"] = int(s.UserNumSta.Val)
|
||||||
fields["guest-num_sta"] = int(s.GuestNumSta.Val)
|
fields["guest-num_sta"] = int(s.GuestNumSta.Val)
|
||||||
fields["num_sta"] = s.NumSta.Val
|
fields["num_sta"] = s.NumSta.Val
|
||||||
|
|
||||||
r.send(&metric{Table: "uap", Tags: tags, Fields: fields})
|
r.send(&metric{Table: "uap", Tags: tags, Fields: fields})
|
||||||
u.processRadTable(r, tags, s.RadioTable, s.RadioTableStats)
|
u.processRadTable(r, tags, s.RadioTable, s.RadioTableStats)
|
||||||
u.processVAPTable(r, tags, s.VapTable)
|
u.processVAPTable(r, tags, s.VapTable)
|
||||||
|
|
@ -39,6 +41,7 @@ func (u *InfluxUnifi) processUAPstats(ap *unifi.Ap) map[string]interface{} {
|
||||||
if ap == nil {
|
if ap == nil {
|
||||||
return map[string]interface{}{}
|
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,
|
||||||
|
|
@ -135,6 +138,7 @@ func (u *InfluxUnifi) processVAPTable(r report, t map[string]string, vt unifi.Va
|
||||||
"wifi_tx_latency_mov_total": s.WifiTxLatencyMov.Total.Val,
|
"wifi_tx_latency_mov_total": s.WifiTxLatencyMov.Total.Val,
|
||||||
"wifi_tx_latency_mov_cuont": s.WifiTxLatencyMov.TotalCount.Val,
|
"wifi_tx_latency_mov_cuont": s.WifiTxLatencyMov.TotalCount.Val,
|
||||||
}
|
}
|
||||||
|
|
||||||
r.send(&metric{Table: "uap_vaps", Tags: tags, Fields: fields})
|
r.send(&metric{Table: "uap_vaps", Tags: tags, Fields: fields})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -155,6 +159,7 @@ func (u *InfluxUnifi) processRadTable(r report, t map[string]string, rt unifi.Ra
|
||||||
"nss": p.Nss.Val,
|
"nss": p.Nss.Val,
|
||||||
"radio_caps": p.RadioCaps.Val,
|
"radio_caps": p.RadioCaps.Val,
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, t := range rts {
|
for _, t := range rts {
|
||||||
if t.Name == p.Name {
|
if t.Name == p.Name {
|
||||||
fields["ast_be_xmit"] = t.AstBeXmit.Val
|
fields["ast_be_xmit"] = t.AstBeXmit.Val
|
||||||
|
|
@ -171,9 +176,11 @@ func (u *InfluxUnifi) processRadTable(r report, t map[string]string, rt unifi.Ra
|
||||||
fields["tx_power"] = t.TxPower.Val
|
fields["tx_power"] = t.TxPower.Val
|
||||||
fields["tx_retries"] = t.TxRetries.Val
|
fields["tx_retries"] = t.TxRetries.Val
|
||||||
fields["user-num_sta"] = t.UserNumSta.Val
|
fields["user-num_sta"] = t.UserNumSta.Val
|
||||||
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
r.send(&metric{Table: "uap_radios", Tags: tags, Fields: fields})
|
r.send(&metric{Table: "uap_radios", Tags: tags, Fields: fields})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,14 +4,16 @@ import (
|
||||||
"golift.io/unifi"
|
"golift.io/unifi"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Combines concatenates N maps. This will delete things if not used with caution.
|
// Combine concatenates N maps. This will delete things if not used with caution.
|
||||||
func Combine(in ...map[string]interface{}) map[string]interface{} {
|
func Combine(in ...map[string]interface{}) map[string]interface{} {
|
||||||
out := make(map[string]interface{})
|
out := make(map[string]interface{})
|
||||||
|
|
||||||
for i := range in {
|
for i := range in {
|
||||||
for k := range in[i] {
|
for k := range in[i] {
|
||||||
out[k] = in[i][k]
|
out[k] = in[i][k]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -36,6 +38,7 @@ func (u *InfluxUnifi) batchUDM(r report, s *unifi.UDM) {
|
||||||
if !s.Adopted.Val || s.Locating.Val {
|
if !s.Adopted.Val || s.Locating.Val {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
tags := map[string]string{
|
tags := map[string]string{
|
||||||
"mac": s.Mac,
|
"mac": s.Mac,
|
||||||
"site_name": s.SiteName,
|
"site_name": s.SiteName,
|
||||||
|
|
@ -65,6 +68,7 @@ func (u *InfluxUnifi) batchUDM(r report, s *unifi.UDM) {
|
||||||
"num_mobile": s.NumMobile.Val,
|
"num_mobile": s.NumMobile.Val,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
r.send(&metric{Table: "usg", Tags: tags, Fields: fields})
|
r.send(&metric{Table: "usg", Tags: tags, Fields: fields})
|
||||||
u.batchNetTable(r, tags, s.NetworkTable)
|
u.batchNetTable(r, tags, s.NetworkTable)
|
||||||
u.batchUSGwans(r, tags, s.Wan1, s.Wan2)
|
u.batchUSGwans(r, tags, s.Wan1, s.Wan2)
|
||||||
|
|
@ -90,13 +94,14 @@ func (u *InfluxUnifi) batchUDM(r report, s *unifi.UDM) {
|
||||||
"uptime": s.Uptime.Val,
|
"uptime": s.Uptime.Val,
|
||||||
"state": s.State.Val,
|
"state": s.State.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)
|
||||||
|
|
||||||
if s.Stat.Ap == nil {
|
if s.Stat.Ap == nil {
|
||||||
return
|
return // we're done now. the following code process UDM (non-pro) UAP data.
|
||||||
// we're done now. the following code process UDM (non-pro) UAP data.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tags = map[string]string{
|
tags = map[string]string{
|
||||||
"mac": s.Mac,
|
"mac": s.Mac,
|
||||||
"site_name": s.SiteName,
|
"site_name": s.SiteName,
|
||||||
|
|
@ -117,6 +122,7 @@ func (u *InfluxUnifi) batchUDM(r report, s *unifi.UDM) {
|
||||||
fields["user-num_sta"] = int(s.UserNumSta.Val)
|
fields["user-num_sta"] = int(s.UserNumSta.Val)
|
||||||
fields["guest-num_sta"] = int(s.GuestNumSta.Val)
|
fields["guest-num_sta"] = int(s.GuestNumSta.Val)
|
||||||
fields["num_sta"] = s.NumSta.Val
|
fields["num_sta"] = s.NumSta.Val
|
||||||
|
|
||||||
r.send(&metric{Table: "uap", Tags: tags, Fields: fields})
|
r.send(&metric{Table: "uap", Tags: tags, Fields: fields})
|
||||||
u.processRadTable(r, tags, *s.RadioTable, *s.RadioTableStats)
|
u.processRadTable(r, tags, *s.RadioTable, *s.RadioTableStats)
|
||||||
u.processVAPTable(r, tags, *s.VapTable)
|
u.processVAPTable(r, tags, *s.VapTable)
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ func (u *InfluxUnifi) batchUSG(r report, s *unifi.USG) {
|
||||||
if !s.Adopted.Val || s.Locating.Val {
|
if !s.Adopted.Val || s.Locating.Val {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
tags := map[string]string{
|
tags := map[string]string{
|
||||||
"mac": s.Mac,
|
"mac": s.Mac,
|
||||||
"site_name": s.SiteName,
|
"site_name": s.SiteName,
|
||||||
|
|
@ -39,44 +40,17 @@ func (u *InfluxUnifi) batchUSG(r report, s *unifi.USG) {
|
||||||
"num_mobile": s.NumMobile.Val,
|
"num_mobile": s.NumMobile.Val,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
r.send(&metric{Table: "usg", Tags: tags, Fields: fields})
|
r.send(&metric{Table: "usg", Tags: tags, Fields: fields})
|
||||||
u.batchNetTable(r, tags, s.NetworkTable)
|
u.batchNetTable(r, tags, s.NetworkTable)
|
||||||
u.batchUSGwans(r, tags, s.Wan1, s.Wan2)
|
u.batchUSGwans(r, tags, s.Wan1, s.Wan2)
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
for _, p := range s.PortTable {
|
|
||||||
t := map[string]string{
|
|
||||||
"device_name": tags["name"],
|
|
||||||
"site_name": tags["site_name"],
|
|
||||||
"name": p.Name,
|
|
||||||
"ifname": p.Ifname,
|
|
||||||
"ip": p.IP,
|
|
||||||
"mac": p.Mac,
|
|
||||||
"up": p.Up.Txt,
|
|
||||||
"speed": p.Speed.Txt,
|
|
||||||
"full_duplex": p.FullDuplex.Txt,
|
|
||||||
"enable": p.Enable.Txt,
|
|
||||||
}
|
|
||||||
f := map[string]interface{}{
|
|
||||||
"rx_bytes": p.RxBytes.Val,
|
|
||||||
"rx_dropped": p.RxDropped.Val,
|
|
||||||
"rx_errors": p.RxErrors.Val,
|
|
||||||
"rx_packets": p.RxBytes.Val,
|
|
||||||
"tx_bytes": p.TxBytes.Val,
|
|
||||||
"tx_dropped": p.TxDropped.Val,
|
|
||||||
"tx_errors": p.TxErrors.Val,
|
|
||||||
"tx_packets": p.TxPackets.Val,
|
|
||||||
"rx_multicast": p.RxMulticast.Val,
|
|
||||||
"dns_servers": strings.Join(p.DNS, ","),
|
|
||||||
}
|
|
||||||
r.send(&metric{Table: "usg_ports", Tags: t, Fields: f})
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
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 {
|
if gw == nil {
|
||||||
return map[string]interface{}{}
|
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,
|
||||||
|
|
@ -92,11 +66,13 @@ func (u *InfluxUnifi) batchUSGstat(ss unifi.SpeedtestStatus, gw *unifi.Gw, ul un
|
||||||
"lan-rx_dropped": gw.LanRxDropped.Val,
|
"lan-rx_dropped": gw.LanRxDropped.Val,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *InfluxUnifi) batchUSGwans(r report, tags map[string]string, wans ...unifi.Wan) {
|
func (u *InfluxUnifi) batchUSGwans(r report, tags map[string]string, wans ...unifi.Wan) {
|
||||||
for _, wan := range wans {
|
for _, wan := range wans {
|
||||||
if !wan.Up.Val {
|
if !wan.Up.Val {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
tags := map[string]string{
|
tags := map[string]string{
|
||||||
"device_name": tags["name"],
|
"device_name": tags["name"],
|
||||||
"site_name": tags["site_name"],
|
"site_name": tags["site_name"],
|
||||||
|
|
@ -129,6 +105,7 @@ func (u *InfluxUnifi) batchUSGwans(r report, tags map[string]string, wans ...uni
|
||||||
"tx_broadcast": wan.TxBroadcast.Val,
|
"tx_broadcast": wan.TxBroadcast.Val,
|
||||||
"tx_multicast": wan.TxMulticast.Val,
|
"tx_multicast": wan.TxMulticast.Val,
|
||||||
}
|
}
|
||||||
|
|
||||||
r.send(&metric{Table: "usg_wan_ports", Tags: tags, Fields: fields})
|
r.send(&metric{Table: "usg_wan_ports", Tags: tags, Fields: fields})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -154,6 +131,7 @@ func (u *InfluxUnifi) batchNetTable(r report, tags map[string]string, nt unifi.N
|
||||||
"tx_bytes": p.TxBytes.Val,
|
"tx_bytes": p.TxBytes.Val,
|
||||||
"tx_packets": p.TxPackets.Val,
|
"tx_packets": p.TxPackets.Val,
|
||||||
}
|
}
|
||||||
|
|
||||||
r.send(&metric{Table: "usg_networks", Tags: tags, Fields: fields})
|
r.send(&metric{Table: "usg_networks", Tags: tags, Fields: fields})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@ func (u *InfluxUnifi) batchUSW(r report, s *unifi.USW) {
|
||||||
"state": s.State.Val,
|
"state": s.State.Val,
|
||||||
"user-num_sta": s.UserNumSta.Val,
|
"user-num_sta": s.UserNumSta.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)
|
||||||
}
|
}
|
||||||
|
|
@ -44,6 +45,7 @@ func (u *InfluxUnifi) batchUSWstat(sw *unifi.Sw) map[string]interface{} {
|
||||||
if sw == nil {
|
if sw == nil {
|
||||||
return map[string]interface{}{}
|
return map[string]interface{}{}
|
||||||
}
|
}
|
||||||
|
|
||||||
return map[string]interface{}{
|
return map[string]interface{}{
|
||||||
"stat_bytes": sw.Bytes.Val,
|
"stat_bytes": sw.Bytes.Val,
|
||||||
"stat_rx_bytes": sw.RxBytes.Val,
|
"stat_rx_bytes": sw.RxBytes.Val,
|
||||||
|
|
@ -59,11 +61,13 @@ func (u *InfluxUnifi) batchUSWstat(sw *unifi.Sw) map[string]interface{} {
|
||||||
"stat_tx_retries": sw.TxRetries.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 {
|
||||||
continue // only record UP ports.
|
continue // only record UP ports.
|
||||||
}
|
}
|
||||||
|
|
||||||
tags := map[string]string{
|
tags := map[string]string{
|
||||||
"site_name": t["site_name"],
|
"site_name": t["site_name"],
|
||||||
"device_name": t["name"],
|
"device_name": t["name"],
|
||||||
|
|
@ -96,11 +100,13 @@ func (u *InfluxUnifi) batchPortTable(r report, t map[string]string, pt []unifi.P
|
||||||
"tx_multicast": p.TxMulticast.Val,
|
"tx_multicast": p.TxMulticast.Val,
|
||||||
"tx_packets": p.TxPackets.Val,
|
"tx_packets": p.TxPackets.Val,
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.PoeEnable.Val && p.PortPoe.Val {
|
if p.PoeEnable.Val && p.PortPoe.Val {
|
||||||
fields["poe_current"] = p.PoeCurrent.Val
|
fields["poe_current"] = p.PoeCurrent.Val
|
||||||
fields["poe_power"] = p.PoePower.Val
|
fields["poe_power"] = p.PoePower.Val
|
||||||
fields["poe_voltage"] = p.PoeVoltage.Val
|
fields["poe_voltage"] = p.PoeVoltage.Val
|
||||||
}
|
}
|
||||||
|
|
||||||
r.send(&metric{Table: "usw_ports", Tags: tags, Fields: fields})
|
r.send(&metric{Table: "usw_ports", Tags: tags, Fields: fields})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,138 @@
|
||||||
|
package inputunifi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/davidnewhall/unifi-poller/pkg/poller"
|
||||||
|
"golift.io/unifi"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (u *InputUnifi) isNill(c Controller) bool {
|
||||||
|
u.Config.RLock()
|
||||||
|
defer u.Config.RUnlock()
|
||||||
|
|
||||||
|
return c.Unifi == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *InputUnifi) collectController(c Controller) (*poller.Metrics, error) {
|
||||||
|
if u.isNill(c) {
|
||||||
|
u.Logf("Re-authenticating to UniFi Controller: %s", c.URL)
|
||||||
|
|
||||||
|
if err := u.getUnifi(c); err != nil {
|
||||||
|
return nil, fmt.Errorf("re-authenticating to %s: %v", c.Name, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m, err := u.pollController(c)
|
||||||
|
if err == nil {
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return u.pollController(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *InputUnifi) pollController(c Controller) (*poller.Metrics, error) {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
u.Config.RLock()
|
||||||
|
defer u.Config.RUnlock()
|
||||||
|
|
||||||
|
m := &poller.Metrics{TS: time.Now()} // At this point, it's the Current Check.
|
||||||
|
|
||||||
|
// Get the sites we care about.
|
||||||
|
if m.Sites, err = u.getFilteredSites(c); err != nil {
|
||||||
|
return m, fmt.Errorf("unifi.GetSites(%v): %v", c.URL, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.SaveIDS {
|
||||||
|
m.IDSList, err = c.Unifi.GetIDS(m.Sites, time.Now().Add(2*time.Minute), time.Now())
|
||||||
|
if err != nil {
|
||||||
|
return m, fmt.Errorf("unifi.GetIDS(%v): %v", c.URL, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get all the points.
|
||||||
|
if m.Clients, err = c.Unifi.GetClients(m.Sites); err != nil {
|
||||||
|
return m, fmt.Errorf("unifi.GetClients(%v): %v", c.URL, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.Devices, err = c.Unifi.GetDevices(m.Sites); err != nil {
|
||||||
|
return m, fmt.Errorf("unifi.GetDevices(%v): %v", c.URL, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return u.augmentMetrics(c, m), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// augmentMetrics is our middleware layer between collecting metrics and writing them.
|
||||||
|
// This is where we can manipuate the returned data or make arbitrary decisions.
|
||||||
|
// This function currently adds parent device names to client metrics.
|
||||||
|
func (u *InputUnifi) augmentMetrics(c Controller, metrics *poller.Metrics) *poller.Metrics {
|
||||||
|
if metrics == nil || metrics.Devices == nil || metrics.Clients == nil {
|
||||||
|
return metrics
|
||||||
|
}
|
||||||
|
|
||||||
|
devices := make(map[string]string)
|
||||||
|
bssdIDs := make(map[string]string)
|
||||||
|
|
||||||
|
for _, r := range metrics.UAPs {
|
||||||
|
devices[r.Mac] = r.Name
|
||||||
|
|
||||||
|
for _, v := range r.VapTable {
|
||||||
|
bssdIDs[v.Bssid] = fmt.Sprintf("%s %s %s:", r.Name, v.Radio, v.RadioName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, r := range metrics.USGs {
|
||||||
|
devices[r.Mac] = r.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, r := range metrics.USWs {
|
||||||
|
devices[r.Mac] = r.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, r := range metrics.UDMs {
|
||||||
|
devices[r.Mac] = r.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
// These come blank, so set them here.
|
||||||
|
for i, c := range metrics.Clients {
|
||||||
|
metrics.Clients[i].SwName = devices[c.SwMac]
|
||||||
|
metrics.Clients[i].ApName = devices[c.ApMac]
|
||||||
|
metrics.Clients[i].GwName = devices[c.GwMac]
|
||||||
|
metrics.Clients[i].RadioDescription = bssdIDs[metrics.Clients[i].Bssid] + metrics.Clients[i].RadioProto
|
||||||
|
}
|
||||||
|
|
||||||
|
if !c.SaveSites {
|
||||||
|
metrics.Sites = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return metrics
|
||||||
|
}
|
||||||
|
|
||||||
|
// getFilteredSites returns a list of sites to fetch data for.
|
||||||
|
// Omits requested but unconfigured sites. Grabs the full list from the
|
||||||
|
// controller and returns the sites provided in the config file.
|
||||||
|
func (u *InputUnifi) getFilteredSites(c Controller) (unifi.Sites, error) {
|
||||||
|
u.Config.RLock()
|
||||||
|
defer u.Config.RUnlock()
|
||||||
|
|
||||||
|
sites, err := c.Unifi.GetSites()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if len(c.Sites) < 1 || poller.StringInSlice("all", c.Sites) {
|
||||||
|
return sites, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var i int
|
||||||
|
|
||||||
|
for _, s := range sites {
|
||||||
|
// Only include valid sites in the request filter.
|
||||||
|
if poller.StringInSlice(s.Name, c.Sites) {
|
||||||
|
sites[i] = s
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sites[:i], nil
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,78 @@
|
||||||
|
// Package inputunifi implements the poller.Input interface and bridges the gap between
|
||||||
|
// metrics from the unifi library, and the augments required to pump them into unifi-poller.
|
||||||
|
package inputunifi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/davidnewhall/unifi-poller/pkg/poller"
|
||||||
|
"golift.io/unifi"
|
||||||
|
)
|
||||||
|
|
||||||
|
// InputUnifi contains the running data.
|
||||||
|
type InputUnifi struct {
|
||||||
|
Config Config `json:"unifi" toml:"unifi" xml:"unifi" yaml:"unifi"`
|
||||||
|
poller.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
// Controller represents the configuration for a UniFi Controller.
|
||||||
|
// Each polled controller may have its own configuration.
|
||||||
|
type Controller struct {
|
||||||
|
VerifySSL bool `json:"verify_ssl" toml:"verify_ssl" xml:"verify_ssl" yaml:"verify_ssl"`
|
||||||
|
SaveIDS bool `json:"save_ids" toml:"save_ids" xml:"save_ids" yaml:"save_ids"`
|
||||||
|
SaveSites bool `json:"save_sites" toml:"save_sites" xml:"save_sites" yaml:"save_sites"`
|
||||||
|
Name string `json:"name" toml:"name" xml:"name,attr" yaml:"name"`
|
||||||
|
User string `json:"user" toml:"user" xml:"user" yaml:"user"`
|
||||||
|
Pass string `json:"pass" toml:"pass" xml:"pass" yaml:"pass"`
|
||||||
|
URL string `json:"url" toml:"url" xml:"url" yaml:"url"`
|
||||||
|
Sites []string `json:"sites,omitempty" toml:"sites,omitempty" xml:"sites" yaml:"sites"`
|
||||||
|
Unifi *unifi.Unifi `json:"-" toml:"-" xml:"-" yaml:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Config contains our configuration data
|
||||||
|
type Config struct {
|
||||||
|
sync.RWMutex // locks the Unifi struct member when re-authing to unifi.
|
||||||
|
Disable bool `json:"disable" toml:"disable" xml:"disable" yaml:"disable"`
|
||||||
|
Controllers []Controller `json:"controller" toml:"controller" xml:"controller" yaml:"controller"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
u := &InputUnifi{}
|
||||||
|
|
||||||
|
poller.NewInput(&poller.InputPlugin{
|
||||||
|
Input: u, // this library implements poller.Input interface for Metrics().
|
||||||
|
Config: u, // Defines our config data interface.
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// getUnifi (re-)authenticates to a unifi controller.
|
||||||
|
func (u *InputUnifi) getUnifi(c Controller) error {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
u.Config.Lock()
|
||||||
|
defer u.Config.Unlock()
|
||||||
|
|
||||||
|
if c.Unifi != nil {
|
||||||
|
c.Unifi.CloseIdleConnections()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create an authenticated session to the Unifi Controller.
|
||||||
|
c.Unifi, err = unifi.NewUnifi(&unifi.Config{
|
||||||
|
User: c.User,
|
||||||
|
Pass: c.Pass,
|
||||||
|
URL: c.URL,
|
||||||
|
VerifySSL: c.VerifySSL,
|
||||||
|
ErrorLog: u.LogErrorf, // Log all errors.
|
||||||
|
DebugLog: u.LogDebugf, // Log debug messages.
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
c.Unifi = nil
|
||||||
|
return fmt.Errorf("unifi controller: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
u.LogDebugf("Authenticated with controller successfully, %s", c.URL)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,122 @@
|
||||||
|
package inputunifi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/davidnewhall/unifi-poller/pkg/poller"
|
||||||
|
"golift.io/unifi"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Metrics grabs all the measurements from a UniFi controller and returns them.
|
||||||
|
func (u *InputUnifi) Metrics() (*poller.Metrics, error) {
|
||||||
|
errs := []string{}
|
||||||
|
metrics := &poller.Metrics{}
|
||||||
|
|
||||||
|
for _, c := range u.Config.Controllers {
|
||||||
|
m, err := u.collectController(c)
|
||||||
|
if err != nil {
|
||||||
|
errs = append(errs, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
if m == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
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...)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(errs) > 0 {
|
||||||
|
return metrics, fmt.Errorf(strings.Join(errs, ", "))
|
||||||
|
}
|
||||||
|
|
||||||
|
return metrics, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize gets called one time when starting up.
|
||||||
|
// Satisfies poller.Input interface.
|
||||||
|
func (u *InputUnifi) Initialize(l poller.Logger) error {
|
||||||
|
if u.Config.Disable {
|
||||||
|
l.Logf("unifi input disabled")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(u.Config.Controllers) < 1 {
|
||||||
|
return fmt.Errorf("no unifi controllers defined for unifi input")
|
||||||
|
}
|
||||||
|
|
||||||
|
u.Logger = l
|
||||||
|
|
||||||
|
for i, c := range u.Config.Controllers {
|
||||||
|
if c.Name == "" {
|
||||||
|
u.Config.Controllers[i].Name = c.URL
|
||||||
|
}
|
||||||
|
|
||||||
|
switch err := u.getUnifi(c); err {
|
||||||
|
case nil:
|
||||||
|
if err := u.checkSites(c); err != nil {
|
||||||
|
u.LogErrorf("checking sites on %s: %v", c.Name, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
u.Logf("Polling UniFi Controller at %s v%s as user %s. Sites: %v",
|
||||||
|
c.URL, c.Unifi.ServerVersion, c.User, c.Sites)
|
||||||
|
default:
|
||||||
|
u.LogErrorf("Controller Auth or Connection failed, but continuing to retry! %s: %v", c.Name, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// checkSites makes sure the list of provided sites exists on the controller.
|
||||||
|
// This only runs once during initialization.
|
||||||
|
func (u *InputUnifi) checkSites(c Controller) error {
|
||||||
|
u.Config.RLock()
|
||||||
|
defer u.Config.RUnlock()
|
||||||
|
u.LogDebugf("Checking Controller Sites List")
|
||||||
|
|
||||||
|
sites, err := c.Unifi.GetSites()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
msg := []string{}
|
||||||
|
|
||||||
|
for _, site := range sites {
|
||||||
|
msg = append(msg, site.Name+" ("+site.Desc+")")
|
||||||
|
}
|
||||||
|
|
||||||
|
u.Logf("Found %d site(s) on controller: %v", len(msg), strings.Join(msg, ", "))
|
||||||
|
|
||||||
|
if poller.StringInSlice("all", c.Sites) {
|
||||||
|
c.Sites = []string{"all"}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
FIRST:
|
||||||
|
for _, s := range c.Sites {
|
||||||
|
for _, site := range sites {
|
||||||
|
if s == site.Name {
|
||||||
|
continue FIRST
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fmt.Errorf("configured site not found on controller: %v", s)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
@ -2,5 +2,5 @@
|
||||||
|
|
||||||
package poller
|
package poller
|
||||||
|
|
||||||
// DefaultConfFile is where to find config is --config is not prvided.
|
// DefaultConfFile is where to find config if --config is not prvided.
|
||||||
const DefaultConfFile = "/usr/local/etc/unifi-poller/up.conf"
|
const DefaultConfFile = "/usr/local/etc/unifi-poller/up.conf"
|
||||||
|
|
|
||||||
|
|
@ -2,5 +2,5 @@
|
||||||
|
|
||||||
package poller
|
package poller
|
||||||
|
|
||||||
// DefaultConfFile is where to find config is --config is not prvided.
|
// DefaultConfFile is where to find config if --config is not prvided.
|
||||||
const DefaultConfFile = "/etc/unifi-poller/up.conf"
|
const DefaultConfFile = "/etc/unifi-poller/up.conf"
|
||||||
|
|
|
||||||
|
|
@ -2,5 +2,5 @@
|
||||||
|
|
||||||
package poller
|
package poller
|
||||||
|
|
||||||
// DefaultConfFile is where to find config is --config is not prvided.
|
// DefaultConfFile is where to find config if --config is not prvided.
|
||||||
const DefaultConfFile = `C:\ProgramData\unifi-poller\up.conf`
|
const DefaultConfFile = `C:\ProgramData\unifi-poller\up.conf`
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@ package poller
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/spf13/pflag"
|
"github.com/spf13/pflag"
|
||||||
|
|
@ -17,23 +16,17 @@ import (
|
||||||
"golift.io/unifi"
|
"golift.io/unifi"
|
||||||
)
|
)
|
||||||
|
|
||||||
// App defaults in case they're missing from the config.
|
|
||||||
const (
|
const (
|
||||||
// AppName is the name of the application.
|
// AppName is the name of the application.
|
||||||
AppName = "unifi-poller"
|
AppName = "unifi-poller"
|
||||||
defaultUnifiUser = "influx"
|
// ENVConfigPrefix is the prefix appended to an env variable tag name.
|
||||||
defaultUnifiURL = "https://127.0.0.1:8443"
|
ENVConfigPrefix = "UP"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ENVConfigPrefix is the prefix appended to an env variable tag
|
|
||||||
// name before retrieving the value from the OS.
|
|
||||||
const ENVConfigPrefix = "UP"
|
|
||||||
|
|
||||||
// UnifiPoller contains the application startup data, and auth info for UniFi & Influx.
|
// UnifiPoller contains the application startup data, and auth info for UniFi & Influx.
|
||||||
type UnifiPoller struct {
|
type UnifiPoller struct {
|
||||||
Flags *Flags
|
Flags *Flags
|
||||||
Config *Config
|
*Config
|
||||||
sync.Mutex // locks the Unifi struct member when re-authing to unifi.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flags represents the CLI args available and their settings.
|
// Flags represents the CLI args available and their settings.
|
||||||
|
|
@ -53,26 +46,9 @@ type Metrics struct {
|
||||||
*unifi.Devices
|
*unifi.Devices
|
||||||
}
|
}
|
||||||
|
|
||||||
// Controller represents the configuration for a UniFi Controller.
|
// Config represents the core library input data.
|
||||||
// Each polled controller may have its own configuration.
|
|
||||||
type Controller struct {
|
|
||||||
VerifySSL bool `json:"verify_ssl" toml:"verify_ssl" xml:"verify_ssl" yaml:"verify_ssl"`
|
|
||||||
SaveIDS bool `json:"save_ids" toml:"save_ids" xml:"save_ids" yaml:"save_ids"`
|
|
||||||
SaveSites bool `json:"save_sites,omitempty" toml:"save_sites,omitempty" xml:"save_sites" yaml:"save_sites"`
|
|
||||||
Name string `json:"name" toml:"name" xml:"name,attr" yaml:"name"`
|
|
||||||
User string `json:"user,omitempty" toml:"user,omitempty" xml:"user" yaml:"user"`
|
|
||||||
Pass string `json:"pass,omitempty" toml:"pass,omitempty" xml:"pass" yaml:"pass"`
|
|
||||||
URL string `json:"url,omitempty" toml:"url,omitempty" xml:"url" yaml:"url"`
|
|
||||||
Sites []string `json:"sites,omitempty" toml:"sites,omitempty" xml:"sites" yaml:"sites"`
|
|
||||||
Unifi *unifi.Unifi `json:"-" toml:"-" xml:"-" yaml:"-"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Config represents the data needed to poll a controller and report to influxdb.
|
|
||||||
// This is all of the data stored in the config file.
|
|
||||||
// Any with explicit defaults have omitempty on json and toml tags.
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Poller `json:"poller" toml:"poller" xml:"poller" yaml:"poller"`
|
Poller `json:"poller" toml:"poller" xml:"poller" yaml:"poller"`
|
||||||
Controllers []Controller `json:"controller,omitempty" toml:"controller,omitempty" xml:"controller" yaml:"controller"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Poller is the global config values.
|
// Poller is the global config values.
|
||||||
|
|
@ -83,31 +59,43 @@ type Poller struct {
|
||||||
|
|
||||||
// ParseConfigs parses the poller config and the config for each registered output plugin.
|
// ParseConfigs parses the poller config and the config for each registered output plugin.
|
||||||
func (u *UnifiPoller) ParseConfigs() error {
|
func (u *UnifiPoller) ParseConfigs() error {
|
||||||
// Parse config file.
|
// Parse core config.
|
||||||
if err := config.ParseFile(u.Config, u.Flags.ConfigFile); err != nil {
|
if err := u.ParseInterface(u.Config); err != nil {
|
||||||
u.Flags.Usage()
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update Config with ENV variable overrides.
|
|
||||||
if _, err := config.ParseENV(u.Config, ENVConfigPrefix); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Parse output plugin configs.
|
||||||
outputSync.Lock()
|
outputSync.Lock()
|
||||||
defer outputSync.Unlock()
|
defer outputSync.Unlock()
|
||||||
|
|
||||||
for _, o := range outputs {
|
for _, o := range outputs {
|
||||||
// Parse config file for each output plugin.
|
if err := u.ParseInterface(o.Config); err != nil {
|
||||||
if err := config.ParseFile(o.Config, u.Flags.ConfigFile); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Update Config for each output with ENV variable overrides.
|
// Parse input plugin configs.
|
||||||
if _, err := config.ParseENV(o.Config, ENVConfigPrefix); err != nil {
|
inputSync.Lock()
|
||||||
|
defer inputSync.Unlock()
|
||||||
|
|
||||||
|
for _, i := range inputs {
|
||||||
|
if err := u.ParseInterface(i.Config); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ParseInterface parses the config file and environment variables into the provided interface.
|
||||||
|
func (u *UnifiPoller) ParseInterface(i interface{}) error {
|
||||||
|
// Parse config file into provided interface.
|
||||||
|
if err := config.ParseFile(i, u.Flags.ConfigFile); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse environment variables into provided interface.
|
||||||
|
_, err := config.ParseENV(i, ENVConfigPrefix)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,16 @@
|
||||||
package poller
|
package poller
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"golift.io/unifi"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// DumpJSONPayload prints raw json from the UniFi Controller.
|
// DumpJSONPayload prints raw json from the UniFi Controller.
|
||||||
// This only works with controller 0 (first one) in the config.
|
// This only works with controller 0 (first one) in the config.
|
||||||
func (u *UnifiPoller) DumpJSONPayload() (err error) {
|
func (u *UnifiPoller) DumpJSONPayload() (err error) {
|
||||||
|
if true {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
/*
|
||||||
u.Config.Quiet = true
|
u.Config.Quiet = true
|
||||||
config := u.Config.Controllers[0]
|
config := u.Config.Controllers[0]
|
||||||
|
|
||||||
|
|
@ -48,8 +48,11 @@ func (u *UnifiPoller) DumpJSONPayload() (err error) {
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("must provide filter: devices, clients, other")
|
return fmt.Errorf("must provide filter: devices, clients, other")
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
func (u *UnifiPoller) dumpSitesJSON(c Controller, path, name string, sites unifi.Sites) error {
|
func (u *UnifiPoller) dumpSitesJSON(c Controller, path, name string, sites unifi.Sites) error {
|
||||||
for _, s := range sites {
|
for _, s := range sites {
|
||||||
apiPath := fmt.Sprintf(path, s.Name)
|
apiPath := fmt.Sprintf(path, s.Name)
|
||||||
|
|
@ -68,3 +71,15 @@ func (u *UnifiPoller) PrintRawAPIJSON(c Controller, apiPath string) error {
|
||||||
fmt.Println(string(body))
|
fmt.Println(string(body))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// StringInSlice returns true if a string is in a slice.
|
||||||
|
func StringInSlice(str string, slice []string) bool {
|
||||||
|
for _, s := range slice {
|
||||||
|
if strings.EqualFold(s, str) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,96 @@
|
||||||
|
package poller
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"golift.io/unifi"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
inputs []*InputPlugin
|
||||||
|
inputSync sync.Mutex
|
||||||
|
)
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
}
|
||||||
|
|
||||||
|
// InputPlugin describes an input plugin's consumable interface.
|
||||||
|
type InputPlugin struct {
|
||||||
|
Config interface{} // Each config is passed into an unmarshaller later.
|
||||||
|
Input
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewInput creates a metric input. This should be called by input plugins
|
||||||
|
// init() functions.
|
||||||
|
func NewInput(i *InputPlugin) {
|
||||||
|
inputSync.Lock()
|
||||||
|
defer inputSync.Unlock()
|
||||||
|
|
||||||
|
if i == nil || i.Input == nil {
|
||||||
|
panic("nil output or method passed to poller.NewOutput")
|
||||||
|
}
|
||||||
|
|
||||||
|
inputs = append(inputs, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
// InitializeInputs runs the passed-in initializer method for each input plugin.
|
||||||
|
func (u *UnifiPoller) InitializeInputs() error {
|
||||||
|
inputSync.Lock()
|
||||||
|
defer inputSync.Unlock()
|
||||||
|
|
||||||
|
for _, input := range inputs {
|
||||||
|
// This must return, or the app locks up here.
|
||||||
|
if err := input.Initialize(u); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Metrics aggregates all the measurements from all configured inputs and returns them.
|
||||||
|
func (u *UnifiPoller) Metrics() (*Metrics, error) {
|
||||||
|
errs := []string{}
|
||||||
|
metrics := &Metrics{}
|
||||||
|
|
||||||
|
for _, input := range inputs {
|
||||||
|
m, err := input.Metrics()
|
||||||
|
if err != nil {
|
||||||
|
errs = append(errs, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
if m == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
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, err
|
||||||
|
}
|
||||||
|
|
@ -3,19 +3,15 @@ package poller
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const callDepth = 2
|
const callDepth = 2
|
||||||
|
|
||||||
// StringInSlice returns true if a string is in a slice.
|
// Logger is passed into input packages so they may write logs.
|
||||||
func StringInSlice(str string, slice []string) bool {
|
type Logger interface {
|
||||||
for _, s := range slice {
|
Logf(m string, v ...interface{})
|
||||||
if strings.EqualFold(s, str) {
|
LogErrorf(m string, v ...interface{})
|
||||||
return true
|
LogDebugf(m string, v ...interface{})
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Logf prints a log entry if quiet is false.
|
// Logf prints a log entry if quiet is false.
|
||||||
|
|
@ -14,9 +14,7 @@ var (
|
||||||
// Output packages must implement this interface.
|
// Output packages must implement this interface.
|
||||||
type Collect interface {
|
type Collect interface {
|
||||||
Metrics() (*Metrics, error)
|
Metrics() (*Metrics, error)
|
||||||
Logf(m string, v ...interface{})
|
Logger
|
||||||
LogErrorf(m string, v ...interface{})
|
|
||||||
LogDebugf(m string, v ...interface{})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Output defines the output data for a metric exporter like influx or prometheus.
|
// Output defines the output data for a metric exporter like influx or prometheus.
|
||||||
|
|
@ -49,6 +47,7 @@ func (u *UnifiPoller) InitializeOutputs() error {
|
||||||
|
|
||||||
for _, o := range outputs {
|
for _, o := range outputs {
|
||||||
count++
|
count++
|
||||||
|
|
||||||
go func(o *Output) {
|
go func(o *Output) {
|
||||||
v <- o.Method(u)
|
v <- o.Method(u)
|
||||||
}(o)
|
}(o)
|
||||||
|
|
|
||||||
|
|
@ -37,25 +37,6 @@ func (u *UnifiPoller) Start() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(u.Config.Controllers) < 1 {
|
|
||||||
u.Config.Controllers = []Controller{{
|
|
||||||
Sites: []string{"all"},
|
|
||||||
User: defaultUnifiUser,
|
|
||||||
Pass: "",
|
|
||||||
URL: defaultUnifiURL,
|
|
||||||
SaveSites: true,
|
|
||||||
}}
|
|
||||||
}
|
|
||||||
|
|
||||||
if u.Flags.DumpJSON != "" {
|
|
||||||
return u.DumpJSONPayload()
|
|
||||||
}
|
|
||||||
|
|
||||||
if u.Config.Debug {
|
|
||||||
log.SetFlags(log.Lshortfile | log.Lmicroseconds | log.Ldate)
|
|
||||||
u.LogDebugf("Debug Logging Enabled")
|
|
||||||
}
|
|
||||||
|
|
||||||
return u.Run()
|
return u.Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -79,20 +60,19 @@ func (f *Flags) 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 u.Flags.DumpJSON != "" {
|
||||||
|
return u.DumpJSONPayload()
|
||||||
|
}
|
||||||
|
|
||||||
|
if u.Config.Debug {
|
||||||
|
log.SetFlags(log.Lshortfile | log.Lmicroseconds | log.Ldate)
|
||||||
|
u.LogDebugf("Debug Logging Enabled")
|
||||||
|
}
|
||||||
|
|
||||||
log.Printf("[INFO] UniFi Poller v%v Starting Up! PID: %d", version.Version, os.Getpid())
|
log.Printf("[INFO] UniFi Poller v%v Starting Up! PID: %d", version.Version, os.Getpid())
|
||||||
|
|
||||||
for i, c := range u.Config.Controllers {
|
if err := u.InitializeInputs(); err != nil {
|
||||||
if c.Name == "" {
|
return err
|
||||||
u.Config.Controllers[i].Name = c.URL
|
|
||||||
}
|
|
||||||
|
|
||||||
switch err := u.GetUnifi(c); err {
|
|
||||||
case nil:
|
|
||||||
u.Logf("Polling UniFi Controller at %s v%s as user %s. Sites: %v",
|
|
||||||
c.URL, c.Unifi.ServerVersion, c.User, c.Sites)
|
|
||||||
default:
|
|
||||||
u.LogErrorf("Controller Auth or Connection failed, but continuing to retry! %s: %v", c.Name, err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return u.InitializeOutputs()
|
return u.InitializeOutputs()
|
||||||
|
|
|
||||||
|
|
@ -1,241 +0,0 @@
|
||||||
package poller
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"golift.io/unifi"
|
|
||||||
)
|
|
||||||
|
|
||||||
// GetUnifi returns a UniFi controller interface.
|
|
||||||
func (u *UnifiPoller) GetUnifi(c Controller) error {
|
|
||||||
var err error
|
|
||||||
|
|
||||||
u.Lock()
|
|
||||||
defer u.Unlock()
|
|
||||||
|
|
||||||
if c.Unifi != nil {
|
|
||||||
c.Unifi.CloseIdleConnections()
|
|
||||||
}
|
|
||||||
// Create an authenticated session to the Unifi Controller.
|
|
||||||
c.Unifi, err = unifi.NewUnifi(&unifi.Config{
|
|
||||||
User: c.User,
|
|
||||||
Pass: c.Pass,
|
|
||||||
URL: c.URL,
|
|
||||||
VerifySSL: c.VerifySSL,
|
|
||||||
ErrorLog: u.LogErrorf, // Log all errors.
|
|
||||||
DebugLog: u.LogDebugf, // Log debug messages.
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
c.Unifi = nil
|
|
||||||
return fmt.Errorf("unifi controller: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
u.LogDebugf("Authenticated with controller successfully, %s", c.URL)
|
|
||||||
|
|
||||||
return u.CheckSites(c)
|
|
||||||
}
|
|
||||||
|
|
||||||
// CheckSites makes sure the list of provided sites exists on the controller.
|
|
||||||
// This does not run in Lambda (run-once) mode.
|
|
||||||
func (u *UnifiPoller) CheckSites(c Controller) error {
|
|
||||||
u.LogDebugf("Checking Controller Sites List")
|
|
||||||
|
|
||||||
sites, err := c.Unifi.GetSites()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
msg := []string{}
|
|
||||||
|
|
||||||
for _, site := range sites {
|
|
||||||
msg = append(msg, site.Name+" ("+site.Desc+")")
|
|
||||||
}
|
|
||||||
|
|
||||||
u.Logf("Found %d site(s) on controller: %v", len(msg), strings.Join(msg, ", "))
|
|
||||||
|
|
||||||
if StringInSlice("all", c.Sites) {
|
|
||||||
c.Sites = []string{"all"}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
FIRST:
|
|
||||||
for _, s := range c.Sites {
|
|
||||||
for _, site := range sites {
|
|
||||||
if s == site.Name {
|
|
||||||
continue FIRST
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return fmt.Errorf("configured site not found on controller: %v", s)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Metrics grabs all the measurements from a UniFi controller and returns them.
|
|
||||||
func (u *UnifiPoller) Metrics() (*Metrics, error) {
|
|
||||||
errs := []string{}
|
|
||||||
metrics := &Metrics{}
|
|
||||||
|
|
||||||
for _, c := range u.Config.Controllers {
|
|
||||||
m, err := u.checkAndPollController(c)
|
|
||||||
if err != nil {
|
|
||||||
errs = append(errs, err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
if m == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
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, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u *UnifiPoller) checkAndPollController(c Controller) (*Metrics, error) {
|
|
||||||
if c.Unifi == nil {
|
|
||||||
u.Logf("Re-authenticating to UniFi Controller: %s", c.URL)
|
|
||||||
|
|
||||||
if err := u.GetUnifi(c); err != nil {
|
|
||||||
u.LogErrorf("re-authenticating to %s: %v", c.URL, err)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m, err := u.collectController(c)
|
|
||||||
if err == nil {
|
|
||||||
return m, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
u.LogErrorf("collecting metrics %v", err)
|
|
||||||
u.Logf("Re-authenticating to UniFi Controller: %s", c.URL)
|
|
||||||
|
|
||||||
if err := u.GetUnifi(c); err != nil {
|
|
||||||
u.LogErrorf("re-authenticating to %s: %v", c.URL, err)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return u.collectController(c)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u *UnifiPoller) collectController(c Controller) (*Metrics, error) {
|
|
||||||
var err error
|
|
||||||
|
|
||||||
m := &Metrics{TS: time.Now()} // At this point, it's the Current Check.
|
|
||||||
|
|
||||||
// Get the sites we care about.
|
|
||||||
if m.Sites, err = u.GetFilteredSites(c); err != nil {
|
|
||||||
return m, fmt.Errorf("unifi.GetSites(%v): %v", c.URL, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.SaveIDS {
|
|
||||||
m.IDSList, err = c.Unifi.GetIDS(m.Sites, time.Now().Add(2*time.Minute), time.Now())
|
|
||||||
if err != nil {
|
|
||||||
return m, fmt.Errorf("unifi.GetIDS(%v): %v", c.URL, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get all the points.
|
|
||||||
if m.Clients, err = c.Unifi.GetClients(m.Sites); err != nil {
|
|
||||||
return m, fmt.Errorf("unifi.GetClients(%v): %v", c.URL, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if m.Devices, err = c.Unifi.GetDevices(m.Sites); err != nil {
|
|
||||||
return m, fmt.Errorf("unifi.GetDevices(%v): %v", c.URL, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return u.augmentMetrics(c, m), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// augmentMetrics is our middleware layer between collecting metrics and writing them.
|
|
||||||
// This is where we can manipuate the returned data or make arbitrary decisions.
|
|
||||||
// This function currently adds parent device names to client metrics.
|
|
||||||
func (u *UnifiPoller) augmentMetrics(c Controller, metrics *Metrics) *Metrics {
|
|
||||||
if metrics == nil || metrics.Devices == nil || metrics.Clients == nil {
|
|
||||||
return metrics
|
|
||||||
}
|
|
||||||
|
|
||||||
devices := make(map[string]string)
|
|
||||||
bssdIDs := make(map[string]string)
|
|
||||||
|
|
||||||
for _, r := range metrics.UAPs {
|
|
||||||
devices[r.Mac] = r.Name
|
|
||||||
for _, v := range r.VapTable {
|
|
||||||
bssdIDs[v.Bssid] = fmt.Sprintf("%s %s %s:", r.Name, v.Radio, v.RadioName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, r := range metrics.USGs {
|
|
||||||
devices[r.Mac] = r.Name
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, r := range metrics.USWs {
|
|
||||||
devices[r.Mac] = r.Name
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, r := range metrics.UDMs {
|
|
||||||
devices[r.Mac] = r.Name
|
|
||||||
}
|
|
||||||
|
|
||||||
// These come blank, so set them here.
|
|
||||||
for i, c := range metrics.Clients {
|
|
||||||
metrics.Clients[i].SwName = devices[c.SwMac]
|
|
||||||
metrics.Clients[i].ApName = devices[c.ApMac]
|
|
||||||
metrics.Clients[i].GwName = devices[c.GwMac]
|
|
||||||
metrics.Clients[i].RadioDescription = bssdIDs[metrics.Clients[i].Bssid] + metrics.Clients[i].RadioProto
|
|
||||||
}
|
|
||||||
|
|
||||||
if !c.SaveSites {
|
|
||||||
metrics.Sites = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return metrics
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetFilteredSites returns a list of sites to fetch data for.
|
|
||||||
// Omits requested but unconfigured sites. Grabs the full list from the
|
|
||||||
// controller and returns the sites provided in the config file.
|
|
||||||
func (u *UnifiPoller) GetFilteredSites(c Controller) (unifi.Sites, error) {
|
|
||||||
var i int
|
|
||||||
|
|
||||||
sites, err := c.Unifi.GetSites()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
} else if len(c.Sites) < 1 || StringInSlice("all", c.Sites) {
|
|
||||||
return sites, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, s := range sites {
|
|
||||||
// Only include valid sites in the request filter.
|
|
||||||
if StringInSlice(s.Name, c.Sites) {
|
|
||||||
sites[i] = s
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return sites[:i], nil
|
|
||||||
}
|
|
||||||
|
|
@ -41,7 +41,8 @@ type uclient struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func descClient(ns string) *uclient {
|
func descClient(ns string) *uclient {
|
||||||
labels := []string{"name", "mac", "site_name", "gw_name", "sw_name", "vlan", "ip", "oui", "network", "sw_port", "ap_name", "wired"}
|
labels := []string{"name", "mac", "site_name", "gw_name", "sw_name", "vlan",
|
||||||
|
"ip", "oui", "network", "sw_port", "ap_name", "wired"}
|
||||||
labelW := append([]string{"radio_name", "radio", "radio_proto", "channel", "essid", "bssid", "radio_desc"}, labels...)
|
labelW := append([]string{"radio_name", "radio", "radio_proto", "channel", "essid", "bssid", "radio_desc"}, labels...)
|
||||||
|
|
||||||
return &uclient{
|
return &uclient{
|
||||||
|
|
@ -64,25 +65,34 @@ func descClient(ns string) *uclient {
|
||||||
TxPower: prometheus.NewDesc(ns+"radio_transmit_power_dbm", "Client Transmit Power", labelW, nil),
|
TxPower: prometheus.NewDesc(ns+"radio_transmit_power_dbm", "Client Transmit Power", labelW, nil),
|
||||||
TxRate: prometheus.NewDesc(ns+"radio_transmit_rate_bps", "Client Transmit Rate", labelW, nil),
|
TxRate: prometheus.NewDesc(ns+"radio_transmit_rate_bps", "Client Transmit Rate", labelW, nil),
|
||||||
WifiTxAttempts: prometheus.NewDesc(ns+"wifi_attempts_transmit_total", "Client Wifi Transmit Attempts", labelW, nil),
|
WifiTxAttempts: prometheus.NewDesc(ns+"wifi_attempts_transmit_total", "Client Wifi Transmit Attempts", labelW, nil),
|
||||||
Uptime: prometheus.NewDesc(ns+"uptime_seconds", "Client Uptime", labelW, nil), // XXX: re-purpose for info tags.
|
Uptime: prometheus.NewDesc(ns+"uptime_seconds", "Client Uptime", labelW, nil),
|
||||||
/* needs more "looking into"
|
/* needs more "looking into"
|
||||||
DpiStatsApp: prometheus.NewDesc(ns+"dpi_stats_app", "Client DPI Stats App", labels, nil),
|
DpiStatsApp: prometheus.NewDesc(ns+"dpi_stats_app",
|
||||||
DpiStatsCat: prometheus.NewDesc(ns+"dpi_stats_cat", "Client DPI Stats Cat", labels, nil),
|
"Client DPI Stats App", labels, nil),
|
||||||
DpiStatsRxBytes: prometheus.NewDesc(ns+"dpi_stats_receive_bytes_total", "Client DPI Stats Receive Bytes", labels, nil),
|
DpiStatsCat: prometheus.NewDesc(ns+"dpi_stats_cat",
|
||||||
DpiStatsRxPackets: prometheus.NewDesc(ns+"dpi_stats_receive_packets_total", "Client DPI Stats Receive Packets", labels, nil),
|
"Client DPI Stats Cat", labels, nil),
|
||||||
DpiStatsTxBytes: prometheus.NewDesc(ns+"dpi_stats_transmit_bytes_total", "Client DPI Stats Transmit Bytes", labels, nil),
|
DpiStatsRxBytes: prometheus.NewDesc(ns+"dpi_stats_receive_bytes_total",
|
||||||
DpiStatsTxPackets: prometheus.NewDesc(ns+"dpi_stats_transmit_packets_total", "Client DPI Stats Transmit Packets", labels, nil),
|
"Client DPI Stats Receive Bytes", labels, nil),
|
||||||
|
DpiStatsRxPackets: prometheus.NewDesc(ns+"dpi_stats_receive_packets_total",
|
||||||
|
"Client DPI Stats Receive Packets", labels, nil),
|
||||||
|
DpiStatsTxBytes: prometheus.NewDesc(ns+"dpi_stats_transmit_bytes_total",
|
||||||
|
"Client DPI Stats Transmit Bytes", labels, nil),
|
||||||
|
DpiStatsTxPackets: prometheus.NewDesc(ns+"dpi_stats_transmit_packets_total",
|
||||||
|
"Client DPI Stats Transmit Packets", labels, nil),
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *promUnifi) exportClient(r report, c *unifi.Client) {
|
func (u *promUnifi) exportClient(r report, c *unifi.Client) {
|
||||||
labels := []string{c.Name, c.Mac, c.SiteName, c.GwName, c.SwName, c.Vlan.Txt, c.IP, c.Oui, c.Network, c.SwPort.Txt, c.ApName, ""}
|
labels := []string{c.Name, c.Mac, c.SiteName, c.GwName, c.SwName, c.Vlan.Txt,
|
||||||
labelW := append([]string{c.RadioName, c.Radio, c.RadioProto, c.Channel.Txt, c.Essid, c.Bssid, c.RadioDescription}, labels...)
|
c.IP, c.Oui, c.Network, c.SwPort.Txt, c.ApName, ""}
|
||||||
|
labelW := append([]string{c.RadioName, c.Radio, c.RadioProto, c.Channel.Txt,
|
||||||
|
c.Essid, c.Bssid, c.RadioDescription}, labels...)
|
||||||
|
|
||||||
if c.IsWired.Val {
|
if c.IsWired.Val {
|
||||||
labels[len(labels)-1] = "true"
|
labels[len(labels)-1] = "true"
|
||||||
labelW[len(labelW)-1] = "true"
|
labelW[len(labelW)-1] = "true"
|
||||||
|
|
||||||
r.send([]*metric{
|
r.send([]*metric{
|
||||||
{u.Client.RxBytes, counter, c.WiredRxBytes, labels},
|
{u.Client.RxBytes, counter, c.WiredRxBytes, labels},
|
||||||
{u.Client.RxBytesR, gauge, c.WiredRxBytesR, labels},
|
{u.Client.RxBytesR, gauge, c.WiredRxBytesR, labels},
|
||||||
|
|
@ -94,6 +104,7 @@ func (u *promUnifi) exportClient(r report, c *unifi.Client) {
|
||||||
} else {
|
} else {
|
||||||
labels[len(labels)-1] = "false"
|
labels[len(labels)-1] = "false"
|
||||||
labelW[len(labelW)-1] = "false"
|
labelW[len(labelW)-1] = "false"
|
||||||
|
|
||||||
r.send([]*metric{
|
r.send([]*metric{
|
||||||
{u.Client.Anomalies, counter, c.Anomalies, labelW},
|
{u.Client.Anomalies, counter, c.Anomalies, labelW},
|
||||||
{u.Client.CCQ, gauge, float64(c.Ccq) / 1000.0, labelW},
|
{u.Client.CCQ, gauge, float64(c.Ccq) / 1000.0, labelW},
|
||||||
|
|
@ -118,6 +129,8 @@ func (u *promUnifi) exportClient(r report, c *unifi.Client) {
|
||||||
}
|
}
|
||||||
|
|
||||||
r.send([]*metric{{u.Client.Uptime, gauge, c.Uptime, labelW}})
|
r.send([]*metric{{u.Client.Uptime, gauge, c.Uptime, labelW}})
|
||||||
|
}
|
||||||
|
|
||||||
/* needs more "looking into"
|
/* needs more "looking into"
|
||||||
{u.Client.DpiStatsApp, gauge, c.DpiStats.App, labels},
|
{u.Client.DpiStatsApp, gauge, c.DpiStats.App, labels},
|
||||||
{u.Client.DpiStatsCat, gauge, c.DpiStats.Cat, labels},
|
{u.Client.DpiStatsCat, gauge, c.DpiStats.Cat, labels},
|
||||||
|
|
@ -126,4 +139,3 @@ func (u *promUnifi) exportClient(r report, c *unifi.Client) {
|
||||||
{u.Client.DpiStatsTxBytes, counter, c.DpiStats.TxBytes, labels},
|
{u.Client.DpiStatsTxBytes, counter, c.DpiStats.TxBytes, labels},
|
||||||
{u.Client.DpiStatsTxPackets, counter, c.DpiStats.TxPackets, labels},
|
{u.Client.DpiStatsTxPackets, counter, c.DpiStats.TxPackets, labels},
|
||||||
*/
|
*/
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -79,6 +79,7 @@ type Report struct {
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
u := &promUnifi{Prometheus: &Prometheus{}}
|
u := &promUnifi{Prometheus: &Prometheus{}}
|
||||||
|
|
||||||
poller.NewOutput(&poller.Output{
|
poller.NewOutput(&poller.Output{
|
||||||
Name: "prometheus",
|
Name: "prometheus",
|
||||||
Config: u.Prometheus,
|
Config: u.Prometheus,
|
||||||
|
|
@ -93,33 +94,27 @@ func (u *promUnifi) Run(c poller.Collect) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u.Config.Namespace = strings.Trim(strings.Replace(u.Config.Namespace, "-", "_", -1), "_")
|
||||||
if u.Config.Namespace == "" {
|
if u.Config.Namespace == "" {
|
||||||
u.Config.Namespace = strings.Replace(poller.AppName, "-", "", -1)
|
u.Config.Namespace = strings.Replace(poller.AppName, "-", "", -1)
|
||||||
}
|
}
|
||||||
|
|
||||||
u.Config.Namespace = strings.Replace(u.Config.Namespace, "-", "_", -1)
|
|
||||||
|
|
||||||
if u.Config.HTTPListen == "" {
|
if u.Config.HTTPListen == "" {
|
||||||
u.Config.HTTPListen = defaultHTTPListen
|
u.Config.HTTPListen = defaultHTTPListen
|
||||||
}
|
}
|
||||||
|
|
||||||
prometheus.MustRegister(version.NewCollector(u.Config.Namespace))
|
prometheus.MustRegister(version.NewCollector(u.Config.Namespace))
|
||||||
|
|
||||||
if u.Config.Namespace = strings.Trim(u.Config.Namespace, "_") + "_"; u.Config.Namespace == "_" {
|
|
||||||
u.Config.Namespace = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
prometheus.MustRegister(&promUnifi{
|
prometheus.MustRegister(&promUnifi{
|
||||||
Collector: c,
|
Collector: c,
|
||||||
Client: descClient(u.Config.Namespace + "client_"),
|
Client: descClient(u.Config.Namespace + "_client_"),
|
||||||
Device: descDevice(u.Config.Namespace + "device_"), // stats for all device types.
|
Device: descDevice(u.Config.Namespace + "_device_"), // stats for all device types.
|
||||||
UAP: descUAP(u.Config.Namespace + "device_"),
|
UAP: descUAP(u.Config.Namespace + "_device_"),
|
||||||
USG: descUSG(u.Config.Namespace + "device_"),
|
USG: descUSG(u.Config.Namespace + "_device_"),
|
||||||
USW: descUSW(u.Config.Namespace + "device_"),
|
USW: descUSW(u.Config.Namespace + "_device_"),
|
||||||
Site: descSite(u.Config.Namespace + "site_"),
|
Site: descSite(u.Config.Namespace + "_site_"),
|
||||||
})
|
})
|
||||||
|
c.Logf("Exporting Measurements for Prometheus at https://%s/metrics, namespace: %s",
|
||||||
c.Logf("Exporting Measurements for Prometheus at https://%s/metrics, namespace: %s", u.Config.HTTPListen, u.Config.Namespace)
|
u.Config.HTTPListen, u.Config.Namespace)
|
||||||
|
|
||||||
return http.ListenAndServe(u.Config.HTTPListen, nil)
|
return http.ListenAndServe(u.Config.HTTPListen, nil)
|
||||||
}
|
}
|
||||||
|
|
@ -152,6 +147,7 @@ func (u *promUnifi) Collect(ch chan<- prometheus.Metric) {
|
||||||
r.error(ch, prometheus.NewInvalidDesc(fmt.Errorf("metric fetch failed")), err)
|
r.error(ch, prometheus.NewInvalidDesc(fmt.Errorf("metric fetch failed")), err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
r.Fetch = time.Since(r.Start)
|
r.Fetch = time.Since(r.Start)
|
||||||
|
|
||||||
if r.Metrics.Devices == nil {
|
if r.Metrics.Devices == nil {
|
||||||
|
|
@ -173,6 +169,7 @@ func (u *promUnifi) exportMetrics(r report, ch chan<- prometheus.Metric, ourChan
|
||||||
for newMetrics := range ourChan {
|
for newMetrics := range ourChan {
|
||||||
for _, m := range newMetrics {
|
for _, m := range newMetrics {
|
||||||
descs[m.Desc] = true
|
descs[m.Desc] = true
|
||||||
|
|
||||||
switch v := m.Value.(type) {
|
switch v := m.Value.(type) {
|
||||||
case unifi.FlexInt:
|
case unifi.FlexInt:
|
||||||
ch <- r.export(m, v.Val)
|
ch <- r.export(m, v.Val)
|
||||||
|
|
@ -195,48 +192,55 @@ func (u *promUnifi) loopExports(r report) {
|
||||||
m := r.metrics()
|
m := r.metrics()
|
||||||
|
|
||||||
r.add()
|
r.add()
|
||||||
|
r.add()
|
||||||
|
r.add()
|
||||||
|
r.add()
|
||||||
|
r.add()
|
||||||
|
r.add()
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
defer r.done()
|
defer r.done()
|
||||||
|
|
||||||
for _, s := range m.Sites {
|
for _, s := range m.Sites {
|
||||||
u.exportSite(r, s)
|
u.exportSite(r, s)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
r.add()
|
|
||||||
go func() {
|
go func() {
|
||||||
defer r.done()
|
defer r.done()
|
||||||
|
|
||||||
for _, d := range m.UAPs {
|
for _, d := range m.UAPs {
|
||||||
u.exportUAP(r, d)
|
u.exportUAP(r, d)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
r.add()
|
|
||||||
go func() {
|
go func() {
|
||||||
defer r.done()
|
defer r.done()
|
||||||
|
|
||||||
for _, d := range m.UDMs {
|
for _, d := range m.UDMs {
|
||||||
u.exportUDM(r, d)
|
u.exportUDM(r, d)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
r.add()
|
|
||||||
go func() {
|
go func() {
|
||||||
defer r.done()
|
defer r.done()
|
||||||
|
|
||||||
for _, d := range m.USGs {
|
for _, d := range m.USGs {
|
||||||
u.exportUSG(r, d)
|
u.exportUSG(r, d)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
r.add()
|
|
||||||
go func() {
|
go func() {
|
||||||
defer r.done()
|
defer r.done()
|
||||||
|
|
||||||
for _, d := range m.USWs {
|
for _, d := range m.USWs {
|
||||||
u.exportUSW(r, d)
|
u.exportUSW(r, d)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
r.add()
|
|
||||||
go func() {
|
go func() {
|
||||||
defer r.done()
|
defer r.done()
|
||||||
|
|
||||||
for _, c := range m.Clients {
|
for _, c := range m.Clients {
|
||||||
u.exportClient(r, c)
|
u.exportClient(r, c)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,32 +35,34 @@ type site struct {
|
||||||
|
|
||||||
func descSite(ns string) *site {
|
func descSite(ns string) *site {
|
||||||
labels := []string{"subsystem", "status", "site_name"}
|
labels := []string{"subsystem", "status", "site_name"}
|
||||||
|
nd := prometheus.NewDesc
|
||||||
|
|
||||||
return &site{
|
return &site{
|
||||||
NumUser: prometheus.NewDesc(ns+"users", "Number of Users", labels, nil),
|
NumUser: nd(ns+"users", "Number of Users", labels, nil),
|
||||||
NumGuest: prometheus.NewDesc(ns+"guests", "Number of Guests", labels, nil),
|
NumGuest: nd(ns+"guests", "Number of Guests", labels, nil),
|
||||||
NumIot: prometheus.NewDesc(ns+"iots", "Number of IoT Devices", labels, nil),
|
NumIot: nd(ns+"iots", "Number of IoT Devices", labels, nil),
|
||||||
TxBytesR: prometheus.NewDesc(ns+"transmit_rate_bytes", "Bytes Transmit Rate", labels, nil),
|
TxBytesR: nd(ns+"transmit_rate_bytes", "Bytes Transmit Rate", labels, nil),
|
||||||
RxBytesR: prometheus.NewDesc(ns+"receive_rate_bytes", "Bytes Receive Rate", labels, nil),
|
RxBytesR: nd(ns+"receive_rate_bytes", "Bytes Receive Rate", labels, nil),
|
||||||
NumAp: prometheus.NewDesc(ns+"aps", "Access Point Count", labels, nil),
|
NumAp: nd(ns+"aps", "Access Point Count", labels, nil),
|
||||||
NumAdopted: prometheus.NewDesc(ns+"adopted", "Adoption Count", labels, nil),
|
NumAdopted: nd(ns+"adopted", "Adoption Count", labels, nil),
|
||||||
NumDisabled: prometheus.NewDesc(ns+"disabled", "Disabled Count", labels, nil),
|
NumDisabled: nd(ns+"disabled", "Disabled Count", labels, nil),
|
||||||
NumDisconnected: prometheus.NewDesc(ns+"disconnected", "Disconnected Count", labels, nil),
|
NumDisconnected: nd(ns+"disconnected", "Disconnected Count", labels, nil),
|
||||||
NumPending: prometheus.NewDesc(ns+"pending", "Pending Count", labels, nil),
|
NumPending: nd(ns+"pending", "Pending Count", labels, nil),
|
||||||
NumGw: prometheus.NewDesc(ns+"gateways", "Gateway Count", labels, nil),
|
NumGw: nd(ns+"gateways", "Gateway Count", labels, nil),
|
||||||
NumSw: prometheus.NewDesc(ns+"switches", "Switch Count", labels, nil),
|
NumSw: nd(ns+"switches", "Switch Count", labels, nil),
|
||||||
NumSta: prometheus.NewDesc(ns+"stations", "Station Count", labels, nil),
|
NumSta: nd(ns+"stations", "Station Count", labels, nil),
|
||||||
Latency: prometheus.NewDesc(ns+"latency_seconds", "Latency", labels, nil),
|
Latency: nd(ns+"latency_seconds", "Latency", labels, nil),
|
||||||
Uptime: prometheus.NewDesc(ns+"uptime_seconds", "Uptime", labels, nil),
|
Uptime: nd(ns+"uptime_seconds", "Uptime", labels, nil),
|
||||||
Drops: prometheus.NewDesc(ns+"intenet_drops_total", "Internet (WAN) Disconnections", labels, nil),
|
Drops: nd(ns+"intenet_drops_total", "Internet (WAN) Disconnections", labels, nil),
|
||||||
XputUp: prometheus.NewDesc(ns+"xput_up_rate", "Speedtest Upload", labels, nil),
|
XputUp: nd(ns+"xput_up_rate", "Speedtest Upload", labels, nil),
|
||||||
XputDown: prometheus.NewDesc(ns+"xput_down_rate", "Speedtest Download", labels, nil),
|
XputDown: nd(ns+"xput_down_rate", "Speedtest Download", labels, nil),
|
||||||
SpeedtestPing: prometheus.NewDesc(ns+"speedtest_ping", "Speedtest Ping", labels, nil),
|
SpeedtestPing: nd(ns+"speedtest_ping", "Speedtest Ping", labels, nil),
|
||||||
RemoteUserNumActive: prometheus.NewDesc(ns+"remote_user_active", "Remote Users Active", labels, nil),
|
RemoteUserNumActive: nd(ns+"remote_user_active", "Remote Users Active", labels, nil),
|
||||||
RemoteUserNumInactive: prometheus.NewDesc(ns+"remote_user_inactive", "Remote Users Inactive", labels, nil),
|
RemoteUserNumInactive: nd(ns+"remote_user_inactive", "Remote Users Inactive", labels, nil),
|
||||||
RemoteUserRxBytes: prometheus.NewDesc(ns+"remote_user_receive_bytes_total", "Remote Users Receive Bytes", labels, nil),
|
RemoteUserRxBytes: nd(ns+"remote_user_receive_bytes_total", "Remote Users Receive Bytes", labels, nil),
|
||||||
RemoteUserTxBytes: prometheus.NewDesc(ns+"remote_user_transmit_bytes_total", "Remote Users Transmit Bytes", labels, nil),
|
RemoteUserTxBytes: nd(ns+"remote_user_transmit_bytes_total", "Remote Users Transmit Bytes", labels, nil),
|
||||||
RemoteUserRxPackets: prometheus.NewDesc(ns+"remote_user_receive_packets_total", "Remote Users Receive Packets", labels, nil),
|
RemoteUserRxPackets: nd(ns+"remote_user_receive_packets_total", "Remote Users Receive Packets", labels, nil),
|
||||||
RemoteUserTxPackets: prometheus.NewDesc(ns+"remote_user_transmit_packets_total", "Remote Users Transmit Packets", labels, nil),
|
RemoteUserTxPackets: nd(ns+"remote_user_transmit_packets_total", "Remote Users Transmit Packets", labels, nil),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -78,7 +80,6 @@ func (u *promUnifi) exportSite(r report, s *unifi.Site) {
|
||||||
{u.Site.SpeedtestPing, gauge, h.SpeedtestPing, labels},
|
{u.Site.SpeedtestPing, gauge, h.SpeedtestPing, labels},
|
||||||
{u.Site.Drops, counter, h.Drops, labels},
|
{u.Site.Drops, counter, h.Drops, labels},
|
||||||
})
|
})
|
||||||
|
|
||||||
case "wlan":
|
case "wlan":
|
||||||
r.send([]*metric{
|
r.send([]*metric{
|
||||||
{u.Site.TxBytesR, gauge, h.TxBytesR, labels},
|
{u.Site.TxBytesR, gauge, h.TxBytesR, labels},
|
||||||
|
|
@ -92,7 +93,6 @@ func (u *promUnifi) exportSite(r report, s *unifi.Site) {
|
||||||
{u.Site.NumAp, gauge, h.NumAp, labels},
|
{u.Site.NumAp, gauge, h.NumAp, labels},
|
||||||
{u.Site.NumDisabled, gauge, h.NumDisabled, labels},
|
{u.Site.NumDisabled, gauge, h.NumDisabled, labels},
|
||||||
})
|
})
|
||||||
|
|
||||||
case "wan":
|
case "wan":
|
||||||
r.send([]*metric{
|
r.send([]*metric{
|
||||||
{u.Site.TxBytesR, gauge, h.TxBytesR, labels},
|
{u.Site.TxBytesR, gauge, h.TxBytesR, labels},
|
||||||
|
|
@ -103,7 +103,6 @@ func (u *promUnifi) exportSite(r report, s *unifi.Site) {
|
||||||
{u.Site.NumGw, gauge, h.NumGw, labels},
|
{u.Site.NumGw, gauge, h.NumGw, labels},
|
||||||
{u.Site.NumSta, gauge, h.NumSta, labels},
|
{u.Site.NumSta, gauge, h.NumSta, labels},
|
||||||
})
|
})
|
||||||
|
|
||||||
case "lan":
|
case "lan":
|
||||||
r.send([]*metric{
|
r.send([]*metric{
|
||||||
{u.Site.TxBytesR, gauge, h.TxBytesR, labels},
|
{u.Site.TxBytesR, gauge, h.TxBytesR, labels},
|
||||||
|
|
@ -116,7 +115,6 @@ func (u *promUnifi) exportSite(r report, s *unifi.Site) {
|
||||||
{u.Site.NumIot, gauge, h.NumIot, labels},
|
{u.Site.NumIot, gauge, h.NumIot, labels},
|
||||||
{u.Site.NumSw, gauge, h.NumSw, labels},
|
{u.Site.NumSw, gauge, h.NumSw, labels},
|
||||||
})
|
})
|
||||||
|
|
||||||
case "vpn":
|
case "vpn":
|
||||||
r.send([]*metric{
|
r.send([]*metric{
|
||||||
{u.Site.RemoteUserNumActive, gauge, h.RemoteUserNumActive, labels},
|
{u.Site.RemoteUserNumActive, gauge, h.RemoteUserNumActive, labels},
|
||||||
|
|
|
||||||
|
|
@ -83,79 +83,80 @@ func descUAP(ns string) *uap {
|
||||||
labelA := []string{"stat", "site_name", "name"} // stat + labels[1:]
|
labelA := []string{"stat", "site_name", "name"} // stat + labels[1:]
|
||||||
labelV := []string{"vap_name", "bssid", "radio", "radio_name", "essid", "usage", "site_name", "name"}
|
labelV := []string{"vap_name", "bssid", "radio", "radio_name", "essid", "usage", "site_name", "name"}
|
||||||
labelR := []string{"radio_name", "radio", "site_name", "name"}
|
labelR := []string{"radio_name", "radio", "site_name", "name"}
|
||||||
|
nd := prometheus.NewDesc
|
||||||
|
|
||||||
return &uap{
|
return &uap{
|
||||||
// 3x each - stat table: total, guest, user
|
// 3x each - stat table: total, guest, user
|
||||||
ApWifiTxDropped: prometheus.NewDesc(ns+"stat_wifi_transmt_dropped_total", "Wifi Transmissions Dropped", labelA, nil),
|
ApWifiTxDropped: nd(ns+"stat_wifi_transmt_dropped_total", "Wifi Transmissions Dropped", labelA, nil),
|
||||||
ApRxErrors: prometheus.NewDesc(ns+"stat_receive_errors_total", "Receive Errors", labelA, nil),
|
ApRxErrors: nd(ns+"stat_receive_errors_total", "Receive Errors", labelA, nil),
|
||||||
ApRxDropped: prometheus.NewDesc(ns+"stat_receive_dropped_total", "Receive Dropped", labelA, nil),
|
ApRxDropped: nd(ns+"stat_receive_dropped_total", "Receive Dropped", labelA, nil),
|
||||||
ApRxFrags: prometheus.NewDesc(ns+"stat_receive_frags_total", "Received Frags", labelA, nil),
|
ApRxFrags: nd(ns+"stat_receive_frags_total", "Received Frags", labelA, nil),
|
||||||
ApRxCrypts: prometheus.NewDesc(ns+"stat_receive_crypts_total", "Receive Crypts", labelA, nil),
|
ApRxCrypts: nd(ns+"stat_receive_crypts_total", "Receive Crypts", labelA, nil),
|
||||||
ApTxPackets: prometheus.NewDesc(ns+"stat_transmit_packets_total", "Transmit Packets", labelA, nil),
|
ApTxPackets: nd(ns+"stat_transmit_packets_total", "Transmit Packets", labelA, nil),
|
||||||
ApTxBytes: prometheus.NewDesc(ns+"stat_transmit_bytes_total", "Transmit Bytes", labelA, nil),
|
ApTxBytes: nd(ns+"stat_transmit_bytes_total", "Transmit Bytes", labelA, nil),
|
||||||
ApTxErrors: prometheus.NewDesc(ns+"stat_transmit_errors_total", "Transmit Errors", labelA, nil),
|
ApTxErrors: nd(ns+"stat_transmit_errors_total", "Transmit Errors", labelA, nil),
|
||||||
ApTxDropped: prometheus.NewDesc(ns+"stat_transmit_dropped_total", "Transmit Dropped", labelA, nil),
|
ApTxDropped: nd(ns+"stat_transmit_dropped_total", "Transmit Dropped", labelA, nil),
|
||||||
ApTxRetries: prometheus.NewDesc(ns+"stat_retries_tx_total", "Transmit Retries", labelA, nil),
|
ApTxRetries: nd(ns+"stat_retries_tx_total", "Transmit Retries", labelA, nil),
|
||||||
ApRxPackets: prometheus.NewDesc(ns+"stat_receive_packets_total", "Receive Packets", labelA, nil),
|
ApRxPackets: nd(ns+"stat_receive_packets_total", "Receive Packets", labelA, nil),
|
||||||
ApRxBytes: prometheus.NewDesc(ns+"stat_receive_bytes_total", "Receive Bytes", labelA, nil),
|
ApRxBytes: nd(ns+"stat_receive_bytes_total", "Receive Bytes", labelA, nil),
|
||||||
WifiTxAttempts: prometheus.NewDesc(ns+"stat_wifi_transmit_attempts_total", "Wifi Transmission Attempts", labelA, nil),
|
WifiTxAttempts: nd(ns+"stat_wifi_transmit_attempts_total", "Wifi Transmission Attempts", labelA, nil),
|
||||||
MacFilterRejections: prometheus.NewDesc(ns+"stat_mac_filter_rejects_total", "MAC Filter Rejections", labelA, nil),
|
MacFilterRejections: nd(ns+"stat_mac_filter_rejects_total", "MAC Filter Rejections", labelA, nil),
|
||||||
// N each - 1 per Virtual AP (VAP)
|
// N each - 1 per Virtual AP (VAP)
|
||||||
VAPCcq: prometheus.NewDesc(ns+"vap_ccq_ratio", "VAP Client Connection Quality", labelV, nil),
|
VAPCcq: nd(ns+"vap_ccq_ratio", "VAP Client Connection Quality", labelV, nil),
|
||||||
VAPMacFilterRejections: prometheus.NewDesc(ns+"vap_mac_filter_rejects_total", "VAP MAC Filter Rejections", labelV, nil),
|
VAPMacFilterRejections: nd(ns+"vap_mac_filter_rejects_total", "VAP MAC Filter Rejections", labelV, nil),
|
||||||
VAPNumSatisfactionSta: prometheus.NewDesc(ns+"vap_satisfaction_stations", "VAP Number Satisifaction Stations", labelV, nil),
|
VAPNumSatisfactionSta: nd(ns+"vap_satisfaction_stations", "VAP Number Satisifaction Stations", labelV, nil),
|
||||||
VAPAvgClientSignal: prometheus.NewDesc(ns+"vap_average_client_signal", "VAP Average Client Signal", labelV, nil),
|
VAPAvgClientSignal: nd(ns+"vap_average_client_signal", "VAP Average Client Signal", labelV, nil),
|
||||||
VAPSatisfaction: prometheus.NewDesc(ns+"vap_satisfaction_ratio", "VAP Satisfaction", labelV, nil),
|
VAPSatisfaction: nd(ns+"vap_satisfaction_ratio", "VAP Satisfaction", labelV, nil),
|
||||||
VAPSatisfactionNow: prometheus.NewDesc(ns+"vap_satisfaction_now_ratio", "VAP Satisfaction Now", labelV, nil),
|
VAPSatisfactionNow: nd(ns+"vap_satisfaction_now_ratio", "VAP Satisfaction Now", labelV, nil),
|
||||||
VAPDNSAvgLatency: prometheus.NewDesc(ns+"vap_dns_latency_average_seconds", "VAP DNS Latency Average", labelV, nil),
|
VAPDNSAvgLatency: nd(ns+"vap_dns_latency_average_seconds", "VAP DNS Latency Average", labelV, nil),
|
||||||
VAPRxBytes: prometheus.NewDesc(ns+"vap_receive_bytes_total", "VAP Bytes Received", labelV, nil),
|
VAPRxBytes: nd(ns+"vap_receive_bytes_total", "VAP Bytes Received", labelV, nil),
|
||||||
VAPRxCrypts: prometheus.NewDesc(ns+"vap_receive_crypts_total", "VAP Crypts Received", labelV, nil),
|
VAPRxCrypts: nd(ns+"vap_receive_crypts_total", "VAP Crypts Received", labelV, nil),
|
||||||
VAPRxDropped: prometheus.NewDesc(ns+"vap_receive_dropped_total", "VAP Dropped Received", labelV, nil),
|
VAPRxDropped: nd(ns+"vap_receive_dropped_total", "VAP Dropped Received", labelV, nil),
|
||||||
VAPRxErrors: prometheus.NewDesc(ns+"vap_receive_errors_total", "VAP Errors Received", labelV, nil),
|
VAPRxErrors: nd(ns+"vap_receive_errors_total", "VAP Errors Received", labelV, nil),
|
||||||
VAPRxFrags: prometheus.NewDesc(ns+"vap_receive_frags_total", "VAP Frags Received", labelV, nil),
|
VAPRxFrags: nd(ns+"vap_receive_frags_total", "VAP Frags Received", labelV, nil),
|
||||||
VAPRxNwids: prometheus.NewDesc(ns+"vap_receive_nwids_total", "VAP Nwids Received", labelV, nil),
|
VAPRxNwids: nd(ns+"vap_receive_nwids_total", "VAP Nwids Received", labelV, nil),
|
||||||
VAPRxPackets: prometheus.NewDesc(ns+"vap_receive_packets_total", "VAP Packets Received", labelV, nil),
|
VAPRxPackets: nd(ns+"vap_receive_packets_total", "VAP Packets Received", labelV, nil),
|
||||||
VAPTxBytes: prometheus.NewDesc(ns+"vap_transmit_bytes_total", "VAP Bytes Transmitted", labelV, nil),
|
VAPTxBytes: nd(ns+"vap_transmit_bytes_total", "VAP Bytes Transmitted", labelV, nil),
|
||||||
VAPTxDropped: prometheus.NewDesc(ns+"vap_transmit_dropped_total", "VAP Dropped Transmitted", labelV, nil),
|
VAPTxDropped: nd(ns+"vap_transmit_dropped_total", "VAP Dropped Transmitted", labelV, nil),
|
||||||
VAPTxErrors: prometheus.NewDesc(ns+"vap_transmit_errors_total", "VAP Errors Transmitted", labelV, nil),
|
VAPTxErrors: nd(ns+"vap_transmit_errors_total", "VAP Errors Transmitted", labelV, nil),
|
||||||
VAPTxPackets: prometheus.NewDesc(ns+"vap_transmit_packets_total", "VAP Packets Transmitted", labelV, nil),
|
VAPTxPackets: nd(ns+"vap_transmit_packets_total", "VAP Packets Transmitted", labelV, nil),
|
||||||
VAPTxPower: prometheus.NewDesc(ns+"vap_transmit_power", "VAP Transmit Power", labelV, nil),
|
VAPTxPower: nd(ns+"vap_transmit_power", "VAP Transmit Power", labelV, nil),
|
||||||
VAPTxRetries: prometheus.NewDesc(ns+"vap_transmit_retries_total", "VAP Retries Transmitted", labelV, nil),
|
VAPTxRetries: nd(ns+"vap_transmit_retries_total", "VAP Retries Transmitted", labelV, nil),
|
||||||
VAPTxCombinedRetries: prometheus.NewDesc(ns+"vap_transmit_retries_combined_total", "VAP Retries Combined Transmitted", labelV, nil),
|
VAPTxCombinedRetries: nd(ns+"vap_transmit_retries_combined_total", "VAP Retries Combined Tx", labelV, nil),
|
||||||
VAPTxDataMpduBytes: prometheus.NewDesc(ns+"vap_data_mpdu_transmit_bytes_total", "VAP Data MPDU Bytes Transmitted", labelV, nil),
|
VAPTxDataMpduBytes: nd(ns+"vap_data_mpdu_transmit_bytes_total", "VAP Data MPDU Bytes Tx", labelV, nil),
|
||||||
VAPTxRtsRetries: prometheus.NewDesc(ns+"vap_transmit_rts_retries_total", "VAP RTS Retries Transmitted", labelV, nil),
|
VAPTxRtsRetries: nd(ns+"vap_transmit_rts_retries_total", "VAP RTS Retries Transmitted", labelV, nil),
|
||||||
VAPTxSuccess: prometheus.NewDesc(ns+"vap_transmit_success_total", "VAP Success Transmits", labelV, nil),
|
VAPTxSuccess: nd(ns+"vap_transmit_success_total", "VAP Success Transmits", labelV, nil),
|
||||||
VAPTxTotal: prometheus.NewDesc(ns+"vap_transmit_total", "VAP Transmit Total", labelV, nil),
|
VAPTxTotal: nd(ns+"vap_transmit_total", "VAP Transmit Total", labelV, nil),
|
||||||
VAPTxGoodbytes: prometheus.NewDesc(ns+"vap_transmit_goodbyes", "VAP Goodbyes Transmitted", labelV, nil),
|
VAPTxGoodbytes: nd(ns+"vap_transmit_goodbyes", "VAP Goodbyes Transmitted", labelV, nil),
|
||||||
VAPTxLatAvg: prometheus.NewDesc(ns+"vap_transmit_latency_average_seconds", "VAP Latency Average Transmit", labelV, nil),
|
VAPTxLatAvg: nd(ns+"vap_transmit_latency_average_seconds", "VAP Latency Average Tx", labelV, nil),
|
||||||
VAPTxLatMax: prometheus.NewDesc(ns+"vap_transmit_latency_maximum_seconds", "VAP Latency Maximum Transmit", labelV, nil),
|
VAPTxLatMax: nd(ns+"vap_transmit_latency_maximum_seconds", "VAP Latency Maximum Tx", labelV, nil),
|
||||||
VAPTxLatMin: prometheus.NewDesc(ns+"vap_transmit_latency_minimum_seconds", "VAP Latency Minimum Transmit", labelV, nil),
|
VAPTxLatMin: nd(ns+"vap_transmit_latency_minimum_seconds", "VAP Latency Minimum Tx", labelV, nil),
|
||||||
VAPRxGoodbytes: prometheus.NewDesc(ns+"vap_receive_goodbyes", "VAP Goodbyes Received", labelV, nil),
|
VAPRxGoodbytes: nd(ns+"vap_receive_goodbyes", "VAP Goodbyes Received", labelV, nil),
|
||||||
VAPRxLatAvg: prometheus.NewDesc(ns+"vap_receive_latency_average_seconds", "VAP Latency Average Receive", labelV, nil),
|
VAPRxLatAvg: nd(ns+"vap_receive_latency_average_seconds", "VAP Latency Average Rx", labelV, nil),
|
||||||
VAPRxLatMax: prometheus.NewDesc(ns+"vap_receive_latency_maximum_seconds", "VAP Latency Maximum Receive", labelV, nil),
|
VAPRxLatMax: nd(ns+"vap_receive_latency_maximum_seconds", "VAP Latency Maximum Rx", labelV, nil),
|
||||||
VAPRxLatMin: prometheus.NewDesc(ns+"vap_receive_latency_minimum_seconds", "VAP Latency Minimum Receive", labelV, nil),
|
VAPRxLatMin: nd(ns+"vap_receive_latency_minimum_seconds", "VAP Latency Minimum Rx", labelV, nil),
|
||||||
VAPWifiTxLatencyMovAvg: prometheus.NewDesc(ns+"vap_transmit_latency_moving_avg_seconds", "VAP Latency Moving Average Tramsit", labelV, nil),
|
VAPWifiTxLatencyMovAvg: nd(ns+"vap_transmit_latency_moving_avg_seconds", "VAP Latency Moving Avg Tx", labelV, nil),
|
||||||
VAPWifiTxLatencyMovMax: prometheus.NewDesc(ns+"vap_transmit_latency_moving_max_seconds", "VAP Latency Moving Maximum Tramsit", labelV, nil),
|
VAPWifiTxLatencyMovMax: nd(ns+"vap_transmit_latency_moving_max_seconds", "VAP Latency Moving Min Tx", labelV, nil),
|
||||||
VAPWifiTxLatencyMovMin: prometheus.NewDesc(ns+"vap_transmit_latency_moving_min_seconds", "VAP Latency Moving Minimum Tramsit", labelV, nil),
|
VAPWifiTxLatencyMovMin: nd(ns+"vap_transmit_latency_moving_min_seconds", "VAP Latency Moving Max Tx", labelV, nil),
|
||||||
VAPWifiTxLatencyMovTotal: prometheus.NewDesc(ns+"vap_transmit_latency_moving_total", "VAP Latency Moving Total Tramsit", labelV, nil),
|
VAPWifiTxLatencyMovTotal: nd(ns+"vap_transmit_latency_moving_total", "VAP Latency Moving Total Tramsit", labelV, nil),
|
||||||
VAPWifiTxLatencyMovCount: prometheus.NewDesc(ns+"vap_transmit_latency_moving_count", "VAP Latency Moving Count Tramsit", labelV, nil),
|
VAPWifiTxLatencyMovCount: nd(ns+"vap_transmit_latency_moving_count", "VAP Latency Moving Count Tramsit", labelV, nil),
|
||||||
// N each - 1 per Radio. 1-4 radios per AP usually
|
// N each - 1 per Radio. 1-4 radios per AP usually
|
||||||
RadioCurrentAntennaGain: prometheus.NewDesc(ns+"radio_current_antenna_gain", "Radio Current Antenna Gain", labelR, nil),
|
RadioCurrentAntennaGain: nd(ns+"radio_current_antenna_gain", "Radio Current Antenna Gain", labelR, nil),
|
||||||
RadioHt: prometheus.NewDesc(ns+"radio_ht", "Radio HT", labelR, nil),
|
RadioHt: nd(ns+"radio_ht", "Radio HT", labelR, nil),
|
||||||
RadioMaxTxpower: prometheus.NewDesc(ns+"radio_max_transmit_power", "Radio Maximum Transmit Power", labelR, nil),
|
RadioMaxTxpower: nd(ns+"radio_max_transmit_power", "Radio Maximum Transmit Power", labelR, nil),
|
||||||
RadioMinTxpower: prometheus.NewDesc(ns+"radio_min_transmit_power", "Radio Minimum Transmit Power", labelR, nil),
|
RadioMinTxpower: nd(ns+"radio_min_transmit_power", "Radio Minimum Transmit Power", labelR, nil),
|
||||||
RadioNss: prometheus.NewDesc(ns+"radio_nss", "Radio Nss", labelR, nil),
|
RadioNss: nd(ns+"radio_nss", "Radio Nss", labelR, nil),
|
||||||
RadioRadioCaps: prometheus.NewDesc(ns+"radio_caps", "Radio Capabilities", labelR, nil),
|
RadioRadioCaps: nd(ns+"radio_caps", "Radio Capabilities", labelR, nil),
|
||||||
RadioTxPower: prometheus.NewDesc(ns+"radio_transmit_power", "Radio Transmit Power", labelR, nil),
|
RadioTxPower: nd(ns+"radio_transmit_power", "Radio Transmit Power", labelR, nil),
|
||||||
RadioAstBeXmit: prometheus.NewDesc(ns+"radio_ast_be_xmit", "Radio AstBe Transmit", labelR, nil),
|
RadioAstBeXmit: nd(ns+"radio_ast_be_xmit", "Radio AstBe Transmit", labelR, nil),
|
||||||
RadioChannel: prometheus.NewDesc(ns+"radio_channel", "Radio Channel", labelR, nil),
|
RadioChannel: nd(ns+"radio_channel", "Radio Channel", labelR, nil),
|
||||||
RadioCuSelfRx: prometheus.NewDesc(ns+"radio_channel_utilization_receive_ratio", "Radio Channel Utilization Receive", labelR, nil),
|
RadioCuSelfRx: nd(ns+"radio_channel_utilization_receive_ratio", "Channel Utilization Rx", labelR, nil),
|
||||||
RadioCuSelfTx: prometheus.NewDesc(ns+"radio_channel_utilization_transmit_ratio", "Radio Channel Utilization Transmit", labelR, nil),
|
RadioCuSelfTx: nd(ns+"radio_channel_utilization_transmit_ratio", "Channel Utilization Tx", labelR, nil),
|
||||||
RadioExtchannel: prometheus.NewDesc(ns+"radio_ext_channel", "Radio Ext Channel", labelR, nil),
|
RadioExtchannel: nd(ns+"radio_ext_channel", "Radio Ext Channel", labelR, nil),
|
||||||
RadioGain: prometheus.NewDesc(ns+"radio_gain", "Radio Gain", labelR, nil),
|
RadioGain: nd(ns+"radio_gain", "Radio Gain", labelR, nil),
|
||||||
RadioNumSta: prometheus.NewDesc(ns+"radio_stations", "Radio Total Station Count", append(labelR, "station_type"), nil),
|
RadioNumSta: nd(ns+"radio_stations", "Radio Total Station Count", append(labelR, "station_type"), nil),
|
||||||
RadioTxPackets: prometheus.NewDesc(ns+"radio_transmit_packets", "Radio Transmitted Packets", labelR, nil),
|
RadioTxPackets: nd(ns+"radio_transmit_packets", "Radio Transmitted Packets", labelR, nil),
|
||||||
RadioTxRetries: prometheus.NewDesc(ns+"radio_transmit_retries", "Radio Transmit Retries", labelR, nil),
|
RadioTxRetries: nd(ns+"radio_transmit_retries", "Radio Transmit Retries", labelR, nil),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -283,6 +284,7 @@ func (u *promUnifi) exportRADtable(r report, labels []string, rt unifi.RadioTabl
|
||||||
labelR := []string{p.Name, p.Radio, labels[1], labels[2]}
|
labelR := []string{p.Name, p.Radio, labels[1], labels[2]}
|
||||||
labelRUser := append(labelR, "user")
|
labelRUser := append(labelR, "user")
|
||||||
labelRGuest := append(labelR, "guest")
|
labelRGuest := append(labelR, "guest")
|
||||||
|
|
||||||
r.send([]*metric{
|
r.send([]*metric{
|
||||||
{u.UAP.RadioCurrentAntennaGain, gauge, p.CurrentAntennaGain, labelR},
|
{u.UAP.RadioCurrentAntennaGain, gauge, p.CurrentAntennaGain, labelR},
|
||||||
{u.UAP.RadioHt, gauge, p.Ht, labelR},
|
{u.UAP.RadioHt, gauge, p.Ht, labelR},
|
||||||
|
|
@ -311,6 +313,7 @@ func (u *promUnifi) exportRADtable(r report, labels []string, rt unifi.RadioTabl
|
||||||
{u.UAP.RadioTxPackets, gauge, t.TxPackets, labelR},
|
{u.UAP.RadioTxPackets, gauge, t.TxPackets, labelR},
|
||||||
{u.UAP.RadioTxRetries, gauge, t.TxRetries, labelR},
|
{u.UAP.RadioTxRetries, gauge, t.TxRetries, labelR},
|
||||||
})
|
})
|
||||||
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@ type usg struct {
|
||||||
|
|
||||||
func descUSG(ns string) *usg {
|
func descUSG(ns string) *usg {
|
||||||
labels := []string{"port", "site_name", "name"}
|
labels := []string{"port", "site_name", "name"}
|
||||||
|
|
||||||
return &usg{
|
return &usg{
|
||||||
WanRxPackets: prometheus.NewDesc(ns+"wan_receive_packets_total", "WAN Receive Packets Total", labels, nil),
|
WanRxPackets: prometheus.NewDesc(ns+"wan_receive_packets_total", "WAN Receive Packets Total", labels, nil),
|
||||||
WanRxBytes: prometheus.NewDesc(ns+"wan_receive_bytes_total", "WAN Receive Bytes Total", labels, nil),
|
WanRxBytes: prometheus.NewDesc(ns+"wan_receive_bytes_total", "WAN Receive Bytes Total", labels, nil),
|
||||||
|
|
@ -75,6 +76,7 @@ func (u *promUnifi) exportUSG(r report, d *unifi.USG) {
|
||||||
|
|
||||||
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.
|
||||||
u.exportWANPorts(r, labels, d.Wan1, d.Wan2)
|
u.exportWANPorts(r, labels, d.Wan1, d.Wan2)
|
||||||
u.exportBYTstats(r, labels, d.TxBytes, d.RxBytes)
|
u.exportBYTstats(r, labels, d.TxBytes, d.RxBytes)
|
||||||
|
|
@ -95,6 +97,7 @@ func (u *promUnifi) exportUSGstats(r report, labels []string, gw *unifi.Gw, st u
|
||||||
|
|
||||||
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{
|
||||||
{u.USG.LanRxPackets, counter, gw.LanRxPackets, labelLan},
|
{u.USG.LanRxPackets, counter, gw.LanRxPackets, labelLan},
|
||||||
{u.USG.LanRxBytes, counter, gw.LanRxBytes, labelLan},
|
{u.USG.LanRxBytes, counter, gw.LanRxBytes, labelLan},
|
||||||
|
|
@ -119,6 +122,7 @@ func (u *promUnifi) exportWANPorts(r report, labels []string, wans ...unifi.Wan)
|
||||||
}
|
}
|
||||||
|
|
||||||
labelWan := []string{wan.Name, labels[1], labels[2]}
|
labelWan := []string{wan.Name, labels[1], labels[2]}
|
||||||
|
|
||||||
r.send([]*metric{
|
r.send([]*metric{
|
||||||
{u.USG.WanRxPackets, counter, wan.RxPackets, labelWan},
|
{u.USG.WanRxPackets, counter, wan.RxPackets, labelWan},
|
||||||
{u.USG.WanRxBytes, counter, wan.RxBytes, labelWan},
|
{u.USG.WanRxBytes, counter, wan.RxBytes, labelWan},
|
||||||
|
|
|
||||||
|
|
@ -49,45 +49,46 @@ func descUSW(ns string) *usw {
|
||||||
pns := ns + "port_"
|
pns := ns + "port_"
|
||||||
labelS := []string{"site_name", "name"}
|
labelS := []string{"site_name", "name"}
|
||||||
labelP := []string{"port_id", "port_num", "port_name", "port_mac", "port_ip", "site_name", "name"}
|
labelP := []string{"port_id", "port_num", "port_name", "port_mac", "port_ip", "site_name", "name"}
|
||||||
|
nd := prometheus.NewDesc
|
||||||
|
|
||||||
return &usw{
|
return &usw{
|
||||||
// This data may be derivable by sum()ing the port data.
|
// This data may be derivable by sum()ing the port data.
|
||||||
SwRxPackets: prometheus.NewDesc(ns+"switch_receive_packets_total", "Switch Packets Received Total", labelS, nil),
|
SwRxPackets: nd(ns+"switch_receive_packets_total", "Switch Packets Received Total", labelS, nil),
|
||||||
SwRxBytes: prometheus.NewDesc(ns+"switch_receive_bytes_total", "Switch Bytes Received Total", labelS, nil),
|
SwRxBytes: nd(ns+"switch_receive_bytes_total", "Switch Bytes Received Total", labelS, nil),
|
||||||
SwRxErrors: prometheus.NewDesc(ns+"switch_receive_errors_total", "Switch Errors Received Total", labelS, nil),
|
SwRxErrors: nd(ns+"switch_receive_errors_total", "Switch Errors Received Total", labelS, nil),
|
||||||
SwRxDropped: prometheus.NewDesc(ns+"switch_receive_dropped_total", "Switch Dropped Received Total", labelS, nil),
|
SwRxDropped: nd(ns+"switch_receive_dropped_total", "Switch Dropped Received Total", labelS, nil),
|
||||||
SwRxCrypts: prometheus.NewDesc(ns+"switch_receive_crypts_total", "Switch Crypts Received Total", labelS, nil),
|
SwRxCrypts: nd(ns+"switch_receive_crypts_total", "Switch Crypts Received Total", labelS, nil),
|
||||||
SwRxFrags: prometheus.NewDesc(ns+"switch_receive_frags_total", "Switch Frags Received Total", labelS, nil),
|
SwRxFrags: nd(ns+"switch_receive_frags_total", "Switch Frags Received Total", labelS, nil),
|
||||||
SwTxPackets: prometheus.NewDesc(ns+"switch_transmit_packets_total", "Switch Packets Transmit Total", labelS, nil),
|
SwTxPackets: nd(ns+"switch_transmit_packets_total", "Switch Packets Transmit Total", labelS, nil),
|
||||||
SwTxBytes: prometheus.NewDesc(ns+"switch_transmit_bytes_total", "Switch Bytes Transmit Total", labelS, nil),
|
SwTxBytes: nd(ns+"switch_transmit_bytes_total", "Switch Bytes Transmit Total", labelS, nil),
|
||||||
SwTxErrors: prometheus.NewDesc(ns+"switch_transmit_errors_total", "Switch Errors Transmit Total", labelS, nil),
|
SwTxErrors: nd(ns+"switch_transmit_errors_total", "Switch Errors Transmit Total", labelS, nil),
|
||||||
SwTxDropped: prometheus.NewDesc(ns+"switch_transmit_dropped_total", "Switch Dropped Transmit Total", labelS, nil),
|
SwTxDropped: nd(ns+"switch_transmit_dropped_total", "Switch Dropped Transmit Total", labelS, nil),
|
||||||
SwTxRetries: prometheus.NewDesc(ns+"switch_transmit_retries_total", "Switch Retries Transmit Total", labelS, nil),
|
SwTxRetries: nd(ns+"switch_transmit_retries_total", "Switch Retries Transmit Total", labelS, nil),
|
||||||
SwRxMulticast: prometheus.NewDesc(ns+"switch_receive_multicast_total", "Switch Multicast Receive Total", labelS, nil),
|
SwRxMulticast: nd(ns+"switch_receive_multicast_total", "Switch Multicast Receive Total", labelS, nil),
|
||||||
SwRxBroadcast: prometheus.NewDesc(ns+"switch_receive_broadcast_total", "Switch Broadcast Receive Total", labelS, nil),
|
SwRxBroadcast: nd(ns+"switch_receive_broadcast_total", "Switch Broadcast Receive Total", labelS, nil),
|
||||||
SwTxMulticast: prometheus.NewDesc(ns+"switch_transmit_multicast_total", "Switch Multicast Transmit Total", labelS, nil),
|
SwTxMulticast: nd(ns+"switch_transmit_multicast_total", "Switch Multicast Transmit Total", labelS, nil),
|
||||||
SwTxBroadcast: prometheus.NewDesc(ns+"switch_transmit_broadcast_total", "Switch Broadcast Transmit Total", labelS, nil),
|
SwTxBroadcast: nd(ns+"switch_transmit_broadcast_total", "Switch Broadcast Transmit Total", labelS, nil),
|
||||||
SwBytes: prometheus.NewDesc(ns+"switch_bytes_total", "Switch Bytes Transferred Total", labelS, nil),
|
SwBytes: nd(ns+"switch_bytes_total", "Switch Bytes Transferred Total", labelS, nil),
|
||||||
// per-port data
|
// per-port data
|
||||||
PoeCurrent: prometheus.NewDesc(pns+"poe_amperes", "POE Current", labelP, nil),
|
PoeCurrent: nd(pns+"poe_amperes", "POE Current", labelP, nil),
|
||||||
PoePower: prometheus.NewDesc(pns+"poe_watts", "POE Power", labelP, nil),
|
PoePower: nd(pns+"poe_watts", "POE Power", labelP, nil),
|
||||||
PoeVoltage: prometheus.NewDesc(pns+"poe_volts", "POE Voltage", labelP, nil),
|
PoeVoltage: nd(pns+"poe_volts", "POE Voltage", labelP, nil),
|
||||||
RxBroadcast: prometheus.NewDesc(pns+"receive_broadcast_total", "Receive Broadcast", labelP, nil),
|
RxBroadcast: nd(pns+"receive_broadcast_total", "Receive Broadcast", labelP, nil),
|
||||||
RxBytes: prometheus.NewDesc(pns+"receive_bytes_total", "Total Receive Bytes", labelP, nil),
|
RxBytes: nd(pns+"receive_bytes_total", "Total Receive Bytes", labelP, nil),
|
||||||
RxBytesR: prometheus.NewDesc(pns+"receive_rate_bytes", "Receive Bytes Rate", labelP, nil),
|
RxBytesR: nd(pns+"receive_rate_bytes", "Receive Bytes Rate", labelP, nil),
|
||||||
RxDropped: prometheus.NewDesc(pns+"receive_dropped_total", "Total Receive Dropped", labelP, nil),
|
RxDropped: nd(pns+"receive_dropped_total", "Total Receive Dropped", labelP, nil),
|
||||||
RxErrors: prometheus.NewDesc(pns+"receive_errors_total", "Total Receive Errors", labelP, nil),
|
RxErrors: nd(pns+"receive_errors_total", "Total Receive Errors", labelP, nil),
|
||||||
RxMulticast: prometheus.NewDesc(pns+"receive_multicast_total", "Total Receive Multicast", labelP, nil),
|
RxMulticast: nd(pns+"receive_multicast_total", "Total Receive Multicast", labelP, nil),
|
||||||
RxPackets: prometheus.NewDesc(pns+"receive_packets_total", "Total Receive Packets", labelP, nil),
|
RxPackets: nd(pns+"receive_packets_total", "Total Receive Packets", labelP, nil),
|
||||||
Satisfaction: prometheus.NewDesc(pns+"satisfaction_ratio", "Satisfaction", labelP, nil),
|
Satisfaction: nd(pns+"satisfaction_ratio", "Satisfaction", labelP, nil),
|
||||||
Speed: prometheus.NewDesc(pns+"port_speed_bps", "Speed", labelP, nil),
|
Speed: nd(pns+"port_speed_bps", "Speed", labelP, nil),
|
||||||
TxBroadcast: prometheus.NewDesc(pns+"transmit_broadcast_total", "Total Transmit Broadcast", labelP, nil),
|
TxBroadcast: nd(pns+"transmit_broadcast_total", "Total Transmit Broadcast", labelP, nil),
|
||||||
TxBytes: prometheus.NewDesc(pns+"transmit_bytes_total", "Total Transmit Bytes", labelP, nil),
|
TxBytes: nd(pns+"transmit_bytes_total", "Total Transmit Bytes", labelP, nil),
|
||||||
TxBytesR: prometheus.NewDesc(pns+"transmit_rate_bytes", "Transmit Bytes Rate", labelP, nil),
|
TxBytesR: nd(pns+"transmit_rate_bytes", "Transmit Bytes Rate", labelP, nil),
|
||||||
TxDropped: prometheus.NewDesc(pns+"transmit_dropped_total", "Total Transmit Dropped", labelP, nil),
|
TxDropped: nd(pns+"transmit_dropped_total", "Total Transmit Dropped", labelP, nil),
|
||||||
TxErrors: prometheus.NewDesc(pns+"transmit_errors_total", "Total Transmit Errors", labelP, nil),
|
TxErrors: nd(pns+"transmit_errors_total", "Total Transmit Errors", labelP, nil),
|
||||||
TxMulticast: prometheus.NewDesc(pns+"transmit_multicast_total", "Total Tranmist Multicast", labelP, nil),
|
TxMulticast: nd(pns+"transmit_multicast_total", "Total Tranmist Multicast", labelP, nil),
|
||||||
TxPackets: prometheus.NewDesc(pns+"transmit_packets_total", "Total Transmit Packets", labelP, nil),
|
TxPackets: nd(pns+"transmit_packets_total", "Total Transmit Packets", labelP, nil),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -98,6 +99,7 @@ func (u *promUnifi) exportUSW(r report, d *unifi.USW) {
|
||||||
|
|
||||||
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)
|
||||||
u.exportPRTtable(r, labels, d.PortTable)
|
u.exportPRTtable(r, labels, d.PortTable)
|
||||||
u.exportBYTstats(r, labels, d.TxBytes, d.RxBytes)
|
u.exportBYTstats(r, labels, d.TxBytes, d.RxBytes)
|
||||||
|
|
@ -129,6 +131,7 @@ func (u *promUnifi) exportUSWstats(r report, labels []string, sw *unifi.Sw) {
|
||||||
}
|
}
|
||||||
|
|
||||||
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},
|
||||||
{u.USW.SwRxBytes, counter, sw.RxBytes, labelS},
|
{u.USW.SwRxBytes, counter, sw.RxBytes, labelS},
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue