diff --git a/core/unifi/clients_influx.go b/core/unifi/clients_influx.go index 7a4ee00d..194f3fa4 100644 --- a/core/unifi/clients_influx.go +++ b/core/unifi/clients_influx.go @@ -9,16 +9,13 @@ import ( // Points generates Unifi Client datapoints for InfluxDB. // These points can be passed directly to influx. func (c Client) Points() ([]*influx.Point, error) { - // Fix name and hostname fields. Sometimes one or the other is blank. - switch { - case c.Hostname == "" && c.Name == "": - c.Hostname = c.Mac - c.Name = c.Mac - case c.Hostname == "" && c.Name != "": - c.Hostname = c.Name - case c.Name == "" && c.Hostname != "": - c.Name = c.Hostname - } + return c.PointsAt(time.Now()) +} + +// PointsAt generates Unifi Client datapoints for InfluxDB. +// These points can be passed directly to influx. +// This is just like Points(), but specify when points were created. +func (c Client) PointsAt(now time.Time) ([]*influx.Point, error) { tags := map[string]string{ "id": c.ID, "mac": c.Mac, @@ -109,7 +106,7 @@ func (c Client) Points() ([]*influx.Point, error) { "dpi_tx_bytes": c.DpiStats.TxBytes.Val, "dpi_tx_packets": c.DpiStats.TxPackets.Val, } - pt, err := influx.NewPoint("clients", tags, fields, time.Now()) + pt, err := influx.NewPoint("clients", tags, fields, now) if err != nil { return nil, err } diff --git a/core/unifi/devices.go b/core/unifi/devices.go index 20a6a580..072cf31e 100644 --- a/core/unifi/devices.go +++ b/core/unifi/devices.go @@ -17,19 +17,22 @@ func (u *Unifi) parseDevices(data []json.RawMessage, siteName string) *Devices { // Choose which type to unmarshal into based on the "type" json key. switch assetType { // Unmarshal again into the correct type.. case "uap": - if uap := (UAP{}); u.unmarshalDevice(assetType, r, &uap) == nil { - uap.SiteName = siteName - devices.UAPs = append(devices.UAPs, uap) + dev := UAP{SiteName: siteName} + if u.unmarshalDevice(assetType, r, &dev) == nil { + dev.Name = pick(dev.Name, dev.Mac) + devices.UAPs = append(devices.UAPs, dev) } case "ugw", "usg": // in case they ever fix the name in the api. - if usg := (USG{}); u.unmarshalDevice(assetType, r, &usg) == nil { - usg.SiteName = siteName - devices.USGs = append(devices.USGs, usg) + dev := USG{SiteName: siteName} + if u.unmarshalDevice(assetType, r, &dev) == nil { + dev.Name = pick(dev.Name, dev.Mac) + devices.USGs = append(devices.USGs, dev) } case "usw": - if usw := (USW{}); u.unmarshalDevice(assetType, r, &usw) == nil { - usw.SiteName = siteName - devices.USWs = append(devices.USWs, usw) + dev := USW{SiteName: siteName} + if u.unmarshalDevice(assetType, r, &dev) == nil { + dev.Name = pick(dev.Name, dev.Mac) + devices.USWs = append(devices.USWs, dev) } default: u.ErrorLog("unknown asset type - %v - skipping", assetType) @@ -50,3 +53,14 @@ func (u *Unifi) unmarshalDevice(dev string, data json.RawMessage, v interface{}) } return err } + +// pick returns the first non empty string in a list. +// used in a few places around this library. +func pick(strings ...string) string { + for _, s := range strings { + if s != "" { + return s + } + } + return "" +} diff --git a/core/unifi/site_influx.go b/core/unifi/site_influx.go index 20a7543d..82dc53fd 100644 --- a/core/unifi/site_influx.go +++ b/core/unifi/site_influx.go @@ -10,6 +10,13 @@ import ( // Points generates Unifi Sites' datapoints for InfluxDB. // These points can be passed directly to influx. func (u Site) Points() ([]*influx.Point, error) { + return u.PointsAt(time.Now()) +} + +// PointsAt generates Unifi Sites' datapoints for InfluxDB. +// These points can be passed directly to influx. +// This is just like Points(), but specify when points were created. +func (u Site) PointsAt(now time.Time) ([]*influx.Point, error) { points := []*influx.Point{} for _, s := range u.Health { tags := map[string]string{ diff --git a/core/unifi/uap_influx.go b/core/unifi/uap_influx.go index d5b3bf63..6ed3ec1a 100644 --- a/core/unifi/uap_influx.go +++ b/core/unifi/uap_influx.go @@ -9,6 +9,13 @@ import ( // Points generates Wireless-Access-Point datapoints for InfluxDB. // These points can be passed directly to influx. func (u UAP) Points() ([]*influx.Point, error) { + return u.PointsAt(time.Now()) +} + +// PointsAt generates Wireless-Access-Point datapoints for InfluxDB. +// These points can be passed directly to influx. +// This is just like Points(), but specify when points were created. +func (u UAP) PointsAt(now time.Time) ([]*influx.Point, error) { tags := map[string]string{ "id": u.ID, "mac": u.Mac, @@ -161,7 +168,7 @@ func (u UAP) Points() ([]*influx.Point, error) { "stat_wifi0-tx_retries": u.Stat.Wifi0TxRetries.Val, "stat_wifi1-tx_retries": u.Stat.Wifi1TxRetries.Val, } - pt, err := influx.NewPoint("uap", tags, fields, time.Now()) + pt, err := influx.NewPoint("uap", tags, fields, now) if err != nil { return nil, err } @@ -265,7 +272,7 @@ func (u UAP) Points() ([]*influx.Point, error) { fields["user-num_sta"] = p.UserNumSta.Val } - pt, err := influx.NewPoint("uap_vaps", tags, fields, time.Now()) + pt, err := influx.NewPoint("uap_vaps", tags, fields, now) if err != nil { return points, err } diff --git a/core/unifi/unifi.go b/core/unifi/unifi.go index 4614d7eb..25e08683 100644 --- a/core/unifi/unifi.go +++ b/core/unifi/unifi.go @@ -82,8 +82,12 @@ func (u *Unifi) GetClients(sites []Site) (Clients, error) { if err := u.GetData(clientPath, &response); err != nil { return nil, err } - for i := range response.Data { + for i, d := range response.Data { + // Add the special "Site Name" to each client. This becomes a Grafana filter somewhere. response.Data[i].SiteName = site.Desc + " (" + site.Name + ")" + // Fix name and hostname fields. Sometimes one or the other is blank. + response.Data[i].Hostname = pick(d.Hostname, d.Name, d.Mac) + response.Data[i].Name = pick(d.Name, d.Hostname) } data = append(data, response.Data...) } @@ -101,17 +105,7 @@ func (u *Unifi) GetDevices(sites []Site) (*Devices, error) { if err := u.GetData(devicePath, &response); err != nil { return nil, err } - loopDevices := u.parseDevices(response.Data, site.Desc+" ("+site.Name+")") - // Add SiteName to each device asset. - for i := range loopDevices.UAPs { - loopDevices.UAPs[i].SiteName = site.Desc + " (" + site.Name + ")" - } - for i := range loopDevices.USGs { - loopDevices.USGs[i].SiteName = site.Desc + " (" + site.Name + ")" - } - for i := range loopDevices.USWs { - loopDevices.USWs[i].SiteName = site.Desc + " (" + site.Name + ")" - } + loopDevices := u.parseDevices(response.Data, site.SiteName) devices.UAPs = append(devices.UAPs, loopDevices.UAPs...) devices.USGs = append(devices.USGs, loopDevices.USGs...) devices.USWs = append(devices.USWs, loopDevices.USWs...) @@ -127,10 +121,13 @@ func (u *Unifi) GetSites() (Sites, error) { if err := u.GetData(SiteList, &response); err != nil { return nil, err } - sites := make([]string, 0) - for i := range response.Data { - response.Data[i].SiteName = response.Data[i].Desc + " (" + response.Data[i].Name + ")" - sites = append(sites, response.Data[i].Name) + sites := []string{} // used for debug log only + for i, d := range response.Data { + // If the human name is missing (description), set it to the cryptic name. + response.Data[i].Desc = pick(d.Desc, d.Name) + // Add the custom site name to each site. used as a Grafana filter somewhere. + response.Data[i].SiteName = d.Desc + " (" + d.Name + ")" + sites = append(sites, d.Name) // used for debug log only } u.DebugLog("Found %d site(s): %s", len(sites), strings.Join(sites, ",")) return response.Data, nil diff --git a/core/unifi/usg_influx.go b/core/unifi/usg_influx.go index da1242d1..a989804e 100644 --- a/core/unifi/usg_influx.go +++ b/core/unifi/usg_influx.go @@ -10,7 +10,13 @@ import ( // Points generates Unifi Gateway datapoints for InfluxDB. // These points can be passed directly to influx. func (u USG) Points() ([]*influx.Point, error) { - now := time.Now() + return u.PointsAt(time.Now()) +} + +// PointsAt generates Unifi Gateway datapoints for InfluxDB. +// These points can be passed directly to influx. +// This is just like Points(), but specify when points were created. +func (u USG) PointsAt(now time.Time) ([]*influx.Point, error) { tags := map[string]string{ "id": u.ID, "mac": u.Mac, diff --git a/core/unifi/usw_influx.go b/core/unifi/usw_influx.go index a48a8e3e..1dee7de9 100644 --- a/core/unifi/usw_influx.go +++ b/core/unifi/usw_influx.go @@ -9,6 +9,13 @@ import ( // Points generates Unifi Switch datapoints for InfluxDB. // These points can be passed directly to influx. func (u USW) Points() ([]*influx.Point, error) { + return u.PointsAt(time.Now()) +} + +// PointsAt generates Unifi Switch datapoints for InfluxDB. +// These points can be passed directly to influx. +// This is just like Points(), but specify when points were created. +func (u USW) PointsAt(now time.Time) ([]*influx.Point, error) { tags := map[string]string{ "id": u.ID, "mac": u.Mac, @@ -93,7 +100,7 @@ func (u USW) Points() ([]*influx.Point, error) { "uplink_depth": u.UplinkDepth.Txt, // Add the port stats too. } - pt, err := influx.NewPoint("usw", tags, fields, time.Now()) + pt, err := influx.NewPoint("usw", tags, fields, now) if err != nil { return nil, err } @@ -153,7 +160,7 @@ func (u USW) Points() ([]*influx.Point, error) { "poe_voltage": p.PoeVoltage.Val, "full_duplex": p.FullDuplex.Val, } - pt, err = influx.NewPoint("usw_ports", tags, fields, time.Now()) + pt, err = influx.NewPoint("usw_ports", tags, fields, now) if err != nil { return points, err }