Help us shape the future of Go! Take the 2026 Go Developer Survey

mikroscope

package module
v1.6.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 6, 2026 License: MIT Imports: 2 Imported by: 0

README

mikroscope

CI Quality gate Coverage Release Downloads Go Reference Go ghcr.io Docker Hub Agent platforms CLI platforms

Sub-second, kernel-level telemetry for container-capable MikroTik RouterOS devices: RouterOS 7.24 or later, on arm64, 32-bit ARM or x86_64. A static Go agent runs on the router, in a scratch container, and reads the shared kernel's /proc at 1 to 100 Hz, 10 by default — per-core CPU with the softirq split, softnet drops, interrupts per CPU — where an exporter that polls the RouterOS API, such as mktxp or mikrotik-exporter, reads cpu-load: all cores in one figure, a trailing mean of about one second on the RB5009 it was measured on. A CLI on your machine installs it, records a window with markers, draws the chart, or runs as a collector into eleven sinks, Prometheus and InfluxDB 3 among them. Two MIT-licensed binaries.

What the observer costs the router is measured rather than promised: at the 10 Hz install default the agent used 2.69 % of one core and 13.2 MiB of resident memory, read from its own cgroup, on an RB5009UG+S+ (4 × 1.4 GHz Cortex-A72, RouterOS 7.24.2) — one 300 s window at steady state, the shipped configuration, the collector forwarding to InfluxDB 3, on 2026-09-18. That is inside the project's ≤ 16 MiB memory budget and above its ≤ 2 % CPU one. The 2.85 % and 31.3 MiB that 1.0.0 published were measured with a 300 s ring, which 1.0.6 cut to 60 s: the memory fell with the ring, and 2.85 % against 2.69 % is the noise between two windows. None of it transfers to a board that is not this one: Agent cost says how the figure is taken and how to take it on your own device, and the rate ceiling has all six runs, from 10 to 100 Hz.

Install

curl -fsSL https://raw.githubusercontent.com/jmrplens/mikroscope/main/install.sh | bash

or, in PowerShell on Windows:

irm https://raw.githubusercontent.com/jmrplens/mikroscope/main/install.ps1 | iex

Either one works out the platform, takes the newest release, and refuses to install anything whose checksum is not the one the release published. On a terminal it then offers the other half — the agent, which runs on the router — and shows every RouterOS command before writing any of them.

Or build it yourself with go install github.com/jmrplens/mikroscope/cmd/mikroscope@latest, or take an archive from the releases page. Install the CLI has each platform step by step, with the checksum and the cosign signature.

Put the agent on the router

mikroscope doctor  --router admin@192.168.88.1   # read-only; names the fix for anything missing
mikroscope install --router admin@192.168.88.1   # lists every command, asks, then writes
mikroscope status  --router admin@192.168.88.1   # what is installed, and whether it answers

On a router that already runs the agent, doctor also reads the samples its ring still holds and reports a layer-2 loop, STP churn or a flapping link by port, and softnet drops by CPU. Those findings and its other WARN lines (a registry credential meant for another registry, an agent published on the LAN without a token) never change its exit status.

install builds the agent from this repository if you have Go. Without it, add --remote-image jmrplens/mikroscope-agent:latest and the router pulls the image itself from Docker Hub — nothing is uploaded and there is no architecture to choose. The registry host travels inside the reference (registry-1.docker.io/…), so the router's global /container/config needs no change and no registry login. Pin the version instead of latest for a deployment you want to be able to reproduce. Install methods covers the others: the image tar, a RouterOS script (or the site's script generator) for a device you reach only through WebFig or Winbox, and the whole install by hand, in the terminal or through WebFig's menus. mikroscope uninstall removes whatever any of them created.

Two things the tool cannot do for you: RouterOS 7.24 or later, and device-mode container=yes, which MikroTik gates behind a physical reset-button press or a power cycle. Requirements is that list, and mikroscope doctor checks all of it against your own device, the RouterOS version included.

Use it

export MIKROSCOPE_ROUTER=admin@192.168.88.1

# Record a window and draw it
mikroscope record --for 5m --out cap    # cap.jsonl, cap.csv, cap.markers.csv
mikroscope mark --out cap "queue tree applied"
mikroscope plot --in cap                # cap.svg, deterministic

# Or keep it running, into a store and a dashboard
export GRAFANA_TOKEN=…
mikroscope forward \
  --influx http://influx:8181 --influx-db mikroscope \
  --grafana http://grafana:3000        # creates the datasource and publishes the dashboard

