diff --git a/CHANGELOG.md b/CHANGELOG.md index 7ea545a3531d..0480ade1dac4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -48,6 +48,9 @@ Main (unreleased) - A new `loki.rules.kubernetes` component that discovers `PrometheusRule` Kubernetes resources and loads them into a Loki Ruler instance. (@EStork09) +- A new `snmp_context` configuration argument for `prometheus.exporter.snmp` and the `snmp` Static mode integration. + It overrides the `context_name` parameter in the SNMP configuration file. (@ptodev) + ### Bugfixes - Fix panic for `prometheus.exporter.snmp` and snmp_exporter integration diff --git a/docs/make-docs b/docs/make-docs index 0a1730e6c6fe..f531df2ebb17 100755 --- a/docs/make-docs +++ b/docs/make-docs @@ -6,6 +6,17 @@ # [Semantic versioning](https://semver.org/) is used to help the reader identify the significance of changes. # Changes are relevant to this script and the support docs.mk GNU Make interface. # +# ## 8.0.0 (2024-05-28) +# +# ### Changed +# +# - Add environment variable `OUTPUT_FORMAT` to control the output of commands. +# +# The default value is `human` and means the output format is human readable. +# The value `json` is also supported and outputs JSON. +# +# Note that the `json` format isn't supported by `make docs`, only `make doc-validator` and `make vale`. +# # ## 7.0.0 (2024-05-03) # # ### Changed @@ -255,6 +266,8 @@ readonly HUGO_REFLINKSERRORLEVEL="${HUGO_REFLINKSERRORLEVEL:-WARNING}" readonly VALE_MINALERTLEVEL="${VALE_MINALERTLEVEL:-error}" readonly WEBSITE_EXEC="${WEBSITE_EXEC:-make server-docs}" +readonly OUTPUT_FORMAT="${OUTPUT_FORMAT:-human}" + PODMAN="$(if command -v podman >/dev/null 2>&1; then echo podman; else echo docker; fi)" if ! command -v curl >/dev/null 2>&1; then @@ -748,45 +761,74 @@ POSIX_HERESTRING case "${image}" in 'grafana/doc-validator') - if ! command -v jq >/dev/null 2>&1; then - errr '`jq` must be installed for the `doc-validator` target to work.' - note 'To install `jq`, refer to https://jqlang.github.io/jq/download/,' - - exit 1 - fi - proj="$(new_proj "$1")" printf '\r\n' - "${PODMAN}" run \ + + IFS='' read -r cmd </dev/null 2>&1; then + errr '`jq` must be installed for the `doc-validator` target to work.' + note 'To install `jq`, refer to https://jqlang.github.io/jq/download/,' + + exit 1 + fi + + ${cmd} \ + | jq -r '"ERROR: \(.location.path):\(.location.range.start.line // 1):\(.location.range.start.column // 1): \(.message)" + if .suggestions[0].text then "\nSuggestion: \(.suggestions[0].text)" else "" end' + ;; + json) + ${cmd} + ;; + *) # default + errr "Invalid output format '${OUTPUT_FORMAT}'" + esac ;; 'grafana/vale') proj="$(new_proj "$1")" printf '\r\n' - "${PODMAN}" run \ + IFS='' read -r cmd < | default = ""] + + # snmp_context overrides the `context_name` parameter in the SNMP configuration file. + [snmp_context: | default = ""] ``` ## walk_param config diff --git a/docs/sources/static/configuration/integrations/snmp-config.md b/docs/sources/static/configuration/integrations/snmp-config.md index d4b519782f8b..b52beafe9ea8 100644 --- a/docs/sources/static/configuration/integrations/snmp-config.md +++ b/docs/sources/static/configuration/integrations/snmp-config.md @@ -15,7 +15,7 @@ which is an embedded version of [`snmp_exporter`](https://github.com/prometheus/snmp_exporter). This allows collection of SNMP metrics from the network devices with ease. {{< admonition type="note" >}} -`snmp config` uses the latest configuration introduced in version 0.23 of the Prometheus `snmp_exporter`. +`snmp config` uses the latest configuration introduced in version 0.26 of the Prometheus `snmp_exporter`. {{< /admonition >}} ## Quick configuration example @@ -167,6 +167,9 @@ Full reference of options: # walk_param config to use for this snmp_target [walk_params: | default = ""] + + # snmp_context overrides the `context_name` parameter in the SNMP configuration file. + [snmp_context: | default = ""] ``` ## walk_param config diff --git a/go.mod b/go.mod index 35e8a9cae92e..dba9e3f36199 100644 --- a/go.mod +++ b/go.mod @@ -50,7 +50,7 @@ require ( github.com/google/dnsmasq_exporter v0.2.1-0.20230620100026-44b14480804a github.com/google/go-cmp v0.6.0 github.com/google/go-jsonnet v0.18.0 - github.com/google/pprof v0.0.0-20240117000934-35fc243c5815 + github.com/google/pprof v0.0.0-20240227163752-401108e1b7e7 github.com/google/renameio/v2 v2.0.0 github.com/google/uuid v1.6.0 github.com/gorilla/mux v1.8.1 @@ -61,7 +61,7 @@ require ( github.com/grafana/loki v1.6.2-0.20240510183741-cef4c2826b4b // k190 branch github.com/grafana/pyroscope-go/godeltaprof v0.1.7 github.com/grafana/pyroscope/api v0.4.0 - github.com/grafana/pyroscope/ebpf v0.4.3 + github.com/grafana/pyroscope/ebpf v0.4.6 github.com/grafana/regexp v0.0.0-20221123153739-15dc172cd2db github.com/grafana/river v0.3.1-0.20240123144725-960753160cd1 github.com/grafana/snowflake-prometheus-exporter v0.0.0-20221213150626-862cad8e9538 @@ -216,14 +216,14 @@ require ( go.uber.org/multierr v1.11.0 go.uber.org/zap v1.27.0 golang.org/x/crypto v0.22.0 - golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc - golang.org/x/net v0.23.0 + golang.org/x/exp v0.0.0-20240119083558-1b970713d09a + golang.org/x/net v0.24.0 golang.org/x/oauth2 v0.18.0 golang.org/x/sys v0.19.0 golang.org/x/text v0.14.0 golang.org/x/time v0.5.0 google.golang.org/api v0.155.0 - google.golang.org/grpc v1.62.0 + google.golang.org/grpc v1.62.1 google.golang.org/protobuf v1.33.0 gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v3 v3.0.1 @@ -310,9 +310,6 @@ require ( github.com/checkpoint-restore/go-criu/v5 v5.3.0 // indirect github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58 // indirect github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa // indirect - github.com/containerd/console v1.0.3 // indirect - github.com/containerd/containerd v1.7.11 // indirect - github.com/containerd/continuity v0.4.2 // indirect github.com/containerd/ttrpc v1.2.2 // indirect github.com/coreos/go-semver v0.3.1 // indirect github.com/cpuguy83/dockercfg v0.3.1 // indirect @@ -325,7 +322,6 @@ require ( github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/digitalocean/godo v1.104.1 // indirect - github.com/dimchansky/utfbom v1.1.1 github.com/docker/cli v24.0.0+incompatible // indirect github.com/docker/distribution v2.8.2+incompatible // indirect github.com/docker/go-units v0.5.0 // indirect @@ -579,14 +575,14 @@ require ( golang.org/x/mod v0.14.0 // indirect golang.org/x/sync v0.6.0 // indirect golang.org/x/term v0.19.0 // indirect - golang.org/x/tools v0.16.1 + golang.org/x/tools v0.17.0 golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect gonum.org/v1/gonum v0.14.0 // indirect google.golang.org/appengine v1.6.8 // indirect google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240125205218-1f4bbc51befe // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240125205218-1f4bbc51befe // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240304161311-37d4d3c04a78 // indirect gopkg.in/alecthomas/kingpin.v2 v2.2.6 // indirect gopkg.in/fsnotify/fsnotify.v1 v1.4.7 // indirect gopkg.in/inf.v0 v0.9.1 // indirect @@ -604,6 +600,7 @@ require github.com/ianlancetaylor/demangle v0.0.0-20230524184225-eabc099b10ab // require ( connectrpc.com/connect v1.14.0 github.com/Shopify/sarama v1.38.1 + github.com/dimchansky/utfbom v1.1.1 github.com/githubexporter/github-exporter v0.0.0-20231025122338-656e7dc33fe7 github.com/grafana/agent-remote-config v0.0.2 github.com/grafana/jfr-parser/pprof v0.0.0-20240126072739-986e71dc0361 @@ -645,6 +642,9 @@ require ( github.com/channelmeter/iso8601duration v0.0.0-20150204201828-8da3af7a2a61 // indirect github.com/cloudflare/circl v1.3.7 // indirect github.com/containerd/cgroups/v3 v3.0.2 // indirect + github.com/containerd/console v1.0.3 // indirect + github.com/containerd/containerd v1.7.11 // indirect + github.com/containerd/continuity v0.4.2 // indirect github.com/containerd/errdefs v0.1.0 // indirect github.com/containerd/log v0.1.0 // indirect github.com/dgryski/go-metro v0.0.0-20180109044635-280f6062b5bc // indirect diff --git a/go.sum b/go.sum index 58076ea2f25a..9cc619280431 100644 --- a/go.sum +++ b/go.sum @@ -971,8 +971,8 @@ github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20211214055906-6f57359322fd/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg= -github.com/google/pprof v0.0.0-20240117000934-35fc243c5815 h1:WzfWbQz/Ze8v6l++GGbGNFZnUShVpP/0xffCPLL+ax8= -github.com/google/pprof v0.0.0-20240117000934-35fc243c5815/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= +github.com/google/pprof v0.0.0-20240227163752-401108e1b7e7 h1:y3N7Bm7Y9/CtpiVkw/ZWj6lSlDF3F74SfKwfTCer72Q= +github.com/google/pprof v0.0.0-20240227163752-401108e1b7e7/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/renameio/v2 v2.0.0 h1:UifI23ZTGY8Tt29JbYFiuyIU3eX+RNFtUwefq9qAhxg= github.com/google/renameio/v2 v2.0.0/go.mod h1:BtmJXm5YlszgC+TD4HOEEUFgkJP3nLxehU6hfe7jRt4= @@ -1063,8 +1063,8 @@ github.com/grafana/pyroscope-go/godeltaprof v0.1.7 h1:C11j63y7gymiW8VugJ9ZW0pWfx github.com/grafana/pyroscope-go/godeltaprof v0.1.7/go.mod h1:Tk376Nbldo4Cha9RgiU7ik8WKFkNpfds98aUzS8omLE= github.com/grafana/pyroscope/api v0.4.0 h1:J86DxoNeLOvtJhB1Cn65JMZkXe682D+RqeoIUiYc/eo= github.com/grafana/pyroscope/api v0.4.0/go.mod h1:MFnZNeUM4RDsDOnbgKW3GWoLSBpLzMMT9nkvhHHo81o= -github.com/grafana/pyroscope/ebpf v0.4.3 h1:gPfm2FKabdycRfFIej/s0awSzsbAaoSefaehrZ1OGJY= -github.com/grafana/pyroscope/ebpf v0.4.3/go.mod h1:Iv66aj9WsDWR8bGMPQzCQPCgVgCru0KizGrbcR3YmLk= +github.com/grafana/pyroscope/ebpf v0.4.6 h1:8A6vddwCF2q8XXrOebFuDczr9xOHCfqPN2QwIkXKxgU= +github.com/grafana/pyroscope/ebpf v0.4.6/go.mod h1:0iOWpGm2M6KXiP2nGa4wf02knSSjEtu11vpUOdQT5AY= github.com/grafana/regexp v0.0.0-20221123153739-15dc172cd2db h1:7aN5cccjIqCLTzedH7MZzRZt5/lsAHch6Z3L2ZGn5FA= github.com/grafana/regexp v0.0.0-20221123153739-15dc172cd2db/go.mod h1:M5qHK+eWfAv8VR/265dIuEpL3fNfeC21tXXp9itM24A= github.com/grafana/river v0.3.1-0.20240123144725-960753160cd1 h1:mCOKdWkLv8n9X0ORWrPR+W/zLOAa1o6iM+Dfy0ofQUs= @@ -2501,8 +2501,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc h1:ao2WRsKSzW6KuUY9IWPwWahcHCgR0s52IfwutMfEbdM= -golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI= +golang.org/x/exp v0.0.0-20240119083558-1b970713d09a h1:Q8/wZp0KX97QFTc2ywcOE0YRjZPVIx+MXInMzdvQqcA= +golang.org/x/exp v0.0.0-20240119083558-1b970713d09a/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08= golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= @@ -2605,8 +2605,8 @@ golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ= -golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= -golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= +golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= golang.org/x/oauth2 v0.0.0-20170807180024-9a379c6b3e95/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -2881,8 +2881,8 @@ golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.16.1 h1:TLyB3WofjdOEepBHAU20JdNC1Zbg87elYofWYAY5oZA= -golang.org/x/tools v0.16.1/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0= +golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc= +golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -3010,8 +3010,8 @@ google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80 h1:KAeGQVN3M9nD0/b google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80/go.mod h1:cc8bqMqtv9gMOr0zHg2Vzff5ULhhL2IXP4sbcn32Dro= google.golang.org/genproto/googleapis/api v0.0.0-20240125205218-1f4bbc51befe h1:0poefMBYvYbs7g5UkjS6HcxBPaTRAmznle9jnxYoAI8= google.golang.org/genproto/googleapis/api v0.0.0-20240125205218-1f4bbc51befe/go.mod h1:4jWUdICTdgc3Ibxmr8nAJiiLHwQBY0UI0XZcEMaFKaA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240125205218-1f4bbc51befe h1:bQnxqljG/wqi4NTXu2+DJ3n7APcEA882QZ1JvhQAq9o= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240125205218-1f4bbc51befe/go.mod h1:PAREbraiVEVGVdTZsVWjSbbTtSyGbAgIIvni8a8CD5s= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240304161311-37d4d3c04a78 h1:Xs9lu+tLXxLIfuci70nG4cpwaRC+mRQPUL7LoIeDJC4= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240304161311-37d4d3c04a78/go.mod h1:UCOku4NytXMJuLQE5VuqA5lX3PcHCBo8pxNyvkf4xBs= google.golang.org/grpc v0.0.0-20180920234847-8997b5fa0873/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= @@ -3048,8 +3048,8 @@ google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnD google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k= -google.golang.org/grpc v1.62.0 h1:HQKZ/fa1bXkX1oFOvSjmZEUL8wLSaZTjCcLAlmZRtdk= -google.golang.org/grpc v1.62.0/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= +google.golang.org/grpc v1.62.1 h1:B4n+nfKzOICUXMgyrNd19h/I9oH0L1pizfk1d4zSgTk= +google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= diff --git a/internal/component/prometheus/exporter/snmp/snmp.go b/internal/component/prometheus/exporter/snmp/snmp.go index aa855e8bd662..d2991c292064 100644 --- a/internal/component/prometheus/exporter/snmp/snmp.go +++ b/internal/component/prometheus/exporter/snmp/snmp.go @@ -51,6 +51,9 @@ func buildSNMPTargets(baseTarget discovery.Target, args component.Arguments) []d if tgt.WalkParams != "" { target["__param_walk_params"] = tgt.WalkParams } + if tgt.SNMPContext != "" { + target["__param_snmp_context"] = tgt.SNMPContext + } if tgt.Auth != "" { target["__param_auth"] = tgt.Auth } @@ -63,11 +66,12 @@ func buildSNMPTargets(baseTarget discovery.Target, args component.Arguments) []d // SNMPTarget defines a target to be used by the exporter. type SNMPTarget struct { - Name string `river:",label"` - Target string `river:"address,attr"` - Module string `river:"module,attr,optional"` - Auth string `river:"auth,attr,optional"` - WalkParams string `river:"walk_params,attr,optional"` + Name string `river:",label"` + Target string `river:"address,attr"` + Module string `river:"module,attr,optional"` + Auth string `river:"auth,attr,optional"` + WalkParams string `river:"walk_params,attr,optional"` + SNMPContext string `river:"snmp_context,attr,optional"` } type TargetBlock []SNMPTarget @@ -77,11 +81,12 @@ func (t TargetBlock) Convert() []snmp_exporter.SNMPTarget { targets := make([]snmp_exporter.SNMPTarget, 0, len(t)) for _, target := range t { targets = append(targets, snmp_exporter.SNMPTarget{ - Name: target.Name, - Target: target.Target, - Module: target.Module, - Auth: target.Auth, - WalkParams: target.WalkParams, + Name: target.Name, + Target: target.Target, + Module: target.Module, + Auth: target.Auth, + WalkParams: target.WalkParams, + SNMPContext: target.SNMPContext, }) } return targets diff --git a/internal/component/prometheus/exporter/snmp/snmp_test.go b/internal/component/prometheus/exporter/snmp/snmp_test.go index 6d5a0e97d7d2..3e2d3dddd239 100644 --- a/internal/component/prometheus/exporter/snmp/snmp_test.go +++ b/internal/component/prometheus/exporter/snmp/snmp_test.go @@ -21,6 +21,7 @@ func TestUnmarshalRiver(t *testing.T) { module = "if_mib" walk_params = "public" auth = "public_v2" + snmp_context = "testcontext" } target "network_router_2" { address = "192.168.1.3" @@ -45,6 +46,7 @@ func TestUnmarshalRiver(t *testing.T) { require.Contains(t, "if_mib", args.Targets[0].Module) require.Contains(t, "public", args.Targets[0].WalkParams) require.Contains(t, "public_v2", args.Targets[0].Auth) + require.Contains(t, "testcontext", args.Targets[0].SNMPContext) require.Contains(t, "network_router_2", args.Targets[1].Name) require.Contains(t, "192.168.1.3", args.Targets[1].Target) @@ -88,10 +90,11 @@ func TestConvertConfigWithInlineConfig(t *testing.T) { func TestConvertTargets(t *testing.T) { targets := TargetBlock{{ - Name: "network_switch_1", - Target: "192.168.1.2", - Module: "if_mib", - Auth: "public_v2", + Name: "network_switch_1", + Target: "192.168.1.2", + Module: "if_mib", + Auth: "public_v2", + SNMPContext: "testcontext", }} res := targets.Convert() @@ -100,6 +103,7 @@ func TestConvertTargets(t *testing.T) { 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, "testcontext", res[0].SNMPContext) } func TestConvertWalkParams(t *testing.T) { diff --git a/internal/component/pyroscope/ebpf/args.go b/internal/component/pyroscope/ebpf/args.go index f2620fedd446..e19cef3a9abd 100644 --- a/internal/component/pyroscope/ebpf/args.go +++ b/internal/component/pyroscope/ebpf/args.go @@ -1,6 +1,7 @@ package ebpf import ( + "errors" "time" "github.com/grafana/agent/internal/component/discovery" @@ -21,4 +22,18 @@ type Arguments struct { CollectKernelProfile bool `river:"collect_kernel_profile,attr,optional"` Demangle string `river:"demangle,attr,optional"` PythonEnabled bool `river:"python_enabled,attr,optional"` + SymbolsMapSize int `river:"symbols_map_size,attr,optional"` + PIDMapSize int `river:"pid_map_size,attr,optional"` +} + +// Validate implements syntax.Validator. +func (arg *Arguments) Validate() error { + var errs []error + if arg.SymbolsMapSize <= 0 { + errs = append(errs, errors.New("symbols_map_size must be greater than 0")) + } + if arg.PIDMapSize <= 0 { + errs = append(errs, errors.New("pid_map_size must be greater than 0")) + } + return errors.Join(errs...) } diff --git a/internal/component/pyroscope/ebpf/ebpf_linux.go b/internal/component/pyroscope/ebpf/ebpf_linux.go index 41f48431f528..ac987c8c6d2d 100644 --- a/internal/component/pyroscope/ebpf/ebpf_linux.go +++ b/internal/component/pyroscope/ebpf/ebpf_linux.go @@ -66,13 +66,10 @@ func New(opts component.Options, args Arguments) (component.Component, error) { return res, nil } -func (rc *Arguments) UnmarshalRiver(f func(interface{}) error) error { - *rc = defaultArguments() - type config Arguments - return f((*config)(rc)) -} +var DefaultArguments = NewDefaultArguments() -func defaultArguments() Arguments { +// NewDefaultArguments create the default settings for a scrape job. +func NewDefaultArguments() Arguments { return Arguments{ CollectInterval: 15 * time.Second, SampleRate: 97, @@ -85,9 +82,16 @@ func defaultArguments() Arguments { CollectKernelProfile: true, Demangle: "none", PythonEnabled: true, + SymbolsMapSize: 2048, + PIDMapSize: 16384, } } +// SetToDefault implements syntax.Defaulter. +func (arg *Arguments) SetToDefault() { + *arg = NewDefaultArguments() +} + type Component struct { options component.Options args Arguments @@ -251,5 +255,9 @@ func convertSessionOptions(args Arguments, ms *metrics) ebpfspy.SessionOptions { KeepRounds: args.CacheRounds, }, }, + BPFMapsOptions: ebpfspy.BPFMapsOptions{ + SymbolsMapSize: uint32(args.SymbolsMapSize), + PIDMapSize: uint32(args.PIDMapSize), + }, } } diff --git a/internal/component/pyroscope/ebpf/ebpf_linux_test.go b/internal/component/pyroscope/ebpf/ebpf_linux_test.go index 1a7db5e31c40..6f92463ca4ef 100644 --- a/internal/component/pyroscope/ebpf/ebpf_linux_test.go +++ b/internal/component/pyroscope/ebpf/ebpf_linux_test.go @@ -9,16 +9,20 @@ import ( "testing" "time" - "github.com/grafana/agent/internal/component" - "github.com/grafana/agent/internal/component/pyroscope" - "github.com/grafana/agent/internal/util" ebpfspy "github.com/grafana/pyroscope/ebpf" "github.com/grafana/pyroscope/ebpf/pprof" "github.com/grafana/pyroscope/ebpf/sd" - "github.com/grafana/river" + "github.com/grafana/pyroscope/ebpf/symtab" + "github.com/grafana/pyroscope/ebpf/symtab/elf" + syntax "github.com/grafana/river" "github.com/oklog/run" "github.com/prometheus/client_golang/prometheus" "github.com/stretchr/testify/require" + + "github.com/grafana/agent/internal/component" + "github.com/grafana/agent/internal/component/discovery" + "github.com/grafana/agent/internal/component/pyroscope" + "github.com/grafana/agent/internal/util" ) type mockSession struct { @@ -67,7 +71,36 @@ func (m *mockSession) CollectProfiles(f pprof.CollectProfilesCallback) error { } func (m *mockSession) DebugInfo() interface{} { - return nil + return ebpfspy.SessionDebugInfo{ + ElfCache: symtab.ElfCacheDebugInfo{ + BuildIDCache: symtab.GCacheDebugInfo[elf.SymTabDebugInfo]{}, + SameFileCache: symtab.GCacheDebugInfo[elf.SymTabDebugInfo]{ + LRUSize: 10, + RoundSize: 10, + CurrentRound: 1, + LRUDump: []elf.SymTabDebugInfo{ + { + Name: "X", + Size: 123, + LastUsedRound: 1, + }, + }, + }, + }, + PidCache: symtab.GCacheDebugInfo[symtab.ProcTableDebugInfo]{ + LRUSize: 10, + RoundSize: 10, + CurrentRound: 1, + LRUDump: []symtab.ProcTableDebugInfo{ + { + Pid: 666, + Size: 123, + }, + }, + }, + Arch: "my-arch", + Kernel: "my-kernel", + } } func TestShutdownOnError(t *testing.T) { @@ -78,7 +111,7 @@ func TestShutdownOnError(t *testing.T) { }) require.NoError(t, err) session := &mockSession{} - arguments := defaultArguments() + arguments := NewDefaultArguments() arguments.CollectInterval = time.Millisecond * 100 c := newTestComponent( component.Options{ @@ -105,7 +138,7 @@ func TestContextShutdown(t *testing.T) { }) require.NoError(t, err) session := &mockSession{} - arguments := defaultArguments() + arguments := NewDefaultArguments() arguments.CollectInterval = time.Millisecond * 100 c := newTestComponent( component.Options{ @@ -150,8 +183,34 @@ func TestContextShutdown(t *testing.T) { } func TestUnmarshalConfig(t *testing.T) { - var arg Arguments - err := river.Unmarshal([]byte(`targets = [{"service_name" = "foo", "container_id"= "cid"}] + for _, tt := range []struct { + name string + in string + expected func() Arguments + expectedErr string + }{ + { + name: "required-params-only", + in: ` +targets = [{"service_name" = "foo", "container_id"= "cid"}] +forward_to = [] +`, + expected: func() Arguments { + x := NewDefaultArguments() + x.Targets = []discovery.Target{ + map[string]string{ + "container_id": "cid", + "service_name": "foo", + }, + } + x.ForwardTo = []pyroscope.Appendable{} + return x + }, + }, + { + name: "full-config", + in: ` +targets = [{"service_name" = "foo", "container_id"= "cid"}] forward_to = [] collect_interval = "3s" sample_rate = 239 @@ -161,34 +220,131 @@ same_file_cache_size = 3000 container_id_cache_size = 4000 cache_rounds = 4 collect_user_profile = true -collect_kernel_profile = false`), &arg) - require.NoError(t, err) - require.Empty(t, arg.ForwardTo) - require.Equal(t, time.Second*3, arg.CollectInterval) - require.Equal(t, 239, arg.SampleRate) - require.Equal(t, 1000, arg.PidCacheSize) - require.Equal(t, 2000, arg.BuildIDCacheSize) - require.Equal(t, 3000, arg.SameFileCacheSize) - require.Equal(t, 4000, arg.ContainerIDCacheSize) - require.Equal(t, 4, arg.CacheRounds) - require.Equal(t, true, arg.CollectUserProfile) - require.Equal(t, false, arg.CollectKernelProfile) -} - -func TestUnmarshalBadConfig(t *testing.T) { - var arg Arguments - err := river.Unmarshal([]byte(`targets = [{"service_name" = "foo", "container_id"= "cid"}] +collect_kernel_profile = false`, + expected: func() Arguments { + x := NewDefaultArguments() + x.Targets = []discovery.Target{ + map[string]string{ + "container_id": "cid", + "service_name": "foo", + }, + } + x.ForwardTo = []pyroscope.Appendable{} + x.CollectInterval = time.Second * 3 + x.SampleRate = 239 + x.PidCacheSize = 1000 + x.BuildIDCacheSize = 2000 + x.SameFileCacheSize = 3000 + x.ContainerIDCacheSize = 4000 + x.CacheRounds = 4 + x.CollectUserProfile = true + x.CollectKernelProfile = false + return x + }, + }, + { + name: "syntax-problem", + in: ` +targets = [{"service_name" = "foo", "container_id"= "cid"}] forward_to = [] collect_interval = 3s" -sample_rate = 239 -pid_cache_size = 1000 -build_id_cache_size = 2000 -same_file_cache_size = 3000 -container_id_cache_size = 4000 -cache_rounds = 4 -collect_user_profile = true -collect_kernel_profile = false`), &arg) - require.Error(t, err) +`, + expectedErr: "4:21: expected TERMINATOR, got IDENT (and 1 more diagnostics)", + }, + { + name: "incorrect-map-sizes", + in: ` +targets = [{"service_name" = "foo", "container_id"= "cid"}] +forward_to = [] +symbols_map_size = -1 +pid_map_size = 0 +`, + expectedErr: "symbols_map_size must be greater than 0\npid_map_size must be greater than 0", + }, + } { + t.Run(tt.name, func(t *testing.T) { + arg := Arguments{} + if tt.expectedErr != "" { + err := syntax.Unmarshal([]byte(tt.in), &arg) + require.Error(t, err) + require.Equal(t, tt.expectedErr, err.Error()) + return + } + require.NoError(t, syntax.Unmarshal([]byte(tt.in), &arg)) + require.Equal(t, tt.expected(), arg) + }) + } +} + +type mockTargetFinder struct { + sd.TargetFinder +} + +func (m *mockTargetFinder) DebugInfo() []map[string]string { + return []map[string]string{ + {"__container_id__": "foo", "__name__": "process_cpu", "container": "kube-proxy"}, + {"__container_id__": "baz", "__name__": "process_cpu", "container": "kube-proxy"}, + } +} + +func TestDebugInfo(t *testing.T) { + c := &Component{ + session: &mockSession{}, + targetFinder: &mockTargetFinder{}, + } + + c.updateDebugInfo() + di := c.DebugInfo() + + v, err := syntax.Marshal(di) + require.NoError(t, err) + + require.Equal(t, `targets = [{ + __container_id__ = "foo", + __name__ = "process_cpu", + container = "kube-proxy", +}, { + __container_id__ = "baz", + __name__ = "process_cpu", + container = "kube-proxy", +}] +session = { + elf_cache = { + build_id_cache = { + lru_size = 0, + round_size = 0, + current_round = 0, + lru_dump = [], + round_dump = [], + }, + same_file_cache = { + lru_size = 10, + round_size = 10, + current_round = 1, + lru_dump = [{ + name = "X", + symbol_count = 123, + file = "", + last_used_round = 1, + }], + round_dump = [], + }, + }, + pid_cache = { + lru_size = 10, + round_size = 10, + current_round = 1, + lru_dump = [{ + elfs = {}, + size = 123, + pid = 666, + last_used_round = 0, + }], + round_dump = [], + }, + arch = "my-arch", + kernel = "my-kernel", +}`, string(v)) } func newTestComponent(opts component.Options, args Arguments, session *mockSession, targetFinder sd.TargetFinder, ms *metrics) *Component { diff --git a/internal/converter/internal/staticconvert/internal/build/snmp_exporter.go b/internal/converter/internal/staticconvert/internal/build/snmp_exporter.go index cd6a8f9f9237..69d26b267eed 100644 --- a/internal/converter/internal/staticconvert/internal/build/snmp_exporter.go +++ b/internal/converter/internal/staticconvert/internal/build/snmp_exporter.go @@ -19,11 +19,12 @@ func toSnmpExporter(config *snmp_exporter.Config) *snmp.Arguments { targets := make([]snmp.SNMPTarget, len(config.SnmpTargets)) for i, t := range config.SnmpTargets { targets[i] = snmp.SNMPTarget{ - Name: common.SanitizeIdentifierPanics(t.Name), - Target: t.Target, - Module: t.Module, - Auth: t.Auth, - WalkParams: t.WalkParams, + Name: common.SanitizeIdentifierPanics(t.Name), + Target: t.Target, + Module: t.Module, + Auth: t.Auth, + WalkParams: t.WalkParams, + SNMPContext: t.SNMPContext, } } @@ -67,11 +68,12 @@ func toSnmpExporterV2(config *snmp_exporter_v2.Config) *snmp.Arguments { targets := make([]snmp.SNMPTarget, len(config.SnmpTargets)) for i, t := range config.SnmpTargets { targets[i] = snmp.SNMPTarget{ - Name: common.SanitizeIdentifierPanics(t.Name), - Target: t.Target, - Module: t.Module, - Auth: t.Auth, - WalkParams: t.WalkParams, + Name: common.SanitizeIdentifierPanics(t.Name), + Target: t.Target, + Module: t.Module, + Auth: t.Auth, + WalkParams: t.WalkParams, + SNMPContext: t.SNMPContext, } } diff --git a/static/integrations/snmp_exporter/snmp_exporter.go b/static/integrations/snmp_exporter/snmp_exporter.go index 47754801e02a..2d0f3aa82f09 100644 --- a/static/integrations/snmp_exporter/snmp_exporter.go +++ b/static/integrations/snmp_exporter/snmp_exporter.go @@ -27,11 +27,12 @@ var DefaultConfig = Config{ // SNMPTarget defines a target device to be used by the integration. type SNMPTarget struct { - Name string `yaml:"name"` - Target string `yaml:"address"` - Module string `yaml:"module"` - Auth string `yaml:"auth"` - WalkParams string `yaml:"walk_params,omitempty"` + Name string `yaml:"name"` + Target string `yaml:"address"` + Module string `yaml:"module"` + Auth string `yaml:"auth"` + WalkParams string `yaml:"walk_params,omitempty"` + SNMPContext string `yaml:"snmp_context,omitempty"` } // Config configures the SNMP integration. @@ -199,6 +200,9 @@ func (i *Integration) ScrapeConfigs() []config.ScrapeConfig { if target.WalkParams != "" { queryParams.Add("walk_params", target.WalkParams) } + if target.SNMPContext != "" { + queryParams.Add("snmp_context", target.SNMPContext) + } res = append(res, config.ScrapeConfig{ JobName: i.sh.cfg.Name() + "/" + target.Name, MetricsPath: "/metrics", diff --git a/static/integrations/v2/snmp_exporter/snmp.go b/static/integrations/v2/snmp_exporter/snmp.go index 071c0de4c7e9..4283e9525c56 100644 --- a/static/integrations/v2/snmp_exporter/snmp.go +++ b/static/integrations/v2/snmp_exporter/snmp.go @@ -68,6 +68,12 @@ func (sh *snmpHandler) Targets(ep integrations.Endpoint) []*targetgroup.Group { }) } + if t.SNMPContext != "" { + labelSet = labelSet.Merge(model.LabelSet{ + "__param_snmp_context": model.LabelValue(t.SNMPContext), + }) + } + if t.Auth != "" { labelSet = labelSet.Merge(model.LabelSet{ "__param_auth": model.LabelValue(t.Auth),