Device info
At start the agent works out what it can about the board it runs on, with no RouterOS API
and no credential, and serves it on /capabilities. The collector hands that to every
sink as its own record: what it holds, when it is sent and where each sink puts it.
Contents
Section titled “Contents”- Identity: the device tree’s model string (the board), the kernel, the core count, whether the container is privileged and whether it has cgroup2, the enabled sources, the port table’s provenance, and a hash of the kernel, the core count and the enabled sources.
- The device’s own ceilings, read once at agent start: each thermal zone’s critical
trip point and polling delay; each core’s cpufreq range, frequency ladder, governor and
cluster; the kernel’s conntrack ceiling; the container’s own
memory.max. - Cadences: the rate each level source is read and stored at, and the named reason it is not the sampler rate.
A ceiling the board does not publish is left out, never filled with a number from somewhere else: every ceiling in the record is the device’s own reading.
Cadence reasons
Section titled “Cadence reasons”reason | What it means |
|---|---|
rate | read at the full sampler rate; nothing the device declares justifies less |
declared | the device publishes its own refresh cadence, and reading faster returns the same value with new dither |
policy | a setting says the value cannot move on its own: a userspace cpufreq governor |
budget | a measured parse cost |
change | read every tick, stored only when it moves |
override | FLOOR_HZ is set, and every level source is on its one cadence |
Scroll sideways to see every column
Counters are never floored; only level sources carry a cadence. The floors themselves are on Source cadences.
When it is sent
Section titled “When it is sent”When forward starts, whenever the agent’s capability hash changes — an agent restarted
with another source set, for example — and otherwise every five minutes. The collector
checks the hash on the health read it makes every minute to re-measure the clock skew, so
a change reaches the sinks within about a minute. Both the direct and the relay transport
can fetch /capabilities; when the fetch fails the collector logs it, sends nothing, and
tries again at the next health read. Nothing sent is absence, not a board with no facts.
Why it repeats. These facts are rows with the collector’s timestamp, so a store holds
them only at the instants they were sent, and a dashboard window that contains no
emission contains no facts at all: sent once at start, the four device panels would read
“No data” over every window after it. Five minutes puts the facts inside any window worth
reading them over and costs, per emission, one row for the identity, one per thermal zone,
one per core with cpufreq facts and one per level source, against the 864 000 sample rows
a day that --rate 10 produces.
The repeat is marked as one, and the sinks split on it: the stores write it like any
other row, so every window holds the facts, and the streams meant for a reader — Loki, stdout,
a recording — skip it, because a log is for change. So Loki still carries exactly one
device line per set of facts.
The hash covers only the kernel string, the core count and the enabled source names; the
board, privileged, cgroup, the port table’s provenance, every ceiling and every cadence
are left out of it. A restarted agent whose only change is a ceiling or a cadence — a new
--memory-max, or a FLOOR_HZ with the same source set — keeps its hash, so the change
is not what triggers the send; it reaches the sinks at the next five-minute repeat, and
the row that carries it is stamped then rather than when it happened. This is read from
the code (capsHash in internal/agent/source.go) and not observed
(Tested on).
These are facts, not samples. They have no clock of their own, so the sinks that
timestamp records stamp them with the collector’s clock when they were sent; the file and
stdout json lines carry no timestamp, and Prometheus renders them at scrape. They are
never mixed into a sample row.
Storage per sink
Section titled “Storage per sink”| Sink | Form |
|---|---|
InfluxDB, Telegraf, stdout lp |
mikroscope_, mikroscope_, mikroscope_, mikroscope_ |
SQL (--sql, --postgres) |
the tables mikroscope_device, mikroscope_, mikroscope_, mikroscope_ |
file, stdout json |
a {"device":…} line holding the capabilities as fetched |
| Elasticsearch | a document with kind: device |
| Graphite | the numeric facts under device.*; board, kernel and governor have no Graphite form |
| OTLP | gauges: mikroscope.device.cores with board, kernel and hash as attributes, the thermal and cpufreq ceilings, mikroscope. |
| Loki | one source="device", level="info" line: board, kernel, cores, privileged, cgroup, sources, hash |
| Prometheus | the device-info families, rendered by the collector’s exposition |
Scroll sideways to see every column
InfluxDB and SQL
Section titled “InfluxDB and SQL”| Measurement or table | Identified by | Holds |
|---|---|---|
mikroscope_device |
board, kernel |
cores, privileged, cgroup, sources (comma-joined, sorted), hash, conntrack_max, cgroup_mem_max, ports_from |
mikroscope_ |
zone |
critical_celsius, polling_ms |
mikroscope_ |
cpu |
cluster (the lowest-numbered core that changes frequency with this one), min_khz, max_khz, governor, steps |
mikroscope_ |
source, reason |
hz |
Scroll sideways to see every column
In InfluxDB board and kernel are tags, unknown when empty; in SQL they are columns,
NULL when empty, and a ceiling that was not published is NULL. steps is the frequency
ladder as a space-joined list of kHz.
Prometheus
Section titled “Prometheus”| Family | Carries |
|---|---|
mikroscope_ |
always 1 |
mikroscope_ |
the zone’s lowest critical trip |
mikroscope_ |
the zone’s polling delay |
mikroscope_ |
the hardware clock range, min and max |
mikroscope_ |
every frequency the driver will use |
mikroscope_ |
always 1 |
mikroscope_ |
the cluster, named by its lowest-numbered core |
mikroscope_ |
the container’s own memory.max |
mikroscope_ |
each level source’s cadence |
Scroll sideways to see every column
The agent reads each core’s cpufreq cluster from its related_cpus, per device. On a board
whose cores change frequency in pairs, for example clusters {0,1} and {2,3}, a per-core
frequency panel is really two series. The conntrack ceiling reaches Prometheus as
mikroscope_ for the nf_conntrack cache rather than as a device-info
family.