@cryptotaxi247 / netdata-1 / commits / 3a787aa9e

feat(go.d/snmp): enable profile scalar metrics collection (#20426)

Ilya Mashchenko committed Jun 5, 2025 at 20:56 UTC 3a787aa9e6a3b6b455c57b6e5a53cb286c561ced
7 files changed +120 -4
src/go/plugin/go.d/collector/snmp/charts.go
+71
@@ -4,9 +4,12 @@ package snmp
4
5 import (
6 "fmt"
7 + "maps"
8 "strings"
9
10 "github.com/netdata/netdata/go/plugins/plugin/go.d/agent/module"
11 + "github.com/netdata/netdata/go/plugins/plugin/go.d/collector/snmp/ddsnmp/ddprofiledefinition"
12 + "github.com/netdata/netdata/go/plugins/plugin/go.d/collector/snmp/ddsnmp/ddsnmpcollector"
13 )
14
15 const (
@@ -19,6 +22,8 @@ const (
22 prioNetIfaceAdminStatus
23 prioNetIfaceOperStatus
24 prioSysUptime
25 +
26 + prioProfileChart
27 )
28
29 var netIfaceChartsTmpl = module.Charts{
@@ -309,3 +314,69 @@ func newUserInputChart(cfg ChartConfig) (*module.Chart, error) {
314
315 return chart, nil
316 }
317 +
318 +func (c *Collector) addProfileScalarMetricChart(m ddsnmpcollector.Metric) {
319 + if m.Name == "" {
320 + return
321 + }
322 +
323 + r := strings.NewReplacer(".", "_", " ", "_")
324 + chart := &module.Chart{
325 + ID: fmt.Sprintf("snmp_device_prof_%s", r.Replace(m.Name)),
326 + Title: m.Description,
327 + Units: m.Unit,
328 + Fam: m.Family,
329 + Ctx: fmt.Sprintf("snmp.device_prof_%s", r.Replace(m.Name)),
330 + Priority: prioProfileChart,
331 + }
332 + if chart.Title == "" {
333 + chart.Title = fmt.Sprintf("SNMP metric %s", m.Name)
334 + }
335 + if chart.Units == "" {
336 + chart.Units = "1"
337 + }
338 + if chart.Fam == "" {
339 + chart.Fam = m.Name
340 + }
341 +
342 + tags := map[string]string{
343 + "vendor": c.sysInfo.Organization,
344 + "sysName": c.sysInfo.Name,
345 + }
346 + maps.Copy(tags, m.Tags)
347 + for k, v := range tags {
348 + chart.Labels = append(chart.Labels, module.Label{Key: k, Value: v})
349 + }
350 +
351 + if len(m.Mappings) > 0 {
352 + for _, v := range m.Mappings {
353 + id := fmt.Sprintf("snmp_device_prof_%s_%s", m.Name, v)
354 + chart.Dims = append(chart.Dims, &module.Dim{ID: id, Name: v, Algo: module.Absolute})
355 + }
356 + } else {
357 + id := fmt.Sprintf("snmp_device_prof_%s", m.Name)
358 + chart.Dims = module.Dims{
359 + {ID: id, Name: m.Name, Algo: dimAlgoFromDdSnmpType(m)},
360 + }
361 + }
362 +
363 + if err := c.Charts().Add(chart); err != nil {
364 + c.Warning(err)
365 + }
366 +}
367 +
368 +func (c *Collector) removeProfileScalarMetricChart(metricName string) {
369 + r := strings.NewReplacer(".", "_", " ", "_")
370 + id := fmt.Sprintf("snmp_device_prof_%s", r.Replace(metricName))
371 + if chart := c.Charts().Get(id); chart != nil {
372 + chart.MarkRemove()
373 + chart.MarkNotCreated()
374 + }
375 +}
376 +
377 +func dimAlgoFromDdSnmpType(m ddsnmpcollector.Metric) module.DimAlgo {
378 + if m.MetricType == ddprofiledefinition.ProfileMetricTypeGauge {
379 + return module.Absolute
380 + }
381 + return module.Incremental
382 +}
src/go/plugin/go.d/collector/snmp/collect.go
+1 -1
@@ -37,7 +37,7 @@ func (c *Collector) collect() (map[string]int64, error) {
37 mx := make(map[string]int64)
38
39 if err := c.collectProfiles(mx); err != nil {
40 - return nil, err
40 + c.Infof("failed to collect profiles: %v", err)
41 }
42
43 if err := c.collectSysUptime(mx); err != nil {
src/go/plugin/go.d/collector/snmp/collect_profiles.go
+38 -1
@@ -3,10 +3,13 @@
3 package snmp
4
5 import (
6 + "fmt"
7 +
8 "github.com/netdata/netdata/go/plugins/plugin/go.d/collector/snmp/ddsnmp/ddsnmpcollector"
9 + "github.com/netdata/netdata/go/plugins/plugin/go.d/pkg/metrix"
10 )
11
9 -func (c *Collector) collectProfiles(_ map[string]int64) error {
12 +func (c *Collector) collectProfiles(mx map[string]int64) error {
13 if len(c.snmpProfiles) == 0 {
14 return nil
15 }
@@ -14,5 +17,39 @@ func (c *Collector) collectProfiles(_ map[string]int64) error {
17 c.ddSnmpColl = ddsnmpcollector.New(c.snmpClient, c.snmpProfiles, c.Logger)
18 }
19
20 + profMetrics, err := c.ddSnmpColl.Collect()
21 + if err != nil {
22 + return err
23 + }
24 +
25 + seen := make(map[string]bool)
26 +
27 + for _, pm := range profMetrics {
28 + for _, m := range pm.Metrics {
29 + seen[m.Name] = true
30 + if !c.seenScalarMetrics[m.Name] {
31 + c.seenScalarMetrics[m.Name] = true
32 + c.addProfileScalarMetricChart(m)
33 + }
34 +
35 + if len(m.Mappings) > 0 {
36 + for k, v := range m.Mappings {
37 + id := fmt.Sprintf("snmp_device_prof_%s_%s", m.Name, v)
38 + mx[id] = metrix.Bool(m.Value == k)
39 + }
40 + } else {
41 + id := fmt.Sprintf("snmp_device_prof_%s", m.Name)
42 + mx[id] = m.Value
43 + }
44 + }
45 + }
46 +
47 + for name := range c.seenScalarMetrics {
48 + if !seen[name] {
49 + delete(c.seenScalarMetrics, name)
50 + c.removeProfileScalarMetricChart(name)
51 + }
52 + }
53 +
54 return nil
55 }
src/go/plugin/go.d/collector/snmp/collector.go
+4
@@ -61,6 +61,8 @@ func New() *Collector {
61 checkMaxReps: true,
62 collectIfMib: true,
63 netInterfaces: make(map[string]*netInterface),
64 +
65 + seenScalarMetrics: make(map[string]bool),
66 }
67 }
68
@@ -90,6 +92,8 @@ type Collector struct {
92 customOids []string
93
94 snmpProfiles []*ddsnmp.Profile
95 +
96 + seenScalarMetrics map[string]bool
97 }
98
99 func (c *Collector) Configuration() any {
src/go/plugin/go.d/collector/snmp/ddsnmp/ddprofiledefinition/metrics.go
+1
@@ -81,6 +81,7 @@ type SymbolConfig struct {
81 MetricType ProfileMetricType `yaml:"metric_type,omitempty" json:"metric_type,omitempty"`
82 Unit string `yaml:"unit,omitempty" json:"unit,omitempty"`
83 Description string `yaml:"description,omitempty" json:"description,omitempty"`
84 + Family string `yaml:"family,omitempty" json:"family,omitempty"`
85 Mapping map[string]string `yaml:"mapping,omitempty" json:"mapping,omitempty"`
86 }
87
src/go/plugin/go.d/collector/snmp/ddsnmp/ddsnmpcollector/collect_scalar.go
+2 -1
@@ -102,8 +102,9 @@ func (c *Collector) collectScalarMetric(cfg ddprofiledefinition.MetricsConfig, p
102 Tags: tags,
103 Unit: cfg.Symbol.Unit,
104 Description: cfg.Symbol.Description,
105 + Family: cfg.Symbol.Family,
106 Mappings: mappings,
106 - MetricType: string(getMetricType(cfg.Symbol, pdu)),
107 + MetricType: getMetricType(cfg.Symbol, pdu),
108 }, nil
109 }
110
src/go/plugin/go.d/collector/snmp/ddsnmp/ddsnmpcollector/collector.go
+3 -1
@@ -13,6 +13,7 @@ import (
13
14 "github.com/netdata/netdata/go/plugins/logger"
15 "github.com/netdata/netdata/go/plugins/plugin/go.d/collector/snmp/ddsnmp"
16 + "github.com/netdata/netdata/go/plugins/plugin/go.d/collector/snmp/ddsnmp/ddprofiledefinition"
17 )
18
19 type ProfileMetrics struct {
@@ -24,8 +25,9 @@ type ProfileMetrics struct {
25 type Metric struct {
26 Name string
27 Description string
28 + Family string
29 Unit string
28 - MetricType string
30 + MetricType ddprofiledefinition.ProfileMetricType
31 Tags map[string]string
32 Mappings map[int64]string
33 Value int64