@cryptotaxi247 / netdata / commits / 479a3f92b

improve(go.d/snmp-profiles): metrics deduplication (#20520)

Ilya Mashchenko committed Jun 18, 2025 at 23:36 UTC 479a3f92ba06596c75206492c3fc3ec2692e5694
2 files changed +855
src/go/plugin/go.d/collector/snmp/ddsnmp/profile.go
+84
@@ -4,10 +4,12 @@ package ddsnmp
4
5 import (
6 "errors"
7 + "fmt"
8 "io/fs"
9 "os"
10 "path/filepath"
11 "slices"
12 + "sort"
13 "strings"
14 "sync"
15
@@ -65,6 +67,7 @@ func FindProfiles(sysObjId string) []*Profile {
67 }
68
69 enrichProfiles(profiles)
70 + deduplicateMetricsAcrossProfiles(profiles)
71
72 return profiles
73 }
@@ -272,6 +275,7 @@ func loadProfileExtensions(profile *Profile, dir string, processedExtends map[st
275 }
276
277 func getProfilesDir() string {
278 + //return "/Users/ilyam/Projects/github/ilyam8/netdata/src/go/plugin/go.d/config/go.d/snmp.profiles/default"
279 if executable.Name == "test" {
280 dir, _ := filepath.Abs("../../../config/go.d/snmp.profiles/default")
281 return dir
@@ -305,3 +309,83 @@ func enrichProfiles(profiles []*Profile) {
309 }
310 }
311 }
312 +
313 +func deduplicateMetricsAcrossProfiles(profiles []*Profile) {
314 + if len(profiles) < 2 {
315 + return
316 + }
317 +
318 + // Create a slice of indices sorted by priority (non-generic first)
319 + type indexedProfile struct {
320 + idx int
321 + isGeneric bool
322 + }
323 +
324 + indexed := make([]indexedProfile, len(profiles))
325 + for i, prof := range profiles {
326 + indexed[i] = indexedProfile{
327 + idx: i,
328 + isGeneric: strings.Contains(strings.ToLower(prof.SourceFile), "generic-"),
329 + }
330 + }
331 +
332 + slices.SortFunc(indexed, func(a, b indexedProfile) int {
333 + if a.isGeneric && !b.isGeneric {
334 + return 1 // a comes after b
335 + }
336 + if !a.isGeneric && b.isGeneric {
337 + return -1 // a comes before b
338 + }
339 + // If both are generic or both are non-generic, maintain original order
340 + return a.idx - b.idx
341 + })
342 +
343 + // Reorder profiles slice according to deduplication priority
344 + sortedProfiles := make([]*Profile, len(profiles))
345 + for i, ip := range indexed {
346 + sortedProfiles[i] = profiles[ip.idx]
347 + }
348 + copy(profiles, sortedProfiles)
349 +
350 + seenMetrics := make(map[string]bool)
351 +
352 + for _, prof := range profiles {
353 + if prof.Definition == nil {
354 + continue
355 + }
356 +
357 + prof.Definition.Metrics = slices.DeleteFunc(prof.Definition.Metrics, func(metric ddprofiledefinition.MetricsConfig) bool {
358 + key := generateMetricKey(metric)
359 + if seenMetrics[key] {
360 + return true
361 + }
362 + seenMetrics[key] = true
363 + return false
364 + })
365 + }
366 +}
367 +
368 +func generateMetricKey(metric ddprofiledefinition.MetricsConfig) string {
369 + var parts []string
370 +
371 + if metric.IsScalar() {
372 + parts = append(parts, "scalar")
373 + parts = append(parts, metric.Symbol.OID)
374 + parts = append(parts, metric.Symbol.Name)
375 + return strings.Join(parts, "|")
376 + }
377 +
378 + parts = append(parts, "table")
379 + parts = append(parts, metric.Table.OID)
380 + parts = append(parts, metric.Table.Name)
381 +
382 + symbolKeys := make([]string, 0, len(metric.Symbols))
383 + for _, sym := range metric.Symbols {
384 + symbolKey := fmt.Sprintf("%s:%s", sym.OID, sym.Name)
385 + symbolKeys = append(symbolKeys, symbolKey)
386 + }
387 + sort.Strings(symbolKeys)
388 + parts = append(parts, symbolKeys...)
389 +
390 + return strings.Join(parts, "|")
391 +}
src/go/plugin/go.d/collector/snmp/ddsnmp/profile_test.go
+771
@@ -11,6 +11,8 @@ import (
11
12 "github.com/stretchr/testify/assert"
13 "github.com/stretchr/testify/require"
14 +
15 + "github.com/netdata/netdata/go/plugins/plugin/go.d/collector/snmp/ddsnmp/ddprofiledefinition"
16 )
17
18 func Test_loadDDSnmpProfiles(t *testing.T) {
@@ -72,3 +74,772 @@ func Test_Profile_merge(t *testing.T) {
74 }
75 }
76 }
77 +
78 +func TestDeduplicateMetricsAcrossProfiles(t *testing.T) {
79 + tests := map[string]struct {
80 + profiles []*Profile
81 + expected []*Profile
82 + }{
83 + "no profiles": {
84 + profiles: []*Profile{},
85 + expected: []*Profile{},
86 + },
87 + "single profile no duplicates": {
88 + profiles: []*Profile{
89 + {
90 + SourceFile: "profile1.yaml",
91 + Definition: &ddprofiledefinition.ProfileDefinition{
92 + Metrics: []ddprofiledefinition.MetricsConfig{
93 + {
94 + Symbol: ddprofiledefinition.SymbolConfig{
95 + OID: "1.3.6.1.2.1.1.3.0",
96 + Name: "sysUpTime",
97 + },
98 + },
99 + {
100 + Symbol: ddprofiledefinition.SymbolConfig{
101 + OID: "1.3.6.1.2.1.1.5.0",
102 + Name: "sysName",
103 + },
104 + },
105 + },
106 + },
107 + },
108 + },
109 + expected: []*Profile{
110 + {
111 + SourceFile: "profile1.yaml",
112 + Definition: &ddprofiledefinition.ProfileDefinition{
113 + Metrics: []ddprofiledefinition.MetricsConfig{
114 + {
115 + Symbol: ddprofiledefinition.SymbolConfig{
116 + OID: "1.3.6.1.2.1.1.3.0",
117 + Name: "sysUpTime",
118 + },
119 + },
120 + {
121 + Symbol: ddprofiledefinition.SymbolConfig{
122 + OID: "1.3.6.1.2.1.1.5.0",
123 + Name: "sysName",
124 + },
125 + },
126 + },
127 + },
128 + },
129 + },
130 + },
131 + "duplicate scalar metrics across profiles": {
132 + profiles: []*Profile{
133 + {
134 + SourceFile: "profile1.yaml",
135 + Definition: &ddprofiledefinition.ProfileDefinition{
136 + Metrics: []ddprofiledefinition.MetricsConfig{
137 + {
138 + Symbol: ddprofiledefinition.SymbolConfig{
139 + OID: "1.3.6.1.2.1.1.3.0",
140 + Name: "sysUpTime",
141 + },
142 + },
143 + },
144 + },
145 + },
146 + {
147 + SourceFile: "profile2.yaml",
148 + Definition: &ddprofiledefinition.ProfileDefinition{
149 + Metrics: []ddprofiledefinition.MetricsConfig{
150 + {
151 + Symbol: ddprofiledefinition.SymbolConfig{
152 + OID: "1.3.6.1.2.1.1.3.0",
153 + Name: "sysUpTime",
154 + },
155 + },
156 + {
157 + Symbol: ddprofiledefinition.SymbolConfig{
158 + OID: "1.3.6.1.2.1.1.5.0",
159 + Name: "sysName",
160 + },
161 + },
162 + },
163 + },
164 + },
165 + },
166 + expected: []*Profile{
167 + {
168 + SourceFile: "profile1.yaml",
169 + Definition: &ddprofiledefinition.ProfileDefinition{
170 + Metrics: []ddprofiledefinition.MetricsConfig{
171 + {
172 + Symbol: ddprofiledefinition.SymbolConfig{
173 + OID: "1.3.6.1.2.1.1.3.0",
174 + Name: "sysUpTime",
175 + },
176 + },
177 + },
178 + },
179 + },
180 + {
181 + SourceFile: "profile2.yaml",
182 + Definition: &ddprofiledefinition.ProfileDefinition{
183 + Metrics: []ddprofiledefinition.MetricsConfig{
184 + {
185 + Symbol: ddprofiledefinition.SymbolConfig{
186 + OID: "1.3.6.1.2.1.1.5.0",
187 + Name: "sysName",
188 + },
189 + },
190 + },
191 + },
192 + },
193 + },
194 + },
195 + "duplicate table metrics - exact same symbols": {
196 + profiles: []*Profile{
197 + {
198 + SourceFile: "profile1.yaml",
199 + Definition: &ddprofiledefinition.ProfileDefinition{
200 + Metrics: []ddprofiledefinition.MetricsConfig{
201 + {
202 + Table: ddprofiledefinition.SymbolConfig{
203 + OID: "1.3.6.1.2.1.2.2",
204 + Name: "ifTable",
205 + },
206 + Symbols: []ddprofiledefinition.SymbolConfig{
207 + {
208 + OID: "1.3.6.1.2.1.2.2.1.10",
209 + Name: "ifInOctets",
210 + },
211 + {
212 + OID: "1.3.6.1.2.1.2.2.1.16",
213 + Name: "ifOutOctets",
214 + },
215 + },
216 + MetricTags: []ddprofiledefinition.MetricTagConfig{
217 + {
218 + Tag: "interface",
219 + Symbol: ddprofiledefinition.SymbolConfigCompat{
220 + OID: "1.3.6.1.2.1.2.2.1.2",
221 + Name: "ifDescr",
222 + },
223 + },
224 + },
225 + },
226 + },
227 + },
228 + },
229 + {
230 + SourceFile: "profile2.yaml",
231 + Definition: &ddprofiledefinition.ProfileDefinition{
232 + Metrics: []ddprofiledefinition.MetricsConfig{
233 + {
234 + Table: ddprofiledefinition.SymbolConfig{
235 + OID: "1.3.6.1.2.1.2.2",
236 + Name: "ifTable",
237 + },
238 + Symbols: []ddprofiledefinition.SymbolConfig{
239 + {
240 + OID: "1.3.6.1.2.1.2.2.1.10",
241 + Name: "ifInOctets",
242 + },
243 + {
244 + OID: "1.3.6.1.2.1.2.2.1.16",
245 + Name: "ifOutOctets",
246 + },
247 + },
248 + MetricTags: []ddprofiledefinition.MetricTagConfig{
249 + {
250 + Tag: "if_name", // Different tag, but ignored in key
251 + Symbol: ddprofiledefinition.SymbolConfigCompat{
252 + OID: "1.3.6.1.2.1.31.1.1.1.1",
253 + Name: "ifName",
254 + },
255 + Table: "ifXTable",
256 + },
257 + },
258 + },
259 + },
260 + },
261 + },
262 + },
263 + expected: []*Profile{
264 + {
265 + SourceFile: "profile1.yaml",
266 + Definition: &ddprofiledefinition.ProfileDefinition{
267 + Metrics: []ddprofiledefinition.MetricsConfig{
268 + {
269 + Table: ddprofiledefinition.SymbolConfig{
270 + OID: "1.3.6.1.2.1.2.2",
271 + Name: "ifTable",
272 + },
273 + Symbols: []ddprofiledefinition.SymbolConfig{
274 + {
275 + OID: "1.3.6.1.2.1.2.2.1.10",
276 + Name: "ifInOctets",
277 + },
278 + {
279 + OID: "1.3.6.1.2.1.2.2.1.16",
280 + Name: "ifOutOctets",
281 + },
282 + },
283 + MetricTags: []ddprofiledefinition.MetricTagConfig{
284 + {
285 + Tag: "interface",
286 + Symbol: ddprofiledefinition.SymbolConfigCompat{
287 + OID: "1.3.6.1.2.1.2.2.1.2",
288 + Name: "ifDescr",
289 + },
290 + },
291 + },
292 + },
293 + },
294 + },
295 + },
296 + {
297 + SourceFile: "profile2.yaml",
298 + Definition: &ddprofiledefinition.ProfileDefinition{
299 + Metrics: []ddprofiledefinition.MetricsConfig{}, // Empty because it's a duplicate
300 + },
301 + },
302 + },
303 + },
304 + "same table different symbols - keep both": {
305 + profiles: []*Profile{
306 + {
307 + SourceFile: "profile1.yaml",
308 + Definition: &ddprofiledefinition.ProfileDefinition{
309 + Metrics: []ddprofiledefinition.MetricsConfig{
310 + {
311 + Table: ddprofiledefinition.SymbolConfig{
312 + OID: "1.3.6.1.2.1.2.2",
313 + Name: "ifTable",
314 + },
315 + Symbols: []ddprofiledefinition.SymbolConfig{
316 + {
317 + OID: "1.3.6.1.2.1.2.2.1.10",
318 + Name: "ifInOctets",
319 + },
320 + },
321 + },
322 + },
323 + },
324 + },
325 + {
326 + SourceFile: "profile2.yaml",
327 + Definition: &ddprofiledefinition.ProfileDefinition{
328 + Metrics: []ddprofiledefinition.MetricsConfig{
329 + {
330 + Table: ddprofiledefinition.SymbolConfig{
331 + OID: "1.3.6.1.2.1.2.2",
332 + Name: "ifTable",
333 + },
334 + Symbols: []ddprofiledefinition.SymbolConfig{
335 + {
336 + OID: "1.3.6.1.2.1.2.2.1.16",
337 + Name: "ifOutOctets",
338 + },
339 + },
340 + },
341 + },
342 + },
343 + },
344 + },
345 + expected: []*Profile{
346 + {
347 + SourceFile: "profile1.yaml",
348 + Definition: &ddprofiledefinition.ProfileDefinition{
349 + Metrics: []ddprofiledefinition.MetricsConfig{
350 + {
351 + Table: ddprofiledefinition.SymbolConfig{
352 + OID: "1.3.6.1.2.1.2.2",
353 + Name: "ifTable",
354 + },
355 + Symbols: []ddprofiledefinition.SymbolConfig{
356 + {
357 + OID: "1.3.6.1.2.1.2.2.1.10",
358 + Name: "ifInOctets",
359 + },
360 + },
361 + },
362 + },
363 + },
364 + },
365 + {
366 + SourceFile: "profile2.yaml",
367 + Definition: &ddprofiledefinition.ProfileDefinition{
368 + Metrics: []ddprofiledefinition.MetricsConfig{
369 + {
370 + Table: ddprofiledefinition.SymbolConfig{
371 + OID: "1.3.6.1.2.1.2.2",
372 + Name: "ifTable",
373 + },
374 + Symbols: []ddprofiledefinition.SymbolConfig{
375 + {
376 + OID: "1.3.6.1.2.1.2.2.1.16",
377 + Name: "ifOutOctets",
378 + },
379 + },
380 + },
381 + },
382 + },
383 + },
384 + },
385 + },
386 + "symbols in different order - still duplicate": {
387 + profiles: []*Profile{
388 + {
389 + SourceFile: "profile1.yaml",
390 + Definition: &ddprofiledefinition.ProfileDefinition{
391 + Metrics: []ddprofiledefinition.MetricsConfig{
392 + {
393 + Table: ddprofiledefinition.SymbolConfig{
394 + OID: "1.3.6.1.2.1.2.2",
395 + Name: "ifTable",
396 + },
397 + Symbols: []ddprofiledefinition.SymbolConfig{
398 + {
399 + OID: "1.3.6.1.2.1.2.2.1.10",
400 + Name: "ifInOctets",
401 + },
402 + {
403 + OID: "1.3.6.1.2.1.2.2.1.16",
404 + Name: "ifOutOctets",
405 + },
406 + },
407 + },
408 + },
409 + },
410 + },
411 + {
412 + SourceFile: "profile2.yaml",
413 + Definition: &ddprofiledefinition.ProfileDefinition{
414 + Metrics: []ddprofiledefinition.MetricsConfig{
415 + {
416 + Table: ddprofiledefinition.SymbolConfig{
417 + OID: "1.3.6.1.2.1.2.2",
418 + Name: "ifTable",
419 + },
420 + Symbols: []ddprofiledefinition.SymbolConfig{
421 + {
422 + OID: "1.3.6.1.2.1.2.2.1.16",
423 + Name: "ifOutOctets",
424 + },
425 + {
426 + OID: "1.3.6.1.2.1.2.2.1.10",
427 + Name: "ifInOctets",
428 + },
429 + },
430 + },
431 + },
432 + },
433 + },
434 + },
435 + expected: []*Profile{
436 + {
437 + SourceFile: "profile1.yaml",
438 + Definition: &ddprofiledefinition.ProfileDefinition{
439 + Metrics: []ddprofiledefinition.MetricsConfig{
440 + {
441 + Table: ddprofiledefinition.SymbolConfig{
442 + OID: "1.3.6.1.2.1.2.2",
443 + Name: "ifTable",
444 + },
445 + Symbols: []ddprofiledefinition.SymbolConfig{
446 + {
447 + OID: "1.3.6.1.2.1.2.2.1.10",
448 + Name: "ifInOctets",
449 + },
450 + {
451 + OID: "1.3.6.1.2.1.2.2.1.16",
452 + Name: "ifOutOctets",
453 + },
454 + },
455 + },
456 + },
457 + },
458 + },
459 + {
460 + SourceFile: "profile2.yaml",
461 + Definition: &ddprofiledefinition.ProfileDefinition{
462 + Metrics: []ddprofiledefinition.MetricsConfig{}, // Empty because symbols are sorted in key
463 + },
464 + },
465 + },
466 + },
467 + "multiple duplicates across three profiles": {
468 + profiles: []*Profile{
469 + {
470 + SourceFile: "generic-device.yaml",
471 + Definition: &ddprofiledefinition.ProfileDefinition{
472 + Metrics: []ddprofiledefinition.MetricsConfig{
473 + {
474 + Symbol: ddprofiledefinition.SymbolConfig{
475 + OID: "1.3.6.1.2.1.1.3.0",
476 + Name: "sysUpTime",
477 + },
478 + },
479 + {
480 + Table: ddprofiledefinition.SymbolConfig{
481 + OID: "1.3.6.1.2.1.2.2",
482 + Name: "ifTable",
483 + },
484 + Symbols: []ddprofiledefinition.SymbolConfig{
485 + {
486 + OID: "1.3.6.1.2.1.2.2.1.10",
487 + Name: "ifInOctets",
488 + },
489 + },
490 + },
491 + },
492 + },
493 + },
494 + {
495 + SourceFile: "vendor-specific.yaml",
496 + Definition: &ddprofiledefinition.ProfileDefinition{
497 + Metrics: []ddprofiledefinition.MetricsConfig{
498 + {
499 + Symbol: ddprofiledefinition.SymbolConfig{
500 + OID: "1.3.6.1.2.1.1.3.0",
501 + Name: "sysUpTime",
502 + },
503 + },
504 + {
505 + Symbol: ddprofiledefinition.SymbolConfig{
506 + OID: "1.3.6.1.4.1.9.9.109.1.1.1.1.7",
507 + Name: "cpmCPUTotal5minRev",
508 + },
509 + },
510 + },
511 + },
512 + },
513 + {
514 + SourceFile: "extended.yaml",
515 + Definition: &ddprofiledefinition.ProfileDefinition{
516 + Metrics: []ddprofiledefinition.MetricsConfig{
517 + {
518 + Table: ddprofiledefinition.SymbolConfig{
519 + OID: "1.3.6.1.2.1.2.2",
520 + Name: "ifTable",
521 + },
522 + Symbols: []ddprofiledefinition.SymbolConfig{
523 + {
524 + OID: "1.3.6.1.2.1.2.2.1.10",
525 + Name: "ifInOctets",
526 + },
527 + },
528 + },
529 + },
530 + },
531 + },
532 + },
533 + expected: []*Profile{
534 + {
535 + SourceFile: "vendor-specific.yaml",
536 + Definition: &ddprofiledefinition.ProfileDefinition{
537 + Metrics: []ddprofiledefinition.MetricsConfig{
538 + {
539 + Symbol: ddprofiledefinition.SymbolConfig{
540 + OID: "1.3.6.1.2.1.1.3.0",
541 + Name: "sysUpTime",
542 + },
543 + },
544 + {
545 + Symbol: ddprofiledefinition.SymbolConfig{
546 + OID: "1.3.6.1.4.1.9.9.109.1.1.1.1.7",
547 + Name: "cpmCPUTotal5minRev",
548 + },
549 + },
550 + },
551 + },
552 + },
553 + {
554 + SourceFile: "extended.yaml",
555 + Definition: &ddprofiledefinition.ProfileDefinition{
556 + Metrics: []ddprofiledefinition.MetricsConfig{
557 + {
558 + Table: ddprofiledefinition.SymbolConfig{
559 + OID: "1.3.6.1.2.1.2.2",
560 + Name: "ifTable",
561 + },
562 + Symbols: []ddprofiledefinition.SymbolConfig{
563 + {
564 + OID: "1.3.6.1.2.1.2.2.1.10",
565 + Name: "ifInOctets",
566 + },
567 + },
568 + },
569 + },
570 + },
571 + },
572 + {
573 + SourceFile: "generic-device.yaml",
574 + Definition: &ddprofiledefinition.ProfileDefinition{
575 + Metrics: []ddprofiledefinition.MetricsConfig{}, // All removed as duplicates
576 + },
577 + },
578 + },
579 + },
580 + "empty metrics in some profiles": {
581 + profiles: []*Profile{
582 + {
583 + SourceFile: "profile1.yaml",
584 + Definition: &ddprofiledefinition.ProfileDefinition{
585 + Metrics: []ddprofiledefinition.MetricsConfig{
586 + {
587 + Symbol: ddprofiledefinition.SymbolConfig{
588 + OID: "1.3.6.1.2.1.1.3.0",
589 + Name: "sysUpTime",
590 + },
591 + },
592 + },
593 + },
594 + },
595 + {
596 + SourceFile: "profile2.yaml",
597 + Definition: &ddprofiledefinition.ProfileDefinition{
598 + Metrics: []ddprofiledefinition.MetricsConfig{},
599 + },
600 + },
601 + {
602 + SourceFile: "profile3.yaml",
603 + Definition: &ddprofiledefinition.ProfileDefinition{
604 + Metrics: []ddprofiledefinition.MetricsConfig{
605 + {
606 + Symbol: ddprofiledefinition.SymbolConfig{
607 + OID: "1.3.6.1.2.1.1.3.0",
608 + Name: "sysUpTime",
609 + },
610 + },
611 + },
612 + },
613 + },
614 + },
615 + expected: []*Profile{
616 + {
617 + SourceFile: "profile1.yaml",
618 + Definition: &ddprofiledefinition.ProfileDefinition{
619 + Metrics: []ddprofiledefinition.MetricsConfig{
620 + {
621 + Symbol: ddprofiledefinition.SymbolConfig{
622 + OID: "1.3.6.1.2.1.1.3.0",
623 + Name: "sysUpTime",
624 + },
625 + },
626 + },
627 + },
628 + },
629 + {
630 + SourceFile: "profile2.yaml",
631 + Definition: &ddprofiledefinition.ProfileDefinition{
632 + Metrics: []ddprofiledefinition.MetricsConfig{},
633 + },
634 + },
635 + {
636 + SourceFile: "profile3.yaml",
637 + Definition: &ddprofiledefinition.ProfileDefinition{
638 + Metrics: []ddprofiledefinition.MetricsConfig{},
639 + },
640 + },
641 + },
642 + },
643 + "generic vs non-generic priority": {
644 + profiles: []*Profile{
645 + {
646 + SourceFile: "generic-device.yaml",
647 + Definition: &ddprofiledefinition.ProfileDefinition{
648 + Metrics: []ddprofiledefinition.MetricsConfig{
649 + {
650 + Symbol: ddprofiledefinition.SymbolConfig{
651 + OID: "1.3.6.1.2.1.1.3.0",
652 + Name: "sysUpTime",
653 + },
654 + },
655 + {
656 + Table: ddprofiledefinition.SymbolConfig{
657 + OID: "1.3.6.1.2.1.2.2",
658 + Name: "ifTable",
659 + },
660 + Symbols: []ddprofiledefinition.SymbolConfig{
661 + {
662 + OID: "1.3.6.1.2.1.2.2.1.10",
663 + Name: "ifInOctets",
664 + },
665 + {
666 + OID: "1.3.6.1.2.1.2.2.1.16",
667 + Name: "ifOutOctets",
668 + },
669 + },
670 + },
671 + {
672 + Symbol: ddprofiledefinition.SymbolConfig{
673 + OID: "1.3.6.1.2.1.1.1.0",
674 + Name: "sysDescr",
675 + },
676 + },
677 + },
678 + },
679 + },
680 + {
681 + SourceFile: "mikrotik-router.yaml",
682 + Definition: &ddprofiledefinition.ProfileDefinition{
683 + Metrics: []ddprofiledefinition.MetricsConfig{
684 + {
685 + Symbol: ddprofiledefinition.SymbolConfig{
686 + OID: "1.3.6.1.2.1.1.3.0",
687 + Name: "sysUpTime",
688 + },
689 + },
690 + {
691 + Table: ddprofiledefinition.SymbolConfig{
692 + OID: "1.3.6.1.2.1.2.2",
693 + Name: "ifTable",
694 + },
695 + Symbols: []ddprofiledefinition.SymbolConfig{
696 + {
697 + OID: "1.3.6.1.2.1.2.2.1.10",
698 + Name: "ifInOctets",
699 + },
700 + {
701 + OID: "1.3.6.1.2.1.2.2.1.16",
702 + Name: "ifOutOctets",
703 + },
704 + },
705 + },
706 + {
707 + Symbol: ddprofiledefinition.SymbolConfig{
708 + OID: "1.3.6.1.4.1.14988.1.1.1.3.0",
709 + Name: "mtxrHlCpuTemperature",
710 + },
711 + },
712 + },
713 + },
714 + },
715 + {
716 + SourceFile: "generic-if.yaml",
717 + Definition: &ddprofiledefinition.ProfileDefinition{
718 + Metrics: []ddprofiledefinition.MetricsConfig{
719 + {
720 + Symbol: ddprofiledefinition.SymbolConfig{
721 + OID: "1.3.6.1.2.1.1.1.0",
722 + Name: "sysDescr",
723 + },
724 + },
725 + {
726 + Table: ddprofiledefinition.SymbolConfig{
727 + OID: "1.3.6.1.2.1.31.1.1",
728 + Name: "ifXTable",
729 + },
730 + Symbols: []ddprofiledefinition.SymbolConfig{
731 + {
732 + OID: "1.3.6.1.2.1.31.1.1.1.6",
733 + Name: "ifHCInOctets",
734 + },
735 + },
736 + },
737 + },
738 + },
739 + },
740 + },
741 + expected: []*Profile{
742 + {
743 + SourceFile: "mikrotik-router.yaml",
744 + Definition: &ddprofiledefinition.ProfileDefinition{
745 + Metrics: []ddprofiledefinition.MetricsConfig{
746 + {
747 + Symbol: ddprofiledefinition.SymbolConfig{
748 + OID: "1.3.6.1.2.1.1.3.0",
749 + Name: "sysUpTime",
750 + },
751 + },
752 + {
753 + Table: ddprofiledefinition.SymbolConfig{
754 + OID: "1.3.6.1.2.1.2.2",
755 + Name: "ifTable",
756 + },
757 + Symbols: []ddprofiledefinition.SymbolConfig{
758 + {
759 + OID: "1.3.6.1.2.1.2.2.1.10",
760 + Name: "ifInOctets",
761 + },
762 + {
763 + OID: "1.3.6.1.2.1.2.2.1.16",
764 + Name: "ifOutOctets",
765 + },
766 + },
767 + },
768 + {
769 + Symbol: ddprofiledefinition.SymbolConfig{
770 + OID: "1.3.6.1.4.1.14988.1.1.1.3.0",
771 + Name: "mtxrHlCpuTemperature",
772 + },
773 + },
774 + },
775 + },
776 + },
777 + {
778 + SourceFile: "generic-device.yaml",
779 + Definition: &ddprofiledefinition.ProfileDefinition{
780 + Metrics: []ddprofiledefinition.MetricsConfig{
781 + {
782 + Symbol: ddprofiledefinition.SymbolConfig{
783 + OID: "1.3.6.1.2.1.1.1.0",
784 + Name: "sysDescr",
785 + },
786 + },
787 + },
788 + },
789 + },
790 + {
791 + SourceFile: "generic-if.yaml",
792 + Definition: &ddprofiledefinition.ProfileDefinition{
793 + Metrics: []ddprofiledefinition.MetricsConfig{
794 + {
795 + Table: ddprofiledefinition.SymbolConfig{
796 + OID: "1.3.6.1.2.1.31.1.1",
797 + Name: "ifXTable",
798 + },
799 + Symbols: []ddprofiledefinition.SymbolConfig{
800 + {
801 + OID: "1.3.6.1.2.1.31.1.1.1.6",
802 + Name: "ifHCInOctets",
803 + },
804 + },
805 + },
806 + },
807 + },
808 + },
809 + },
810 + },
811 + }
812 +
813 + for name, tc := range tests {
814 + t.Run(name, func(t *testing.T) {
815 + // Make a deep copy of profiles to avoid modifying test data
816 + profiles := make([]*Profile, len(tc.profiles))
817 + for i, p := range tc.profiles {
818 + profiles[i] = p.clone()
819 + }
820 +
821 + deduplicateMetricsAcrossProfiles(profiles)
822 +
823 + require.Equal(t, len(tc.expected), len(profiles))
824 +
825 + for i, expectedProf := range tc.expected {
826 + assert.Equal(t, expectedProf.SourceFile, profiles[i].SourceFile)
827 + assert.Equal(t, len(expectedProf.Definition.Metrics), len(profiles[i].Definition.Metrics))
828 +
829 + // Compare metrics
830 + for j, expectedMetric := range expectedProf.Definition.Metrics {
831 + actualMetric := profiles[i].Definition.Metrics[j]
832 +
833 + if expectedMetric.IsScalar() {
834 + assert.Equal(t, expectedMetric.Symbol.OID, actualMetric.Symbol.OID)
835 + assert.Equal(t, expectedMetric.Symbol.Name, actualMetric.Symbol.Name)
836 + } else {
837 + assert.Equal(t, expectedMetric.Table.OID, actualMetric.Table.OID)
838 + assert.Equal(t, expectedMetric.Table.Name, actualMetric.Table.Name)
839 + assert.Equal(t, len(expectedMetric.Symbols), len(actualMetric.Symbols))
840 + }
841 + }
842 + }
843 + })
844 + }
845 +}