Prometheus Network Monitoring

By NetMon Hub Editorial ·

Official site · Latest version: 3.13.0

Prometheus for Network Monitoring

Prometheus is a pull-based metrics platform that has become the default observability choice for cloud-native infrastructure. Network engineers sometimes dismiss it as “a Kubernetes thing”, which is understandable — most tutorials are container-centric. But the scrape model maps surprisingly well onto SNMP polling, and the combination of Prometheus + snmp_exporter + Grafana gives you a fully open-source network observability stack with no per-device licensing.

This page covers what that stack actually looks like, where it performs well, and where you should look elsewhere.


How Prometheus collects metrics

Prometheus scrapes targets over HTTP at a configured interval. Each target exposes a /metrics endpoint returning labelled time-series data in Prometheus exposition format. The server stores those samples in its local TSDB (time-series database) and makes them queryable via PromQL.

That pull model has a practical consequence for network monitoring: your routers and switches cannot expose a /metrics endpoint. You need an exporter — a process that speaks SNMP toward the device and speaks Prometheus exposition format toward the Prometheus server.

Prometheus server

     │  GET /snmp?target=192.0.2.1&module=if_mib

snmp_exporter  ←──── SNMP GET/GETBULK ────► router / switch

The exporter is stateless. Prometheus passes the device address as a query parameter on each scrape, so a single snmp_exporter instance can fan out across hundreds of devices without maintaining persistent state per device.

Scrape interval vs SNMP polling interval: these are the same thing. Set scrape_interval in the Prometheus job and that determines how often SNMP counters are read. Fifteen seconds is common for interface counters; 60–300 seconds for environmental or BGP state. Going below 10 seconds rarely gains you anything and increases load on control-plane CPUs.


snmp_exporter in practice

snmp_exporter (current release: 0.30.1, as of July 2026) translates SNMP OIDs into Prometheus metrics. It is driven by a snmp.yml config file that maps MIBs to metric names and label sets.

Generating snmp.yml

Writing snmp.yml by hand is not the intended workflow. The project ships a generator that reads MIB files and outputs the config automatically:

# clone the generator, not the exporter
git clone https://github.com/prometheus/snmp_exporter
cd snmp_exporter/generator

# install MIBs (example: net-snmp defaults + vendor MIBs)
apt-get install snmp-mibs-downloader   # or brew install net-snmp on macOS
cp /path/to/vendor/CISCO-IF-EXTENSION-MIB.my mibs/

# edit generator.yml to select modules + OIDs, then:
go run . generate

The output snmp.yml lands in the current directory. Commit it alongside your exporter deployment. The generator is documented at snmp_exporter/generator/README.md.

A minimal Prometheus scrape job

# prometheus.yml

scrape_configs:
  - job_name: "snmp_network"
    static_configs:
      - targets:
          - 192.0.2.1   # core-sw-01
          - 192.0.2.2   # core-sw-02
    metrics_path: /snmp
    params:
      module: [if_mib]
    relabel_configs:
      - source_labels: [__address__]
        target_label: __param_target
      - source_labels: [__param_target]
        target_label: instance
      - target_label: __address__
        replacement: snmp-exporter:9116   # the exporter's address

The relabel_configs block is boilerplate for every SNMP job: it rewrites __address__ so Prometheus hits the exporter, not the device, while preserving the device IP as the instance label.

For dynamic environments, replace static_configs with a file-based SD block pointing to a JSON/YAML inventory, or use a service-discovery integration (Consul, EC2, etc.).

What IF-MIB gives you out of the box

The bundled if_mib module covers ifTable and ifXTable:

MetricOIDNotes
ifHCInOctets1.3.6.1.2.1.31.1.1.1.664-bit in-bytes counter
ifHCOutOctets1.3.6.1.2.1.31.1.1.1.1064-bit out-bytes counter
ifOperStatus1.3.6.1.2.1.2.2.1.81=up, 2=down, 7=lowerLayerDown
ifInErrors / ifOutErrors.14 / .20Error counters
ifInDiscards / ifOutDiscards.13 / .19Drop counters

Vendor-specific MIBs (CISCO-PROCESS-MIB, JUNIPER-MIB, etc.) require adding modules in generator.yml.


Querying with PromQL

PromQL is a functional query language. The learning curve is real, but for network metrics you need roughly four patterns.

Interface utilisation (%)

