DEV Community

DevKit
DevKit

Posted on

Monitoring MikroTik RouterOS with snmp_exporter and Grafana: CPU, memory, traffic, errors, and five PromQL alerts

A MikroTik router often runs for years unnoticed, until something feels slow. This post shows how to get RouterOS metrics into Prometheus over SNMP, what to watch, and five starter alert rules.

The examples use a free Grafana dashboard, MikroTik RouterOS Lite: https://grafana.com/grafana/dashboards/26041/ . Every metric name below comes from the dashboard JSON. The dashboard JSON supports snmp_exporter only; mikrotik-exporter uses different metric names and is not covered.

Set up SNMP and the exporter

Enable SNMP on the router (IP -> SNMP), set your own community or SNMPv3 user, and restrict access to the exporter's address.

The JSON queries use sysUpTime, ifHCInOctets, ifHCOutOctets, ifInErrors, ifOutErrors, ifInDiscards, ifOutDiscards, ifOperStatus, ifAdminStatus, ifHighSpeed (with the ifName label), plus hrProcessorLoad, hrStorageUsed and hrStorageSize (with hrStorageDescr). A generator.yml module that produces them:

modules:
  routeros:
    walk: [sysUpTime, ifTable, ifXTable, hrProcessorLoad, hrStorageTable]
    lookups:
      - source_indexes: [ifIndex]
        lookup: ifName
      - source_indexes: [hrStorageIndex]
        lookup: hrStorageDescr
        drop_source_indexes: true
    overrides:
      ifName: {type: DisplayString}
Enter fullscreen mode Exit fullscreen mode

Generate snmp.yml, add an auth with your credentials, then scrape:

scrape_configs:
  - job_name: mikrotik
    metrics_path: /snmp
    params: {module: [routeros], auth: [YOUR_SNMP_AUTH]}
    static_configs: [{targets: ["192.0.2.1", "192.0.2.2"]}]
    relabel_configs:
      - {source_labels: [__address__], target_label: __param_target}
      - {source_labels: [__param_target], target_label: instance}
      - {target_label: __address__, replacement: "snmp-exporter:9116"}
Enter fullscreen mode Exit fullscreen mode

Import dashboard 26041 in Grafana and pick your Prometheus data source for DS_PROMETHEUS.

What to watch

  • Reachability: up{job=~"$job"}. If SNMP stops answering, up is 0 even when the router still pings. A panel in the JSON also uses snmp_scrape_duration_seconds.
  • Uptime: sysUpTime is in hundredths of a second, so in the JSON it is divided by 100. A sudden small minimum means an unexpected reboot.
  • CPU: hrProcessorLoad, averaged per router. On multi-core models, check the raw per-core values if the average looks calm but things are slow.
  • Memory and storage: 100 * hrStorageUsed / hrStorageSize. RouterOS lists memory and disks as separate rows, told apart by hrStorageDescr.
  • Traffic: rate(ifHCInOctets[...]) * 8 and the same for out, shown in the JSON as top-N interfaces. A utilisation panel in the JSON divides by ifHighSpeed * 1000000, ignoring interfaces where speed is 0.
  • Errors and discards: rates of ifInErrors, ifOutErrors, ifInDiscards, ifOutDiscards. Steady errors on a physical port usually point to a cable, duplex or SFP issue.
  • Port state: ifOperStatus == 2 and ifAdminStatus == 1 finds ports that are enabled but have no link.

Temperature and voltage are not in this dashboard JSON and not in the module above, so I do not cover them here.

Five alert rules

Thresholds are starting points. Tune them after watching your own graphs for a couple of weeks.

groups:
  - name: mikrotik
    rules:
      - alert: MikrotikSnmpDown
        expr: up{job="mikrotik"} == 0
        for: 3m
        labels: {severity: critical}

      - alert: MikrotikCpuHigh
        expr: avg by (instance) (hrProcessorLoad{job="mikrotik"}) > 85
        for: 10m
        labels: {severity: warning}

      - alert: MikrotikMemoryHigh
        expr: |
          100 * hrStorageUsed{job="mikrotik", hrStorageDescr=~".*memory.*"}
              / hrStorageSize{job="mikrotik", hrStorageDescr=~".*memory.*"} > 90
        for: 10m
        labels: {severity: warning}

      - alert: MikrotikInterfaceErrors
        expr: |
          sum by (instance, ifName) (
            rate(ifInErrors{job="mikrotik"}[5m]) + rate(ifOutErrors{job="mikrotik"}[5m])
          ) > 1
        for: 10m
        labels: {severity: warning}

      - alert: MikrotikPortDown
        expr: ifOperStatus{job="mikrotik"} == 2 and ifAdminStatus{job="mikrotik"} == 1
        for: 5m
        labels: {severity: warning}
Enter fullscreen mode Exit fullscreen mode

Check which hrStorageDescr values your router returns before relying on the memory regex. Exclude intentionally empty but enabled ports by ifName.

Common problems

  • Empty dashboard: the module and auth in the scrape config must match snmp.yml, and SNMP must be allowed from the exporter's address.
  • Missing ifName or hrStorageDescr labels: the generator lookups did not apply.

Links

Dashboard: https://grafana.com/grafana/dashboards/26041/

Alert templates and related material: https://t.me/devkit_shop_bot?start=gf_mikrotik_article

Top comments (0)