Or take a stack whole: deploy/ has two compose files, each a collector and somewhere for it to write, plus a Grafana. The InfluxDB one publishes its dashboard on start once GRAFANA_TOKEN is in .env; the Prometheus one needs the dashboard imported, and its README gives both ways.

docker compose -f deploy/compose.influxdb-grafana.yaml up -d

forward writes to eleven sinks — the file, Prometheus, InfluxDB 3, Loki, OTLP, Graphite, Elasticsearch, PostgreSQL both as a script and down a connection, Telegraf and standard output — and merges the kernel tier with the RouterOS API tier as it goes. First recording is the whole path once, end to end.

What it draws

Five Grafana dashboards, one per store Grafana can query, generated from a single panel list and shipped in the repository. forward --grafana creates the datasource and publishes the one for the store it writes to, at start, before the first sample.

Beside them, dashboards/ ships Grafana alert rules for InfluxDB, PostgreSQL and Prometheus (14, 10 and 15 rules): counters that should not move, a bridge port the bridge has stopped delivering to, and a wake-up storm judged against the device's own previous day rather than a fixed number. Alert rules lists them.

The overview, which every dashboard opens with — is this router healthy right now, and can these numbers be believed:

And the receive path, which is the section the kernel tier exists for — softnet backlog, drops, time squeezes and per-CPU budget, none of which the RouterOS API can see:

Both are a run of the canned fake agent the end-to-end suites use, written into a container store and photographed by the site's own script. The host is called rb5009 because the fake imitates that board's captured /proc, and the figures are whatever the fake publishes: read them as the shape of the page, never as a measurement. They were captured on 2026-09-17, before 1.2.0 turned the overview's memory gauge into a time series and fixed the size of the stat numbers, and have not been recaptured since.

The five dashboards, section by section, with a capture of each.

Where it has been verified

Device Versioned profile Tested on real hardware
MikroTik RB5009UG+S+ (arm64, RouterOS 7.24.2 measured; 7.24.4 install round trip, 2026-09-21) yes yes

Everything else the project builds for — 32-bit ARM and x86 RouterOS — is cross-compiled and CI-checked and has never run on hardware. Tested on is the measurement behind each claim. If you run mikroscope on another board, mikroscope status names it, and that plus what you measured is everything a pull request needs to add a row, or a board report if you would rather someone else wrote it.

Documentation

All of it is at https://jmrp.io/docs/mikroscope/, in English and Spanish.

Using it

  • Quick install — the CLI, doctor, the agent and a check, in four commands
  • First recording — record, mark and plot, the whole path once
  • Install methods — the CLI, the script generator, a RouterOS script, by hand in the terminal or WebFig, offline; upgrade and uninstall
  • Configure — network access, the two firewall traps, storage and container settings, the API user
  • Record, mark and plot — recording, markers, charts, triggered capture
  • Run the collector — the eleven sinks, the RouterOS API tier, the derive stage
  • Dashboards — the five dashboards, publishing them, alert rules
  • Diagnose faults — the signature of each fault, and the checks to make before trusting a reading
  • Troubleshooting — the symptoms this produces, in the words you actually see

Knowing what to trust

  • Agent cost — the observer's own CPU and memory, the rate ceiling, the tick floor
  • How it works — the agent, the collector and the data path between them
  • Resolution limits — namespaces, privileged, the per-source floors
  • Security model — what runs where, the API user, what --expose opens, what the installer refuses
  • Tested on — the devices, RouterOS versions and dates behind each claim, what has not been tested, and the known issues
  • Case studies — an idle router first, then six faults read against it on the router they were measured on

Reference

Contributing

CONTRIBUTING.md has the layout, the test suites, the virtual RouterOS lab they test the deployment in, and which one to run for which change. Questions go to Discussions; a bug, a board report, a feature request and a documentation defect each have an issue form. The Markdown under docs/ is generated from the site's English pages — change the page and its Spanish twin, then run pnpm run docs in site/.

Lineage: the deployment steps, the dockerless image builder and the vendored RouterOS API client come from cmd/perfmon and internal/rosapi in cs-routeros-bouncer (MIT), with attribution in each package.

License: MIT.

Documentation

Overview

Package mikroscope exists for one reason: it is the only package that can read the repository's VERSION file at compile time.

A go:embed directive cannot reach outside its own package directory, and VERSION sits at the module root because everything that has to agree on a release number reads it from there: the Makefile, GoReleaser's agent image tars and the release workflow's preflight, which refuses to release when the pushed tag and the file disagree. A package at the root can embed it; nothing under cmd/ or internal/ can.

