fix(inputunifi): apply default_site_name_override to log entries

default_site_name_override is applied in augmentMetrics, which only the
metrics path goes through. Log entries leave by collectControllerEvents,
which reads its sites straight from getFilteredSites — where the override
is deliberately not applied — so events, alarms, IDS records and system-log
entries ship with the controller's stock site name.

Four of the five site-scoped log collectors were affected; collectAnomalies
already did this inline, which is what makes the omission visible.

The consequence is worst for a poller watching several UniFi OS consoles:
each one calls its only site "default", so their log entries are
indistinguishable downstream. In Loki every stream from those consoles lands
under site_name="Default (default)" no matter which console it came from,
and no relabeling downstream can separate them again — the information is
gone by then. That is precisely the case the option was added for, and it
works for the metrics from those same consoles.

Extract the check collectAnomalies was doing into overrideSiteName and call
it from all five, so the two paths agree.

Note that only Site.Name reaches an API path; Site.SiteName is a display
name throughout the library. The override is therefore safe here, which is
what applySiteNameOverride's own comment already says ("keeping default for
API calls").
This commit is contained in:
Prototype0645
2026-09-01 09:08:13 +02:00
parent 3d70164732
commit 6c08d43b4c
2 changed files with 77 additions and 3 deletions
+23 -3
View File
@@ -71,6 +71,21 @@ func (u *InputUnifi) collectControllerEvents(c *Controller) ([]any, error) {
return logs, nil
}
// overrideSiteName applies the controller's default_site_name_override to a
// site name that is still the controller's stock default.
//
// Log entries need this applied here, one collector at a time. Metrics get the
// override from augmentMetrics, but log entries never pass through it: they
// leave by collectControllerEvents, which reads its sites straight from
// getFilteredSites. So whatever a collector appends is what ships.
func overrideSiteName(c *Controller, siteName string) string {
if c.DefaultSiteNameOverride != "" && isDefaultSiteName(siteName) {
return c.DefaultSiteNameOverride
}
return siteName
}
func (u *InputUnifi) collectAlarms(logs []any, sites []*unifi.Site, c *Controller) ([]any, error) {
if *c.SaveAlarms {
u.LogDebugf("Collecting controller alarms: %s (%s)", c.URL, c.ID)
@@ -161,6 +176,7 @@ func (u *InputUnifi) collectAlarms(logs []any, sites []*unifi.Site, c *Controlle
for _, e := range events {
// Try to extract MAC address from alarm message and enrich with device name
e.DeviceName = u.extractDeviceNameFromAlarm(e, macToName)
e.SiteName = overrideSiteName(c, e.SiteName)
logs = append(logs, e)
@@ -202,9 +218,7 @@ func (u *InputUnifi) collectAnomalies(logs []any, sites []*unifi.Site, c *Contro
}
for _, e := range events {
if c.DefaultSiteNameOverride != "" && isDefaultSiteName(e.SiteName) {
e.SiteName = c.DefaultSiteNameOverride
}
e.SiteName = overrideSiteName(c, e.SiteName)
logs = append(logs, e)
@@ -241,6 +255,8 @@ func (u *InputUnifi) collectEvents(logs []any, sites []*unifi.Site, c *Controlle
for _, e := range events {
e := redactEvent(e, c.HashPII, c.DropPII)
e.SiteName = overrideSiteName(c, e.SiteName)
logs = append(logs, e)
webserver.NewInputEvent(PluginName, s.ID+"_events", &webserver.Event{
@@ -270,6 +286,8 @@ func (u *InputUnifi) collectSyslog(logs []any, sites []*unifi.Site, c *Controlle
for _, e := range entries {
e := redactSystemLogEntry(e, c.HashPII, c.DropPII)
e.SiteName = overrideSiteName(c, e.SiteName)
logs = append(logs, e)
webserver.NewInputEvent(PluginName, e.SiteName+"_syslog", &webserver.Event{
@@ -362,6 +380,8 @@ func (u *InputUnifi) collectIDs(logs []any, sites []*unifi.Site, c *Controller)
}
for _, e := range events {
e.SiteName = overrideSiteName(c, e.SiteName)
logs = append(logs, e)
webserver.NewInputEvent(PluginName, s.ID+"_ids", &webserver.Event{
+54
View File
@@ -0,0 +1,54 @@
package inputunifi // nolint: testpackage
import (
"testing"
"github.com/stretchr/testify/assert"
)
// TestOverrideSiteName is what this change exists for. Every UniFi OS console
// calls its only site "default", so a poller watching several of them ships log
// entries that cannot be told apart — which is what default_site_name_override
// is meant to solve, and did not, on this path.
func TestOverrideSiteName(t *testing.T) {
t.Parallel()
for name, tc := range map[string]struct {
override string
siteName string
want string
}{
"stock name from a UniFi OS console": {
override: "Les_Solidarites",
siteName: "Default (default)",
want: "Les_Solidarites",
},
"bare default": {
override: "Les_Solidarites",
siteName: "default",
want: "Les_Solidarites",
},
"a site the operator already named is left alone": {
override: "Les_Solidarites",
siteName: "CharlHot - SweetHome",
want: "CharlHot - SweetHome",
},
"no override configured is a no-op": {
override: "",
siteName: "Default (default)",
want: "Default (default)",
},
"empty site name is not a default": {
override: "Les_Solidarites",
siteName: "",
want: "",
},
} {
t.Run(name, func(t *testing.T) {
t.Parallel()
c := &Controller{DefaultSiteNameOverride: tc.override}
assert.Equal(t, tc.want, overrideSiteName(c, tc.siteName))
})
}
}