improvement(go.d/ddsnmp): dedup metrics when merging profiles (#20456)
Ilya Mashchenko committed
Jun 10, 2025 at 11:56 UTC
c55d08d49f2f2ac31f77b1a0508f5001622c6ec5
2 files changed
+61
-2
src/go/plugin/go.d/collector/snmp/ddsnmp/profile.go
+40
-2
@@ -7,6 +7,7 @@ import (
7
"io/fs"
8
"os"
9
"path/filepath"
10
+ "slices"
11
"strings"
12
"sync"
13
@@ -79,11 +80,48 @@ func (p *Profile) clone() *Profile {
80
}
81
82
func (p *Profile) merge(base *Profile) {
82
- // Append metrics (deep clone already handled in the Definition.Clone method)
83
- p.Definition.Metrics = append(p.Definition.Metrics, base.Definition.Metrics...)
83
+ p.mergeMetrics(base)
84
+ // Append other fields as before (these likely don't need deduplication)
85
p.Definition.MetricTags = append(p.Definition.MetricTags, base.Definition.MetricTags...)
86
p.Definition.StaticTags = append(p.Definition.StaticTags, base.Definition.StaticTags...)
87
+ p.mergeMetadata(base)
88
+}
89
+
90
+func (p *Profile) mergeMetrics(base *Profile) {
91
+ seen := make(map[string]bool)
92
+
93
+ for _, m := range p.Definition.Metrics {
94
+ switch {
95
+ case m.IsScalar():
96
+ seen[m.Symbol.Name] = true
97
+ case m.IsColumn():
98
+ for _, symbol := range m.Symbols {
99
+ seen[symbol.Name] = true
100
+ }
101
+ }
102
+ }
103
+
104
+ for _, bm := range base.Definition.Metrics {
105
+ switch {
106
+ case bm.IsScalar():
107
+ if !seen[bm.Symbol.Name] {
108
+ p.Definition.Metrics = append(p.Definition.Metrics, bm)
109
+ seen[bm.Symbol.Name] = true
110
+ }
111
+ case bm.IsColumn():
112
+ bm.Symbols = slices.DeleteFunc(bm.Symbols, func(sym ddprofiledefinition.SymbolConfig) bool {
113
+ v := seen[sym.Name]
114
+ seen[sym.Name] = true
115
+ return v
116
+ })
117
+ if len(bm.Symbols) > 0 {
118
+ p.Definition.Metrics = append(p.Definition.Metrics, bm)
119
+ }
120
+ }
121
+ }
122
+}
123
124
+func (p *Profile) mergeMetadata(base *Profile) {
125
if p.Definition.Metadata == nil {
126
p.Definition.Metadata = make(ddprofiledefinition.MetadataConfig)
127
}
src/go/plugin/go.d/collector/snmp/ddsnmp/profile_test.go
+21
@@ -5,8 +5,11 @@ package ddsnmp
5
import (
6
"os"
7
"path/filepath"
8
+ "slices"
9
+ "strings"
10
"testing"
11
12
+ "github.com/stretchr/testify/assert"
13
"github.com/stretchr/testify/require"
14
)
15
@@ -51,3 +54,21 @@ func Test_FindProfiles(t *testing.T) {
54
})
55
}
56
}
57
+
58
+func Test_Profile_merge(t *testing.T) {
59
+ profiles := FindProfiles("1.3.6.1.4.1.9.1.1216") // cisco-nexus
60
+
61
+ i := slices.IndexFunc(profiles, func(p *Profile) bool {
62
+ return strings.HasSuffix(p.SourceFile, "cisco-nexus.yaml")
63
+ })
64
+
65
+ require.GreaterOrEqual(t, 1, 0)
66
+
67
+ for _, m := range profiles[i].Definition.Metrics {
68
+ if m.IsColumn() && m.Table.Name == "ciscoMemoryPoolTable" {
69
+ for _, s := range m.Symbols {
70
+ assert.NotEqual(t, "memory.used", s.Name)
71
+ }
72
+ }
73
+ }
74
+}