@cryptotaxi247 / netdata-1 / commits / c55d08d49

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 +}