Skip to content

Commit

Permalink
Allow the setting of labels for snmp exporter for both target and tar…
Browse files Browse the repository at this point in the history
…gets (#1876)

* Allow the setting of labels for snmp exporter, both in the hardcoded manner and also in the labels manner.

* Simplify snmp exporter

* Add tests.

* Remove name.

* PR feedback
  • Loading branch information
mattdurham authored Oct 11, 2024
1 parent b013bc5 commit dbda546
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 13 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,11 @@ Main (unreleased)
### Features

- Add the function `path_join` to the stdlib. (@wildum)

- Add support to `loki.source.syslog` for the RFC3164 format ("BSD syslog"). (@sushain97)

- Add support to `loki.source.api` to be able to extract the tenant from the HTTP `X-Scope-OrgID` header (@QuentinBisson)
-
- (_Experimental_) Add a `loki.secretfilter` component to redact secrets from collected logs.

### Enhancements
Expand All @@ -31,6 +34,9 @@ Main (unreleased)

- Fix an issue where some `faro.receiver` would drop multiple fields defined in `payload.meta.browser`, as fields were defined in the struct.

- SNMP exporter now supports labels in both `target` and `targets` parameters. (@mattdurham)


### Bugfixes

- Fixed a bug in `import.git` which caused a `"non-fast-forward update"` error message. (@ptodev)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ The following labels can be set to a target:
* `auth`: The SNMP authentication profile to use.
* `walk_params`: The config to use for this target.

Any other labels defined are added to the scraped metrics.

## Blocks

The following blocks are supported inside the definition of
Expand All @@ -83,13 +85,15 @@ The following blocks are supported inside the definition of
The `target` block defines an individual SNMP target.
The `target` block may be specified multiple times to define multiple targets. The label of the block is required and will be used in the target's `job` label.

| Name | Type | Description | Default | Required |
| -------------- | -------- | --------------------------------------------------------------------- | ------- | -------- |
| `address` | `string` | The address of SNMP device. | | yes |
| `module` | `string` | SNMP module to use for polling. | `""` | no |
| `auth` | `string` | SNMP authentication profile to use. | `""` | no |
| `walk_params` | `string` | Config to use for this target. | `""` | no |
| `snmp_context` | `string` | Override the `context_name` parameter in the SNMP configuration file. | `""` | no |
| Name | Type | Description | Default | Required |
|----------------|---------------|-----------------------------------------------------------------------| ------- | -------- |
| `address` | `string` | The address of SNMP device. | | yes |
| `module` | `string` | SNMP module to use for polling. | `""` | no |
| `auth` | `string` | SNMP authentication profile to use. | `""` | no |
| `walk_params` | `string` | Config to use for this target. | `""` | no |
| `snmp_context` | `string` | Override the `context_name` parameter in the SNMP configuration file. | `""` | no |
| `labels` | `map(string)` | Map of labels to apply to all metrics captured from the target. | `""` | no |


### walk_param block

Expand Down Expand Up @@ -136,6 +140,9 @@ prometheus.exporter.snmp "example" {
address = "192.168.1.2"
module = "if_mib"
walk_params = "public"
labels = {
"env" = "dev",
}
}
target "network_router_2" {
Expand Down Expand Up @@ -227,6 +234,7 @@ prometheus.exporter.snmp "example" {
"address" = "192.168.1.2",
"module" = "if_mib",
"walk_params" = "public",
"env" = "dev",
},
{
"name" = "network_router_2",
Expand Down
38 changes: 32 additions & 6 deletions internal/component/prometheus/exporter/snmp/snmp.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package snmp
import (
"errors"
"fmt"
"slices"
"time"

"github.com/grafana/alloy/internal/component"
Expand Down Expand Up @@ -44,12 +45,17 @@ func buildSNMPTargets(baseTarget discovery.Target, args component.Arguments) []d

for _, tgt := range snmpTargets {
target := make(discovery.Target)
// Set extra labels first, meaning that any other labels will override
for k, v := range tgt.Labels {
target[k] = v
}
for k, v := range baseTarget {
target[k] = v
}

target["job"] = target["job"] + "/" + tgt.Name
target["__param_target"] = tgt.Target
target["__param_name"] = tgt.Name
if tgt.Module != "" {
target["__param_module"] = tgt.Module
}
Expand All @@ -71,12 +77,13 @@ func buildSNMPTargets(baseTarget discovery.Target, args component.Arguments) []d

// SNMPTarget defines a target to be used by the exporter.
type SNMPTarget struct {
Name string `alloy:",label"`
Target string `alloy:"address,attr"`
Module string `alloy:"module,attr,optional"`
Auth string `alloy:"auth,attr,optional"`
WalkParams string `alloy:"walk_params,attr,optional"`
SNMPContext string `alloy:"snmp_context,attr,optional"`
Name string `alloy:",label"`
Target string `alloy:"address,attr"`
Module string `alloy:"module,attr,optional"`
Auth string `alloy:"auth,attr,optional"`
WalkParams string `alloy:"walk_params,attr,optional"`
SNMPContext string `alloy:"snmp_context,attr,optional"`
Labels map[string]string `alloy:"labels,attr,optional"`
}

type TargetBlock []SNMPTarget
Expand All @@ -92,6 +99,7 @@ func (t TargetBlock) Convert() []snmp_exporter.SNMPTarget {
Auth: target.Auth,
WalkParams: target.WalkParams,
SNMPContext: target.SNMPContext,
Labels: target.Labels,
})
}
return targets
Expand Down Expand Up @@ -134,6 +142,22 @@ type Arguments struct {

type TargetsList []map[string]string

// target technically isnt required but its so overloaded within snmp I dont want it leaking.
var ignoredLabels = []string{"name", "module", "auth", "walk_params", "snmp_context", "address", "__address__", "target"}

func createUserLabels(t map[string]string) map[string]string {
// Need to create labels.
userLabels := make(map[string]string)
for k, v := range t {
// ignore the special labels
if slices.Contains(ignoredLabels, k) {
continue
}
userLabels[k] = v
}
return userLabels
}

func (t TargetsList) Convert() []snmp_exporter.SNMPTarget {
targets := make([]snmp_exporter.SNMPTarget, 0, len(t))
for _, target := range t {
Expand All @@ -145,6 +169,7 @@ func (t TargetsList) Convert() []snmp_exporter.SNMPTarget {
Auth: target["auth"],
WalkParams: target["walk_params"],
SNMPContext: target["snmp_context"],
Labels: createUserLabels(target),
})
}
return targets
Expand All @@ -161,6 +186,7 @@ func (t TargetsList) convert() []SNMPTarget {
Auth: target["auth"],
WalkParams: target["walk_params"],
SNMPContext: target["snmp_context"],
Labels: createUserLabels(target),
})
}
return targets
Expand Down
41 changes: 41 additions & 0 deletions internal/component/prometheus/exporter/snmp/snmp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,21 @@ func TestConvertConfig(t *testing.T) {
require.Equal(t, "network_switch_1", res.SnmpTargets[0].Name)
}

func TestConfigLabels(t *testing.T) {
lbls := map[string]string{"env": "dev"}
args := Arguments{
ConfigFile: "modules.yml",
Targets: TargetBlock{{Name: "network_switch_1", Target: "192.168.1.2", Module: "if_mib", Labels: lbls}},
WalkParams: WalkParams{{Name: "public", Retries: 2}},
}

res := args.Convert()
require.Equal(t, "modules.yml", res.SnmpConfigFile)
require.Equal(t, 1, len(res.SnmpTargets))
require.Equal(t, "network_switch_1", res.SnmpTargets[0].Name)
require.Equal(t, res.SnmpTargets[0].Labels["env"], "dev")
}

func TestConvertConfigWithInlineConfig(t *testing.T) {
args := Arguments{
ConfigStruct: config.Config{Modules: map[string]*config.Module{"if_mib": {Walk: []string{"1.3.6.1.2.1.2"}}}},
Expand Down Expand Up @@ -177,6 +192,32 @@ func TestConvertTargetsList(t *testing.T) {
require.Equal(t, "1.3.6.1.2.1.2", res[0].WalkParams)
}

func TestConvertTargetsListWithLabels(t *testing.T) {
targets := TargetsList{
{
"name": "network_switch_1",
"address": "192.168.1.2",
"module": "if_mib",
"auth": "public_v2",
"walk_params": "1.3.6.1.2.1.2",
"env": "dev",
"app": "falcon",
},
}

res := targets.Convert()
require.Equal(t, 1, len(res))
require.Equal(t, "network_switch_1", res[0].Name)
require.Equal(t, "192.168.1.2", res[0].Target)
require.Equal(t, "if_mib", res[0].Module)
require.Equal(t, "public_v2", res[0].Auth)
require.Equal(t, "1.3.6.1.2.1.2", res[0].WalkParams)
require.Len(t, res[0].Labels, 2)
require.Equal(t, "dev", res[0].Labels["env"])
require.Equal(t, "falcon", res[0].Labels["app"])

}

func TestConvertTargetsListAlternativeAddress(t *testing.T) {
targets := TargetsList{
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ func toSnmpExporter(config *snmp_exporter.Config) *snmp.Arguments {
target["auth"] = t.Auth
target["walk_params"] = t.WalkParams
target["snmp_context"] = t.SNMPContext
for k, v := range t.Labels {
target[k] = v
}
targets = append(targets, target)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ type SNMPTarget struct {
Auth string `yaml:"auth"`
WalkParams string `yaml:"walk_params,omitempty"`
SNMPContext string `yaml:"snmp_context,omitempty"`
Labels map[string]string
}

// Config configures the SNMP integration.
Expand Down

0 comments on commit dbda546

Please sign in to comment.