snmp_exporter
snmp_exporter copied to clipboard
Should we allow multiple modules per target?
This is an ongoing discussion between @SuperQ and I; input very much appreciated.
Pro:
- Less config bloat
- Allows for modular configs, which might be nice for modular chassis and such
Con:
- Non-obvious precedence, merging, etc
- Harder to debug
Neutral:
- Through https://github.com/prometheus/snmp_exporter/issues/619 and others, we may be able to reduce pressure on snmp.yml to be touched at all, thus reducing the need for any human to ever touch snmp.yml
Currently, @SuperQ is slightly in favor, I am slightly against, but could easily change. I am, however, strongly in favor of doing this later rather than sooner due to reduced pressure on snmp.yml.
Pro:
- Less config bloat for configurations that handle multiple versions of the same device: (ex. 24 port switch monitor only uplinks, 24 port switch monitor all ports, 24 port switch monitor all ports named "MON.*", etc.
Con:
- Code will get a bit more complexity to handle ordering the module data to an intermediate in-memory module config (my suggestion)
Implementation:
Must not introduce config complexity in prometheus.yml and its dependant targets.json files (ex. Due to having to provide a list of modules or other funky stuff) I would see an implementation that uses import module statements in the device module of generator.yml. The order of imports would impart the merging ordering logic. Doing it this way should not make it overly complexe to troubleshoot. As the generator would essentially build an intermediate module with all the sections ordered by the import order. This intermediate module would then be used to generate the output module for snmp.yml I hope this makes sense.
I like this idea, it reduces the manual config work and lets the generator do the heavy lifting. While I agree merging and such does become a pain but at the same time, a dumb merging strategy (no de-dup etc.) would mean the onus is on the user to ensure their generator input is sane.
It would be so much easier to be able to define e.g.:
metrics:
ifmib:
table: <oid>
ifbgp4:
table: <oid>
module:
juniper_switch:
metrics:
- ifmib
juniper_router:
metrics:
- ifmib
- ifbgp4
https://github.com/toni-moreno/snmpcollector actually does a very good job of defining SNMP objects and tables into metrics like this and allow you to collect them into "metric groups" for defining to devices.
Allowing multiple modules will be beneficial for the people to minimize level of effort and clear confusion
Hopefully, this feature will be implemented as soon as possible, because it really makes configuration work much easier!!!
I also like this. IF_MIB is IF_MIB; every vendor's IF_MIB is the same (or at least, it has a subset of the data - e.g. very old devices might not have ifXTable
)
The approach which occurred to me first was to specify multiple modules in a scrape request:
/snmp?target=x.x.x.x&module=foo&module=bar&module=baz
That maps nicely to an NMS front-end where you might just select a bunch of checkboxes for the modules to scrape for a particular target or target group.
The problem with this approach is that in a Prometheus scrape job, whilst you can specify multiple values for the same parameter statically, you cannot do it via relabelling (that is, __param_module
can only have a single value), making it harder to configure this dynamically.
You could allow an alternative way like a comma-separated list:
/snmp?target=x.x.x.x&module=foo,bar,baz
Actually, it's even possible out-of-the-box with today's snmp_exporter if you create three scrape jobs which scrape the same target for each module, but that's a pain to manage in prometheus.yml - every new module needs a new scrape job, and relabelling rules to drop the targets that shouldn't be scraped with that module.
Looking at @tardoe's approach, another option would be for one module to include/inherit other modules:
module:
ifmib:
table: <oid>
ifbgp4:
table: <oid>
juniper_switch:
include: [ifmib]
juniper_router:
include: [ifmib, ifbgp4]
juniper_ex4200_switch:
include: [juniper_switch]
table: <oid> # specific to this model
This still requires the user to pre-define every combination of MIBs that they want to use though.