Without this, a build nobody stamped reports "dev". That was true of every `go build`, every `go run ./cmd/mikroscope image` and therefore of every agent image tar built from one, because the real number only ever arrived through the release ldflags, and a plausible wrong version is not something anyone notices on a router.

Index

Constants

This section is empty.

Variables

View Source
var Version = strings.TrimSpace(versionFile)

Version is the release this build was compiled from. It is the floor, never a guess: release ldflags may still override what a command reports, which is what happens when a tag names a number the file has not caught up with yet.

Functions

This section is empty.

Types

This section is empty.

Directories

Path Synopsis
cmd
gen_brand command
Command gen_brand writes the mikroscope mark, and the compositions built on it.
Command gen_brand writes the mikroscope mark, and the compositions built on it.
gen_rsc command
Command gen_rsc writes the steps spec and its case matrix for the site's install script generator and manual install pages, which render RouterOS commands from them instead of keeping a copy of their own:
Command gen_rsc writes the steps spec and its case matrix for the site's install script generator and manual install pages, which render RouterOS commands from them instead of keeping a copy of their own:
mikroscope command
Command mikroscope is the operator-side CLI: it installs the agent on a RouterOS device, removes it, shows what it would write, and — from Phase 5 and 6 on — records, plots and forwards.
Command mikroscope is the operator-side CLI: it installs the agent on a RouterOS device, removes it, shows what it would write, and — from Phase 5 and 6 on — records, plots and forwards.
mikroscope-agent command
Command mikroscope-agent runs on the RouterOS device, inside a scratch container, and samples the shared kernel's /proc at a fixed rate into a ring buffer it serves over HTTP on the veth.
Command mikroscope-agent runs on the RouterOS device, inside a scratch container, and samples the shared kernel's /proc at a fixed rate into a ring buffer it serves over HTTP on the veth.
mikroscope-lab command
Command mikroscope-lab drives the virtual RouterOS lab: MikroTik's Cloud Hosted Router under QEMU in a Docker container, which every RouterOS test of the project runs against (test/lab/README.md).
Command mikroscope-lab drives the virtual RouterOS lab: MikroTik's Cloud Hosted Router under QEMU in a Docker container, which every RouterOS test of the project runs against (test/lab/README.md).
internal
agent
Package agent is what runs on the router: a sampler that reads /proc at a fixed rate into a ring buffer, and an HTTP server on the veth that hands the ring out as NDJSON and as Prometheus text.
Package agent is what runs on the router: a sampler that reads /proc at a fixed rate into a ring buffer, and an HTTP server on the veth that hands the ring out as NDJSON and as Prometheus text.
apitier
Package apitier samples what the container cannot see, over one persistent RouterOS API connection at 1 Hz: per-core load as RouterOS reports it, memory, health, interface rates, and, opt-in at its own cadence, the conntrack count.
Package apitier samples what the container cannot see, over one persistent RouterOS API connection at 1 Hz: per-core load as RouterOS reports it, memory, health, interface rates, and, opt-in at its own cadence, the conntrack count.
chart
Package chart draws a recording as a deterministic SVG: three panels on one time axis — per-core busy ratio, softnet drops and time squeezes per second, memory available — with the recording's markers as dashed verticals.
Package chart draws a recording as a deterministic SVG: three panels on one time axis — per-core busy ratio, softnet drops and time squeezes per second, memory available — with the recording's markers as dashed verticals.
dashboards
Package dashboards generates the Grafana dashboards, one per store, in the shareable export format: a `${DS_…}` datasource placeholder declared in `__inputs`, a fixed `uid` so a re-import updates in place, and `__requires` for the directory listing.
Package dashboards generates the Grafana dashboards, one per store, in the shareable export format: a `${DS_…}` datasource placeholder declared in `__inputs`, a fixed `uid` so a re-import updates in place, and `__requires` for the directory listing.
derive
Package derive is the collector's derive stage: what can be computed from the samples with no cost on the device, identically for every sink, and with state across samples that a query language expresses badly and a sink cannot express at all.
Package derive is the collector's derive stage: what can be computed from the samples with no cost on the device, identically for every sink, and with state across samples that a query language expresses badly and a sink cannot express at all.
forward
Package forward is the collector: it pulls the kernel tier from the agent, samples the API tier at 1 Hz, stamps both in the agent's clock and fans the merged timeline out to sinks.
Package forward is the collector: it pulls the kernel tier from the agent, samples the API tier at 1 Hz, stamps both in the agent's clock and fans the merged timeline out to sinks.
health
Package health reads a window of the agent's samples and names the faults it shows: the ones that are happening NOW, in the ring the agent still holds.
Package health reads a window of the agent's samples and names the faults it shows: the ones that are happening NOW, in the ring the agent still holds.
image
Package image builds the agent's container image without Docker: a cross-compiled static binary packed into a docker-save-format tar that RouterOS's `/container/add file=` accepts.
Package image builds the agent's container image without Docker: a cross-compiled static binary packed into a docker-save-format tar that RouterOS's `/container/add file=` accepts.
lab
Package lab drives the virtual RouterOS lab: MikroTik's Cloud Hosted Router under QEMU in a Docker container, provisioned once into a clean snapshot (the container package installed, device-mode container=yes confirmed) and put back to it in seconds.
Package lab drives the virtual RouterOS lab: MikroTik's Cloud Hosted Router under QEMU in a Docker container, provisioned once into a clean snapshot (the container package installed, device-mode container=yes confirmed) and put back to it in seconds.
lab/vm
Package vm is the lab container's side of the virtual RouterOS lab: what runs inside `mikroscope-lab-<arch>` as its PID 1, and what runs inside the throwaway container `mikroscope-lab cli` starts in the lab's network namespace.
Package vm is the lab container's side of the virtual RouterOS lab: what runs inside `mikroscope-lab-<arch>` as its PID 1, and what runs inside the throwaway container `mikroscope-lab cli` starts in the lab's network namespace.
procfs
Package procfs parses the /proc files the mikroscope agent samples into typed counters.
Package procfs parses the /proc files the mikroscope agent samples into typed counters.
record
Package record is the diagnostician's path: pull samples from the agent for a window, write them as JSONL (verbatim) and CSV (wide), and keep a marker file where every line typed on stdin, every gap and — opt-in — every router log line lands with the agent's timestamp, so "what happened at 14:03" has an answer.
Package record is the diagnostician's path: pull samples from the agent for a window, write them as JSONL (verbatim) and CSV (wide), and keep a marker file where every line typed on stdin, every gap and — opt-in — every router log line lands with the agent's timestamp, so "what happened at 14:03" has an answer.
rosapi
Package routeros is a pure Go client library for accessing Mikrotik devices using the RouterOS API.
Package routeros is a pure Go client library for accessing Mikrotik devices using the RouterOS API.
router
Package router deploys the mikroscope agent to a RouterOS device and removes it again, with the containment rules inherited from cs-routeros-bouncer cmd/perfmon (PR #123): every object created carries one exact comment tag, every removal selects by that tag plus the object's identity — never by pattern — and uninstall verifies by ownership counts before it reports success.
Package router deploys the mikroscope agent to a RouterOS device and removes it again, with the containment rules inherited from cs-routeros-bouncer cmd/perfmon (PR #123): every object created carries one exact comment tag, every removal selects by that tag plus the object's identity — never by pattern — and uninstall verifies by ownership counts before it reports success.
sample
Package sample defines what one tick of the mikroscope agent produces: the deltas of every counter since the previous tick, plus the few absolute values that are not counters.
Package sample defines what one tick of the mikroscope agent produces: the deltas of every counter since the previous tick, plus the few absolute values that are not counters.
sinks
Package sinks receives the merged timeline — kernel-tier samples at the agent's rate, API-tier samples at 1 Hz, gaps — and writes it somewhere: a JSONL file, a Prometheus /metrics, InfluxDB 3 line protocol.
Package sinks receives the merged timeline — kernel-tier samples at the agent's rate, API-tier samples at 1 Hz, gaps — and writes it somewhere: a JSONL file, a Prometheus /metrics, InfluxDB 3 line protocol.
teardown
Package teardown removes what a collector left in a store.
Package teardown removes what a collector left in a store.
transport
Package transport reaches the agent's HTTP from the operator host.
Package transport reaches the agent's HTTP from the operator host.
version
Package version carries the build identity both binaries report.
Package version carries the build identity both binaries report.
test
e2e/fakeagent
Package fakeagent is a stand-in for the mikroscope agent: the HTTP paths a deployment reads — /healthz, /capabilities, /snapshot, /stream and the /metrics a Prometheus scrapes — serving canned samples built from internal/sample's own types rather than from hand-written JSON, so a field that is renamed in the sample cannot quietly stop being tested here.
Package fakeagent is a stand-in for the mikroscope agent: the HTTP paths a deployment reads — /healthz, /capabilities, /snapshot, /stream and the /metrics a Prometheus scrapes — serving canned samples built from internal/sample's own types rather than from hand-written JSON, so a field that is renamed in the sample cannot quietly stop being tested here.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL