Skip to content

mikroscope

The RouterOS API reports CPU load once a second. mikroscope runs on the router, in a container, and reads the kernel's own counters at 1 to 100 Hz — for whoever has to say what a MikroTik device did inside that second. Two MIT-licensed binaries, and what the observer costs the router measured rather than promised, first thing below.

Measured, not budgeted

The first three from the agent's own cgroup and /metrics, the fourth from the three sinks the collector forwarded to, on an RB5009 (4 × 1.4 GHz Cortex-A72, RouterOS 7.24.2), 60 s windows at steady state, 2026-09-15. The 10 Hz figures are above the ≤ 2 % and ≤ 16 MiB budget.

A one-second average is a report about a second

The RouterOS API reports cpu-load once a second. A core saturated for 100 ms and idle for the other 900 moves a four-core, one-second average by 2.5 %. That is arithmetic, not a measurement, and the figure is true: it just cannot say when.

The agent reads /proc/stat, /proc/interrupts, /proc/softirqs and /proc/net/softnet_stat from inside the router, at 10 Hz by default, and ships raw tick deltas with the interval each one covers. It never computes a percentage; the window is yours.

The floor is the kernel's, not the tool's. /proc/stat counts in ticks of 10 ms, so a 100 ms sample resolves one core to 10 % steps. On the RB5009 (RouterOS 7.24.2, Linux 5.6.3) there is no PSI and no schedstat to go finer: both files are absent, checked 2026-09-11.

What it costs, at three rates

Each row is one 60 s window with the ring already full. Memory differs by row because the ring and the memory limit do.

Measured on RB5009UG+S+ · 4 × 1.4 GHz Cortex-A72 · RouterOS 7.24.2 · · 60 s windows at steady state (ring full), full source set, collector forwarding to a file, a Prometheus exposition and InfluxDB 3 at once

The measured runs
ratefloorsCPU of one coreµs/sampleRSSslipped ticksgaps / drops
10 Hz (default)default2.85 %2 85631.3 MiB00 / 0
50 Hzdefault10.13 %2 02651.9 MiB00 / 0
100 Hzdefault17.81 %1 78176.5 MiB5 (0.08 %)0 / 0

Nothing was lost at any of these rates: every sink reported 0 gaps and 0 drops, and the delivered rate matched the configured one to three figures. At the default floors and 100 Hz, a whole tick's sources were read in under 2 ms for 97.5 % of samples, inside a 10 ms period.

All five runs, including every source on every tick →

The router's CPU from the kernel, its interfaces from the API

Kernel tier · the agent · 10 to 100 Hz

Global inside the container, so these are the router's own: per-core CPU ticks, interrupts, softirqs, softnet drops and time squeezes, /proc/meminfo, /proc/vmstat, load and disk I/O. A privileged container adds the kernel log as timestamped events and the global slab caches.

API tier · the collector · 1 Hz

The container has its own network namespace, so /proc/net/dev describes the container, not the router. Interface bytes and packets come from the RouterOS API and are merged by the collector, not interpolated. privileged=yes does not change that (checked 2026-09-12).

Every write listed before it is made

Download the archive for your platform from the release, or build the CLI from a checkout with make build. The router needs RouterOS 7.24 or later — the container step writes privileged=, an attribute earlier 7.x releases reject — with the container package and device-mode container=yes, which MikroTik gates behind a reset-button press or a power cycle. arm64, arm and x86_64; not MIPS, not TILE.

  1. mikroscope doctor

    Read-only preflight; names the fix for anything missing.

  2. mikroscope plan

    Every RouterOS command, nothing written.

  3. mikroscope install

    Doctor, confirmation, the writes, then a probe of the agent. The image comes from your own Go toolchain, from the published agent tar, or from the registry the router pulls it from.

  4. mikroscope status

    Ownership counts and the agent's health.

  5. mikroscope uninstall

    Removes and verifies.

What install writes to your router

  • a veth
  • one address
  • one interface-list membership
  • one address-list entry
  • an envlist
  • the image tar, unless --remote-image has the router pull the image
  • the container

Every object carries the comment mikroscope:<name> (managed by mikroscope)

mikroscope plan prints every command before anything is written.

uninstall removes by exact tag plus identity, never by pattern, and fails naming the step if anything remains.

What is not claimed

Where to go next