# ingress utilisation on a 1 Gbps interface
100 * (
  rate(ifHCInOctets{instance="192.0.2.1", ifDescr="GigabitEthernet0/1"}[5m]) * 8
)
/ 1e9

rate() computes per-second delta from a counter, averaged over the window. Multiply by 8 to convert bytes → bits. Divide by link speed in bps. The [5m] window should be at least 2–3× your scrape interval.

Warning: rate() assumes monotonically increasing counters and handles wraps correctly for 64-bit counters. For 32-bit ifInOctets/ifOutOctets, wraps occur at ~4 GB — not uncommon on a 1 Gbps port within an hour. Always prefer ifHCInOctets/ifHCOutOctets where the device supports them.

Interface error rate

rate(ifInErrors{instance="192.0.2.1"}[5m])
  / rate(ifHCInOctets{instance="192.0.2.1"}[5m])

Top-N interfaces by throughput

topk(10,
  rate(ifHCInOctets[5m]) * 8
)

Alerting: interface down

# alerts/network.yml
groups:
  - name: network_interfaces
    rules:
      - alert: InterfaceDown
        expr: ifOperStatus{ifDescr!~"Loopback.*"} == 2
        for: 2m
        labels:
          severity: warning
        annotations:
          summary: "Interface {{ $labels.ifDescr }} down on {{ $labels.instance }}"

The for: 2m guard prevents flap noise. Remove it only if your scrape interval is already 60 s+.


Grafana integration

Prometheus is Grafana’s native data source. Add it under Connections → Data sources → Prometheus, set the URL to your Prometheus server, and you’re querying immediately.

For network dashboards, the community SNMP / Network Stats dashboard (ID 11169) is a reasonable starting point — import it, adjust the job and instance variables to match your label scheme, then modify from there. Treat it as a template, not a finished product; the variable queries often need tuning for non-default label names.

Grafana’s Transformations panel is worth knowing for network work: Group By lets you aggregate across all interfaces per device without writing extra PromQL.


When this stack fits

Good fit:

Poor fit:


Retention and scaling considerations

Default Prometheus local retention is 15 days. Set --storage.tsdb.retention.time to suit your needs; 90 days is workable on modest hardware for a pure-network SNMP dataset (counter-only series compress well).

For longer retention or multi-site federation, remote-write to a long-term storage backend:

All three accept Prometheus remote-write and are queryable from Grafana without changing your dashboard PromQL.


Quick-start checklist

  1. Deploy snmp_exporter 0.30.1 (release notes) — single binary or Docker image.
  2. Run the generator against your MIBs; commit the resulting snmp.yml.
  3. Add a snmp_network scrape job to prometheus.yml using the relabel pattern above.
  4. Verify in Prometheus UI: up{job="snmp_network"} should show 1 per device.
  5. Import Grafana dashboard 11169; adjust variables.
  6. Write alert rules for ifOperStatus == 2 and high error rates.
  7. Configure remote-write if retention > 15 days.

FAQ

Does snmp_exporter support SNMPv3? Yes. Configure auth and priv fields in the module’s walk section of snmp.yml. The generator supports v3 auth via generator.yml — see the generator auth docs.

How do I monitor BGP session state with Prometheus? Add the BGP4-MIB (RFC 4271) to your generator config. bgpPeerState (OID 1.3.6.1.2.1.15.3.1.2) returns an integer; alert when it drops below 6 (established). Vendor-specific BGP MIBs give you prefix counts and AS paths.

Can Prometheus replace my existing SNMP trap receiver? No. Prometheus is poll-based; it does not receive unsolicited trap messages. Run a separate trap receiver (snmptrapd, Elastalert, or your NMS) alongside it.

What scrape interval should I use? For interface counters, 15–30 seconds is the common choice. For CPU/memory/environment, 60 seconds is usually sufficient. Check your device’s SNMP agent documentation — some lower-end switches struggle to respond to SNMP polls faster than once per 30 seconds under load.

Is Prometheus suitable for monitoring hundreds of devices? Yes, with caveats. A single Prometheus server handles thousands of devices comfortably if you control cardinality. The risk is label explosion: avoid high-cardinality labels like per-MAC-address or per-BGP-prefix. At 500+ devices, consider sharding by site/region into multiple Prometheus servers behind Thanos or Mimir.


Sources & further reading


Internal links: see also SolarWinds SWQL to DDSQL conversion — interface utilisation for a worked PromQL comparison example; Grafana overview for dashboard configuration depth.