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}
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"}
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,upis 0 even when the router still pings. A panel in the JSON also usessnmp_scrape_duration_seconds. -
Uptime:
sysUpTimeis 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 byhrStorageDescr. -
Traffic:
rate(ifHCInOctets[...]) * 8and the same for out, shown in the JSON as top-N interfaces. A utilisation panel in the JSON divides byifHighSpeed * 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 == 1finds 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}
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
authin the scrape config must matchsnmp.yml, and SNMP must be allowed from the exporter's address. - Missing
ifNameorhrStorageDescrlabels: the generatorlookupsdid 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)