mirror of
https://github.com/unpoller/unpoller.git
synced 2026-03-31 06:24:19 -04:00
Merge pull request #940 from brngates98/feat/sysinfo-metrics
feat: add controller sysinfo metrics (unpoller#927)
This commit is contained in:
2
go.mod
2
go.mod
@@ -12,7 +12,7 @@ require (
|
||||
github.com/prometheus/common v0.67.5
|
||||
github.com/spf13/pflag v1.0.10
|
||||
github.com/stretchr/testify v1.11.1
|
||||
github.com/unpoller/unifi/v5 v5.14.0
|
||||
github.com/unpoller/unifi/v5 v5.15.0
|
||||
golang.org/x/crypto v0.47.0
|
||||
golang.org/x/term v0.39.0
|
||||
golift.io/cnfg v0.2.3
|
||||
|
||||
4
go.sum
4
go.sum
@@ -77,8 +77,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||
github.com/unpoller/unifi/v5 v5.14.0 h1:mKz1GJhkYStJLgP6CpHAvMl8YTqBFJDCM8TNvC62Ois=
|
||||
github.com/unpoller/unifi/v5 v5.14.0/go.mod h1:vSIXIclPG9dpKxUp+pavfgENHWaTZXvDg7F036R1YCo=
|
||||
github.com/unpoller/unifi/v5 v5.15.0 h1:9xYBmboWBcY4Cv8ARbWMjBlAUNVlG7TIuX+aRf6mcUE=
|
||||
github.com/unpoller/unifi/v5 v5.15.0/go.mod h1:vSIXIclPG9dpKxUp+pavfgENHWaTZXvDg7F036R1YCo=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
|
||||
@@ -198,6 +198,14 @@ func (u *InputUnifi) pollController(c *Controller) (*poller.Metrics, error) {
|
||||
u.LogDebugf("Found %d WAN configuration entries", len(m.WANConfigs))
|
||||
}
|
||||
|
||||
// Get controller system info (UniFi OS only)
|
||||
if m.Sysinfos, err = c.Unifi.GetSysinfo(sites); err != nil {
|
||||
// Don't fail collection if sysinfo fails - older controllers may not have this endpoint
|
||||
u.LogDebugf("unifi.GetSysinfo(%s): %v (continuing)", c.URL, err)
|
||||
} else {
|
||||
u.LogDebugf("Found %d Sysinfo entries", len(m.Sysinfos))
|
||||
}
|
||||
|
||||
return u.augmentMetrics(c, m), nil
|
||||
}
|
||||
|
||||
@@ -397,6 +405,10 @@ func (u *InputUnifi) augmentMetrics(c *Controller, metrics *Metrics) *poller.Met
|
||||
m.WANConfigs = append(m.WANConfigs, wanConfig)
|
||||
}
|
||||
|
||||
for _, sysinfo := range metrics.Sysinfos {
|
||||
m.Sysinfos = append(m.Sysinfos, sysinfo)
|
||||
}
|
||||
|
||||
// Apply default_site_name_override to all metrics if configured.
|
||||
// This must be done AFTER all metrics are added to m, so everything is included.
|
||||
// This allows us to use the console name for Cloud Gateways while keeping
|
||||
@@ -502,6 +514,15 @@ func applySiteNameOverride(m *poller.Metrics, overrideName string) {
|
||||
}
|
||||
}
|
||||
|
||||
// Apply to sysinfo (controller metrics)
|
||||
for i := range m.Sysinfos {
|
||||
if s, ok := m.Sysinfos[i].(*unifi.Sysinfo); ok {
|
||||
if isDefaultSiteName(s.SiteName) {
|
||||
s.SiteName = overrideName
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Apply to WAN configs
|
||||
for i := range m.WANConfigs {
|
||||
if wanConfig, ok := m.WANConfigs[i].(*unifi.WANEnrichedConfiguration); ok {
|
||||
|
||||
@@ -88,6 +88,7 @@ type Metrics struct {
|
||||
Devices *unifi.Devices
|
||||
DHCPLeases []*unifi.DHCPLease
|
||||
WANConfigs []*unifi.WANEnrichedConfiguration
|
||||
Sysinfos []*unifi.Sysinfo
|
||||
}
|
||||
|
||||
func init() { // nolint: gochecknoinits
|
||||
|
||||
@@ -92,6 +92,7 @@ type Metrics struct {
|
||||
CountryTraffic []any
|
||||
DHCPLeases []any
|
||||
WANConfigs []any
|
||||
Sysinfos []any
|
||||
}
|
||||
|
||||
// Events defines the type for log entries.
|
||||
|
||||
@@ -24,8 +24,7 @@ type Input interface {
|
||||
DebugInput() (bool, error)
|
||||
}
|
||||
|
||||
// Discoverer is an optional interface for inputs that can discover API endpoints
|
||||
// on a controller and write a shareable report (e.g. for support/debugging).
|
||||
// Discoverer is an optional interface for inputs that can discover API endpoints.
|
||||
type Discoverer interface {
|
||||
Discover(outputPath string) error
|
||||
}
|
||||
@@ -277,6 +276,7 @@ func AppendMetrics(existing *Metrics, m *Metrics) *Metrics {
|
||||
existing.CountryTraffic = append(existing.CountryTraffic, m.CountryTraffic...)
|
||||
existing.DHCPLeases = append(existing.DHCPLeases, m.DHCPLeases...)
|
||||
existing.WANConfigs = append(existing.WANConfigs, m.WANConfigs...)
|
||||
existing.Sysinfos = append(existing.Sysinfos, m.Sysinfos...)
|
||||
|
||||
return existing
|
||||
}
|
||||
|
||||
@@ -49,6 +49,7 @@ type promUnifi struct {
|
||||
CountryTraffic *ucountrytraffic
|
||||
DHCPLease *dhcplease
|
||||
WAN *wan
|
||||
Controller *controller
|
||||
// This interface is passed to the Collect() method. The Collect method uses
|
||||
// this interface to retrieve the latest UniFi measurements and export them.
|
||||
Collector poller.Collect
|
||||
@@ -210,6 +211,7 @@ func (u *promUnifi) Run(c poller.Collect) error {
|
||||
u.CountryTraffic = descCountryTraffic(u.Namespace + "_countrytraffic_")
|
||||
u.DHCPLease = descDHCPLease(u.Namespace + "_")
|
||||
u.WAN = descWAN(u.Namespace + "_")
|
||||
u.Controller = descController(u.Namespace + "_")
|
||||
|
||||
mux := http.NewServeMux()
|
||||
promver.Version = version.Version
|
||||
@@ -441,6 +443,13 @@ func (u *promUnifi) loopExports(r report) {
|
||||
}
|
||||
}
|
||||
|
||||
// Export controller sysinfo metrics
|
||||
for _, s := range m.Sysinfos {
|
||||
if sysinfo, ok := s.(*unifi.Sysinfo); ok {
|
||||
u.exportSysinfo(r, sysinfo)
|
||||
}
|
||||
}
|
||||
|
||||
u.exportClientDPItotals(r, appTotal, catTotal)
|
||||
}
|
||||
|
||||
|
||||
103
pkg/promunifi/controller.go
Normal file
103
pkg/promunifi/controller.go
Normal file
@@ -0,0 +1,103 @@
|
||||
package promunifi
|
||||
|
||||
import (
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/unpoller/unifi/v5"
|
||||
)
|
||||
|
||||
type controller struct {
|
||||
Info *prometheus.Desc
|
||||
UptimeSeconds *prometheus.Desc
|
||||
UpdateAvailable *prometheus.Desc
|
||||
UpdateDownloaded *prometheus.Desc
|
||||
AutobackupEnabled *prometheus.Desc
|
||||
WebRTCSupport *prometheus.Desc
|
||||
IsCloudConsole *prometheus.Desc
|
||||
DataRetentionDays *prometheus.Desc
|
||||
DataRetention5minHours *prometheus.Desc
|
||||
DataRetentionHourlyHours *prometheus.Desc
|
||||
DataRetentionDailyHours *prometheus.Desc
|
||||
DataRetentionMonthlyHours *prometheus.Desc
|
||||
UnsupportedDeviceCount *prometheus.Desc
|
||||
InformPort *prometheus.Desc
|
||||
HTTPSPort *prometheus.Desc
|
||||
PortalHTTPPort *prometheus.Desc
|
||||
}
|
||||
|
||||
func descController(ns string) *controller {
|
||||
labels := []string{"hostname", "site_name", "source"}
|
||||
infoLabels := []string{"version", "build", "device_type", "console_version", "hostname", "site_name", "source"}
|
||||
|
||||
nd := prometheus.NewDesc
|
||||
|
||||
return &controller{
|
||||
Info: nd(ns+"controller_info", "Controller information (always 1)", infoLabels, nil),
|
||||
UptimeSeconds: nd(ns+"controller_uptime_seconds", "Controller uptime in seconds", labels, nil),
|
||||
UpdateAvailable: nd(ns+"controller_update_available", "Update available (1/0)", labels, nil),
|
||||
UpdateDownloaded: nd(ns+"controller_update_downloaded", "Update downloaded (1/0)", labels, nil),
|
||||
AutobackupEnabled: nd(ns+"controller_autobackup_enabled", "Auto backup enabled (1/0)", labels, nil),
|
||||
WebRTCSupport: nd(ns+"controller_webrtc_support", "WebRTC supported (1/0)", labels, nil),
|
||||
IsCloudConsole: nd(ns+"controller_is_cloud_console", "Is cloud console (1/0)", labels, nil),
|
||||
DataRetentionDays: nd(ns+"controller_data_retention_days", "Data retention in days", labels, nil),
|
||||
DataRetention5minHours: nd(ns+"controller_data_retention_5min_hours", "5-minute scale retention hours", labels, nil),
|
||||
DataRetentionHourlyHours: nd(ns+"controller_data_retention_hourly_hours", "Hourly scale retention hours", labels, nil),
|
||||
DataRetentionDailyHours: nd(ns+"controller_data_retention_daily_hours", "Daily scale retention hours", labels, nil),
|
||||
DataRetentionMonthlyHours: nd(ns+"controller_data_retention_monthly_hours", "Monthly scale retention hours", labels, nil),
|
||||
UnsupportedDeviceCount: nd(ns+"controller_unsupported_device_count", "Number of unsupported devices", labels, nil),
|
||||
InformPort: nd(ns+"controller_inform_port", "Inform port number", labels, nil),
|
||||
HTTPSPort: nd(ns+"controller_https_port", "HTTPS port number", labels, nil),
|
||||
PortalHTTPPort: nd(ns+"controller_portal_http_port", "Portal HTTP port number", labels, nil),
|
||||
}
|
||||
}
|
||||
|
||||
func (u *promUnifi) exportSysinfo(r report, s *unifi.Sysinfo) {
|
||||
hostname := s.Hostname
|
||||
if hostname == "" {
|
||||
hostname = s.Name
|
||||
}
|
||||
if hostname == "" {
|
||||
hostname = s.SiteName // fallback when API omits both (e.g. remote/cloud)
|
||||
}
|
||||
labels := []string{hostname, s.SiteName, s.SourceName}
|
||||
infoLabels := []string{s.Version, s.Build, s.DeviceType, s.ConsoleVer, hostname, s.SiteName, s.SourceName}
|
||||
|
||||
updateAvail := 0
|
||||
if s.UpdateAvail {
|
||||
updateAvail = 1
|
||||
}
|
||||
updateDown := 0
|
||||
if s.UpdateDown {
|
||||
updateDown = 1
|
||||
}
|
||||
autobackup := 0
|
||||
if s.Autobackup {
|
||||
autobackup = 1
|
||||
}
|
||||
webrtc := 0
|
||||
if s.HasWebRTC {
|
||||
webrtc = 1
|
||||
}
|
||||
cloud := 0
|
||||
if s.IsCloud {
|
||||
cloud = 1
|
||||
}
|
||||
|
||||
r.send([]*metric{
|
||||
{u.Controller.Info, gauge, 1, infoLabels},
|
||||
{u.Controller.UptimeSeconds, gauge, s.Uptime, labels},
|
||||
{u.Controller.UpdateAvailable, gauge, updateAvail, labels},
|
||||
{u.Controller.UpdateDownloaded, gauge, updateDown, labels},
|
||||
{u.Controller.AutobackupEnabled, gauge, autobackup, labels},
|
||||
{u.Controller.WebRTCSupport, gauge, webrtc, labels},
|
||||
{u.Controller.IsCloudConsole, gauge, cloud, labels},
|
||||
{u.Controller.DataRetentionDays, gauge, s.DataRetDays, labels},
|
||||
{u.Controller.DataRetention5minHours, gauge, s.DataRet5min, labels},
|
||||
{u.Controller.DataRetentionHourlyHours, gauge, s.DataRetHour, labels},
|
||||
{u.Controller.DataRetentionDailyHours, gauge, s.DataRetDay, labels},
|
||||
{u.Controller.DataRetentionMonthlyHours, gauge, s.DataRetMonth, labels},
|
||||
{u.Controller.UnsupportedDeviceCount, gauge, s.Unsupported, labels},
|
||||
{u.Controller.InformPort, gauge, s.InformPort, labels},
|
||||
{u.Controller.HTTPSPort, gauge, s.HTTPSPort, labels},
|
||||
{u.Controller.PortalHTTPPort, gauge, s.PortalPort, labels},
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user