Prometheus metrics
Every metric family mikroscope exposes in the Prometheus text
format, with its
type, its labels, what it counts and when it is not there, read
from internal/expo/expo.go, internal/
and internal/. A family is listed under the source it
comes from, because that is what decides whether a given board has it.
Families by source
Section titled “Families by source”There is one exposition: the collector’s, served by forward --prom :9124.
The agent serves none; everything below is what the collector carries.
| Families | Where the collector gets them |
|---|---|
| everything recomputed from samples: CPU, windows, runs, receive path, memory, PMU, sensors, flash, disk, kernel log, observer counters | the samples it pulled, folded by the same Totals code |
the sampler’s timing histograms (mikroscope_tick_*) |
dt_ns, wake_ns and read_ns, which ride in each sample |
mikroscope_slipped_total, mikroscope_ |
the agent’s /sampler, read at start and every minute |
| trigger and capture families | the same, while CAPTURE_MB is above 0 |
device facts (mikroscope_device_info, ceilings, cadences) |
/capabilities, re-read every five minutes |
mikroscope_collector_*, mikroscope_derived_* |
its own: the derive stage and its counters |
mikroscope_api_* |
the API tier, once it has delivered a sample |
Scroll sideways to see every column
A deployment reached only through the relay gets all of it, because none of it depends on scraping the router.
- job_name: "mikroscope" scrape_interval: 5s static_configs: [{ targets: ["<collector host>:9124"] }]mikroscope_slipped_total is the number the agent reports on /sampler. The
counters that are not per-tick are as fresh as that one-minute read, not as
fresh as the scrape.
Collector differences
Section titled “Collector differences”The collector’s sink is built for a nominal 10 Hz whatever rate the agent runs
at (promHistogramRateHz in cmd/), so that its
bucket layout does not change when it reconnects to a differently configured
agent. Five things follow from that constant:
mikroscope_info{rate_hz}on the collector reads10, not the agent’s rate./healthzhas the agent’s.mikroscope_has the bucketscpu_ busy_ ticks le="0"tole="11", sized for a 100 ms sample. An agent below 10 Hz puts its busier samples in+Inf.- The ring behind the trailing windows holds 60 s of the connected agent’s
samples: the collector reads the agent’s rate from its health check and sizes
the ring from it, so
window="60s"is 60 s at any rate. - The trailing mean behind
mikroscope_has a weight of 1/600, which is a 60 s memory at 10 Hz and shorter above it.softnet_ burst_ samples_ total - An interrupt line leaves
mikroscope_irq_totalafter 36 000 samples out of every top-K, which is one hour only at 10 Hz: 12 min at 50 Hz, 6 min at 100 Hz. The check runs every 1 000 samples, so a line can stay up to that much longer.
The counters on the collector count from the collector’s start, and
mikroscope_ and mikroscope_info{version} describe the
collector. mikroscope_self_* still describe the agent: they come from the
agent’s samples.
The first three hold on a running agent at 100 Hz and at 50 Hz
(verified). The last two follow
from internal/expo/expo.go: the collector’s Totals is sized once at
the nominal 10 Hz and SetSamplerRate resizes only the ring, never re-buckets,
so the 1/600 weight and the 36 000-sample eviction stand whatever the agent’s
rate (not observed).
Conventions
Section titled “Conventions”- Counters count since the exporter started and never reset on a scrape.
The ring carries deltas;
/metricsaccumulates them.rate()over any range is then correct, and two scrapers see the same values. - Gauges are the newest sample. A floored source (thermal, cpufreq, slab,
buddyinfo, MTD) is absent from most samples by design, so its gauge holds
the last reading between emissions, and
mikroscope_says how old that reading is.source_ age_ seconds - Absent is not zero, with five exceptions. Most families for a source the kernel does
not have, or the deployment cannot read, are not rendered at all. The
exceptions are
mikroscope_,meminfo_ kbytes mikroscope_load,mikroscope_threads,mikroscope_andself_ rss_ bytes mikroscope_: they are written from the first sample and read 0 when their file cannot be read orirq_ errors_ total SOURCESleaves it out.mikroscope_also reads 0 on a kernel whoseirq_ errors_ total /proc/interruptshas noErrrow. - One dimension, one name. A processor is the label
cpueverywhere. Which cores, zones, interrupt lines, caches and counters exist is a property of the board; read the label, never assume a set. - No ratio in the samples. The busy-ratio gauges are window statistics
computed at scrape, and the collector’s
mikroscope_derived_*gauges are divisions it made beside their inputs. Every other ratio is yours to divide.
CPU ticks and /proc/stat
Section titled “CPU ticks and /proc/stat”| Family | Type | Labels | Meaning |
|---|---|---|---|
mikroscope_ |
counter | cpu, mode: user, nice, system, idle, iowait, irq, softirq, steal |
USER_HZ ticks per core and mode |
mikroscope_ |
counter | mode |
the same, from /proc/stat’s own cpu summary line; a separate name so summing the per-core series cannot double-count it |
mikroscope_ |
histogram | cpu, le |
busy ticks per sample, one bucket per achievable integer, 0 up to one more than a period holds, plus +Inf. _sum is the exact busy total. Recovers time above a threshold to one sample, not contiguity |
mikroscope_ |
counter | none | ctxt |
mikroscope_ |
counter | none | intr, every source |
mikroscope_forks_total |
counter | none | the processes line: RouterOS spawning scripts, fetches and containers, although the PID namespace hides the processes |
mikroscope_procs_blocked |
gauge | none | tasks in uninterruptible sleep; on a kernel without PSI the only direct stall signal |
Scroll sideways to see every column
A tick is busy when it is user, nice, system, irq, softirq or
steal. A kernel that leaves the irq column at 0 counts hard-IRQ time inside
system (measured): read the irq
mode as absent there, not as a router with no interrupt load.
Trailing windows and busy runs
Section titled “Trailing windows and busy runs”Computed at scrape from the ring over fixed wall-clock windows, so a scraper at any interval up to 60 s sees a transient’s peak whoever scraped last.
| Family | Type | Labels | Meaning |
|---|---|---|---|
mikroscope_ |
gauge | cpu, window: 1s, 10s, 60s; stat: max, min, p95 |
busy ratio statistics over the trailing window |
mikroscope_ |
gauge | window, stat |
the sampler’s measured interval over the trailing window; its max says whether the rate was delivered |
mikroscope_ |
histogram | cpu, threshold: 0.5, 0.9; le: 0.1, 0.2, 0.5, 1, 2, 5, 10, 30, 60, +Inf |
length of each run of consecutive samples at or above the busy ratio, in seconds of the samples’ own intervals, observed when the run ends |
mikroscope_ |
gauge | cpu, threshold |
how long the run in progress has lasted; 0 below the threshold |
Scroll sideways to see every column
A 2 s plateau is one observation of 2 in mikroscope_ and
twenty scattered 100 ms spikes are twenty of 0.1; the busy-tick histogram
cannot tell those apart.
Sampler timing
Section titled “Sampler timing”The three histograms are rendered by the collector from each sample’s dt_ns
and self block; the two counters come from the agent’s /sampler. A sample is
read over a stretch of time, not at an instant, and these families measure that
stretch.
| Family | Type | Labels | Meaning |
|---|---|---|---|
mikroscope_ |
histogram | le |
measured interval between samples; buckets at 0.5, 0.9, 0.95, 0.99, 1.01, 1.05, 1.1, 1.25, 1.5, 2 and 5 times the nominal period |
mikroscope_ |
histogram | le |
how late the loop ran after its ticker fired; buckets 0.1 ms, 0.25, 0.5, 1, 2, 5, 10, 20, 50, 100 ms |
mikroscope_ |
histogram | le |
how long reading every due source took; same buckets |
mikroscope_slipped_total |
counter | none | ticks whose read finished after the next tick was due |
mikroscope_ |
counter | none | ticks the agent took since it started, as the agent counts them |
Scroll sideways to see every column
A slipped tick is not a lost sample: the sample is still produced with its real
dt_ns. If mikroscope_slipped_total moves, distrust the sampler’s own
accounting before the router’s.
Receive path and interrupts
Section titled “Receive path and interrupts”/proc/net/softnet_stat, /proc/softirqs and /proc/interrupts are global
inside the container, unlike /proc/net/dev.
| Family | Type | Labels | Meaning |
|---|---|---|---|
mikroscope_softnet_total |
counter | cpu, kind: processed, dropped, time_squeeze |
per-CPU softnet counters |
mikroscope_ |
counter | cpu |
samples in which that CPU had any squeeze or drop; its rate is a duty cycle |
mikroscope_ |
counter | cpu |
the squeezed samples whose packet count was at or below that CPU’s trailing mean (EWMA with a one-minute memory); evidence of bursts shorter than a sample, not a count of them |
mikroscope_softirq_total |
counter | cpu, kind |
softirq counts; which kinds exist is the kernel’s list. NET_RX carries a router’s forwarding load |
mikroscope_irq_total |
counter | irq, name, cpu |
lines that appeared in any sample’s top-K. A line out of every top-K for an hour leaves the family, and restarts from 0 if it returns; on the collector the hour holds only at 10 Hz (above) |
mikroscope_ |
counter | none | every interrupt line summed, including those outside the top-K: the denominator for mikroscope_irq_total |
mikroscope_ |
counter | none | the Err row of /proc/interrupts, which the top-K never shows while it sits at zero |
Scroll sideways to see every column
Match an interrupt on its name label or on its rate, never on a hardcoded
name: which lines a NIC raises is a property of the board and its driver.
Scheduler, load and PSI
Section titled “Scheduler, load and PSI”| Family | Type | Labels | Absent when | Meaning |
|---|---|---|---|---|
mikroscope_load |
gauge | period: 1m, 5m, 15m |
no sample yet | load averages |
mikroscope_threads |
gauge | state: running, total |
no sample yet | from /proc/loadavg |
mikroscope_ |
counter | resource, kind: cpu/some, memory/some, memory/full, io/some, io/full |
the kernel has no /proc/pressure |
PSI stall microseconds |
mikroscope_ |
counter | cpu |
the kernel has no /proc/schedstat |
time tasks spent on each CPU |
mikroscope_ |
counter | cpu |
the same | time runnable tasks waited for each CPU |
Scroll sideways to see every column
Both PSI and schedstat families are absent on a kernel without those files, which some RouterOS kernels are (measured).
Memory
Section titled “Memory”| Family | Type | Labels | Meaning |
|---|---|---|---|
mikroscope_ |
gauge | field |
/proc/meminfo in kB: MemTotal, MemFree, MemAvailable, Buffers, Cached, Dirty, Writeback, Shmem, Slab, SReclaimable, SUnreclaim, AnonPages, Mapped, KernelStack, PageTables, Active, Inactive, Committed_AS, CommitLimit |
mikroscope_ |
counter | event |
/proc/vmstat events: pgfault, pgmajfault, pgscan_kswapd, pgscan_direct, pgsteal_kswapd, pgsteal_direct, pgalloc, pgfree, allocstall, compact_stall, oom_kill, pswpin, pswpout. pgalloc and allocstall are summed over zones |
mikroscope_vm_pages |
gauge | field |
/proc/vmstat levels in pages: nr_free_pages, nr_dirty, nr_writeback, nr_slab_reclaimable, nr_slab_unreclaimable |
mikroscope_ |
gauge | node, zone, order |
free blocks of 2^order pages from /proc/buddyinfo: fragmentation that MemFree cannot show |
Scroll sideways to see every column
The events and the levels are separate families on purpose: nr_dirty falling
is pages being written back, not a negative event count. MemFree in kB
divided by nr_free_pages gives the page size from the data rather than from
an assumption. The vmstat families are absent until a sample shows a fault or
a free-page level, because an unreadable /proc/vmstat and a quiet tick both
arrive as zeros.
PMU and CPU frequency
Section titled “PMU and CPU frequency”| Family | Type | Labels | Absent when | Meaning |
|---|---|---|---|---|
mikroscope_ |
counter | counter, cpu |
not privileged, or no reachable PMU | hardware counter events from perf_event_open; a counter the CPU does not implement is absent |
mikroscope_ |
counter | counter, cpu |
the same | seconds each counter was enabled |
mikroscope_ |
counter | counter, cpu |
the same | seconds it was actually counting; below enabled the PMU is multiplexed and the counts are scaled down by running over enabled |
mikroscope_ |
counter | cpu |
no cpufreq | the governor’s frequency integrated over each sample’s interval: nominal cycles offered, not cycles retired. rate() of it is the mean frequency over any window |
mikroscope_ |
gauge | cpu |
no cpufreq | the governor’s frequency at the newest emission |
Scroll sideways to see every column
Instructions per cycle is rate(mikroscope_
over rate(…{counter="cycles"}); the agent ships the counts and never the
ratio.
Temperature and slab caches
Section titled “Temperature and slab caches”| Family | Type | Labels | Absent when | Meaning |
|---|---|---|---|---|
mikroscope_ |
gauge | zone |
no thermal zone | temperature under the kernel’s own zone name, for example cpu-thermal or soc-thermal |
mikroscope_ |
gauge | cache |
not privileged | active objects per slab cache; nf_conntrack is the router’s real connection count, although the container’s namespace reports zero |
mikroscope_ |
gauge | cache |
not privileged, or no ceiling published | the ceiling for caches that have one, today nf_conntrack from nf_conntrack_max; read once at agent start |
Scroll sideways to see every column
Connection-table occupancy is
mikroscope_.
A change to nf_conntrack_max shows after the agent restarts.
Flash and block devices
Section titled “Flash and block devices”| Family | Type | Labels | Absent when | Meaning |
|---|---|---|---|---|
mikroscope_ |
counter | device, kind: page_writes, page_reads, erasures, gc_copies, gcs |
no /proc/yaffs |
YAFFS NAND operations; erasures maps to flash lifetime, gc_copies over page_writes is write amplification |
mikroscope_ |
gauge | device |
no /proc/yaffs, and on any scrape whose newest sample carried no flash row (no operation, free chunks unchanged); not held between emissions |
blocks the NAND has retired; a rise is the flash wearing out |
mikroscope_ |
gauge | device |
the same as mikroscope_ |
chunks still free |
mikroscope_ |
counter | device, partition |
not privileged | bits the ECC corrected since boot, the kernel’s own count; climbs before a block is retired |
mikroscope_ |
counter | device, partition |
not privileged | reads the ECC could not correct since boot: data loss |
mikroscope_mtd_blocks |
gauge | device, partition, kind: bad, bbt |
not privileged | bad blocks, and blocks the bad-block table occupies |
mikroscope_ |
gauge | device, partition |
not published | corrected bits per ECC step at which the kernel moves a block’s data |
mikroscope_ |
gauge | device, partition |
not published | most bits per ECC step the code can correct |
mikroscope_ |
counter | device, op: read, write |
no device has done I/O | requests completed |
mikroscope_ |
counter | device, op |
the same | sectors transferred; the conversion to bytes is left to the reader |
mikroscope_ |
counter | device |
the same | time the device had I/O in flight |
mikroscope_disk_inflight |
gauge | device |
no I/O on that device in the newest sample; not held between emissions | requests in flight |
Scroll sideways to see every column
A block device that did nothing is not in the sample and so not here either.
Unlike the floored sources in the conventions above, the flash levels and
mikroscope_disk_inflight are not carried forward, so they are missing from
most scrapes of a quiet board.
Kernel log
Section titled “Kernel log”/dev/kmsg is root-only, so these families need a privileged container. The
record text is never a label.
| Family | Type | Labels | Meaning |
|---|---|---|---|
mikroscope_ |
counter | level: emerg, alert, crit, err, warn, notice, info, debug |
records per syslog severity |
mikroscope_ |
counter | none | loss events, not records: one per tick that hit the cap of 64 records, one per kernel ring overrun (which can stand for many records); while it moves, the per-level counts above are a lower bound |
mikroscope_ |
counter | port, kind, level |
records whose text named a port: a subset of the family above. kind is link-up, link-down, stp-<state> (blocking, listening, learning, forwarding, disabled), own-address — the bridge received a frame carrying its own MAC as source address, the layer-2 loop signature — or other; only non-zero triples are written |
Scroll sideways to see every column
Both mikroscope_ and mikroscope_ are
rendered from the start, at 0, on the exposition when the capabilities list
kmsg as a source, so a quiet router reads as silent and not as unreadable.
Without that, they appear with the first record. The port family appears with
the first record that names a port.
The agent names the port in its records with the RouterOS default name on a
board in the port table and the kernel name otherwise. The collector’s API-tier
interface inventory puts the port’s current RouterOS name in port, so a port
renamed from ether5 to WAN is counted under WAN; without an API tier the
record keeps the board’s default name. The collector classifies any port record
that reaches it without a kind of its own, so records from an agent that ships
none still carry the label.
A port coming up writes four records on a bridge, not four faults: link-up,
then stp-blocking, stp-learning and stp-forwarding on its bridge port.
own-address is the one kind that is a fault on its own.
Agent self-metrics
Section titled “Agent self-metrics”| Family | Type | Labels | Meaning |
|---|---|---|---|
mikroscope_ |
counter | none | CPU microseconds the agent’s container used: from cgroup2 when mounted, else /proc/self/stat ticks |
mikroscope_ |
gauge | none | the agent’s resident set |
mikroscope_ |
gauge | none | the container cgroup’s memory.current, RSS plus page cache charged to it; absent without cgroup2 |
mikroscope_ |
counter | none | periods the container’s cpu.max quota stopped it; absent without cgroup2 |
mikroscope_ |
counter | none | seconds it spent stopped; absent without cgroup2 |
mikroscope_ |
counter | none | processes OOM-killed inside the agent’s own cgroup; not the router’s, which is mikroscope_ |
mikroscope_samples_total |
counter | none | samples folded into these counters |
mikroscope_ |
counter | none | sequence number of the newest sample; increase() of it against increase(mikroscope_ is exactly the ticks produced and not folded in |
mikroscope_ |
counter | none | the samples’ own intervals summed; rate() of it is the wall-clock time covered per second, 1 while no tick slipped. The denominator for derived ratios |
mikroscope_ |
counter | none | monotonic counters that went backwards without a 32-bit wrap; a rate across such a tick is a lower bound |
mikroscope_info |
gauge | version, rate_hz |
always 1 |
mikroscope_ |
gauge | none | seconds since this exporter started |
Scroll sideways to see every column
The agent’s cost is two reads of mikroscope_ 60 s apart at
steady state, divided by 60 000 000. Agent cost has the
procedure and the measured figures.
Device facts
Section titled “Device facts”What the agent established about the board at start, with no RouterOS API. Each family is absent when the device does not publish that fact.
| Family | Type | Labels | Meaning |
|---|---|---|---|
mikroscope_device_info |
gauge | board, kernel, cores, privileged, cgroup, ports_from, hash |
always 1; hash changes when the source set does |
mikroscope_ |
gauge | zone |
the lowest critical trip point the zone declares; passive and active trips are not included |
mikroscope_ |
gauge | zone |
the zone’s polling_delay: reads faster than this see the same value |
mikroscope_ |
gauge | cpu, bound: min, max |
the hardware clock range |
mikroscope_ |
gauge | cpu, step |
every frequency the driver uses; step counts from the slowest |
mikroscope_ |
gauge | cpu, governor |
always 1; userspace is a pinned clock, ondemand or schedutil one that scales |
mikroscope_ |
gauge | cpu |
the lowest-numbered core that changes frequency with this one |
mikroscope_ |
gauge | none | the container’s own memory.max, as the operator set it |
mikroscope_ |
gauge | source, reason |
the rate each level source is read and stored at, and why: declared, policy, budget, change, override or rate |
mikroscope_ |
gauge | source |
seconds since each floored source (thermal, cpufreq, slabinfo, buddyinfo, mtd) was last actually read |
Scroll sideways to see every column
All but the last are read once at agent start; a ceiling changed while the agent runs shows after it restarts.
Triggers and captures
Section titled “Triggers and captures”Rendered by the collector, and only while CAPTURE_MB is above 0. Every
condition-and-reason pair is written from the start at 0.
| Family | Type | Labels | Meaning |
|---|---|---|---|
mikroscope_ |
counter | condition |
times each configured condition armed a capture; condition="manual" appears after the first POST /capture |
mikroscope_ |
counter | condition, reason: refractory, pending |
times a condition was true and nothing was armed: how much of a burst was not seen |
mikroscope_ |
counter | reason: budget, empty |
captures collected and not kept: the budget was full, or the ring no longer held the window |
mikroscope_captures_held |
gauge | none | captures retained |
mikroscope_capture_bytes |
gauge | none | ring bytes the retained captures pin |
mikroscope_ |
gauge | none | the budget |
mikroscope_ |
counter | none | bytes handed out over /captures/{id}, which runs on the sampler’s core |
Scroll sideways to see every column
Derived values
Section titled “Derived values”| Family | Type | Labels | Meaning |
|---|---|---|---|
mikroscope_ |
counter | none | ring gaps the collector saw: samples lost between pulls |
mikroscope_ |
counter | cause |
capture triggers the collector saw the agent fire; absent until the first. The windows stay on the agent under /captures |
mikroscope_ |
counter | rule |
detection events per rule, every rule at 0 from the first scrape: counter-reset, agent-restart, agent-oom, microburst, reboot, link-flap, conntrack-cliff, conntrack-high, thermal-high, thermal-rising, ipc-collapse |
mikroscope_ |
counter | none | samples flagged as a sub-sample burst |
mikroscope_ |
gauge | none | the allocator’s ladder at the newest sample: 0 none, 1 kswapd scanned, 2 direct reclaim, 3 an allocation stalled or a page swapped out, 4 the OOM killer ran |
mikroscope_ |
gauge | none | PMU cycles per packet, summed over cores; absent without a PMU, in a sample with no packets, and in one with a counter reset |
mikroscope_ |
gauge | none | the same, instructions |
mikroscope_ |
gauge | none | the same, cache misses |
mikroscope_ |
gauge | none | packets per device interrupt, the NAPI coalescing depth; absent when the timer row was not in the sample’s top-K |
mikroscope_ |
gauge | interface, direction: rx, tx |
the fast-path share of the traffic the interface hands the CPU, between the last two counter polls: fp-rx-byte over driver-rx-byte on a switch port, over rx-byte on a software interface. Absent for a direction that moved no bytes |
Scroll sideways to see every column
The fast-path share is not a share of the wire: a frame the switch chip
forwards in hardware is in neither of its two numbers. On a switch port whose
fp-rx-byte equals its driver-rx-byte the share reads about 100 % and says
little; it moves on software interfaces such as a bridge or a PPPoE client
(measured). direction="tx" is withheld
while the interface’s cumulative fp-tx-byte is 0, rather than published as a
fabricated 0 %.
The rules and what each may not claim are on Detection rules; the derived values on Derived values.
API tier
Section titled “API tier”Absent until the API tier has delivered a sample, and absent entirely with
--api-mode off unless --api-every is also given explicitly.
| Family | Type | Labels | Meaning |
|---|---|---|---|
mikroscope_api_up |
gauge | none | 1 once the API tier has delivered a sample. It does not go back to 0 if the tier stops later, although its HELP line says “while” |
mikroscope_api_cpu_load |
gauge | none | cpu-load as /system/resource reports it, a one-second average |
mikroscope_ |
gauge | kind: free, total |
from /system/resource |
mikroscope_ |
gauge | none | the router’s uptime |
mikroscope_ |
gauge | cpu, kind: load, irq, disk |
/system/resource/cpu |
mikroscope_api_health |
gauge | name |
/system/health readings, by RouterOS’s name |
mikroscope_api_interface |
gauge | interface, kind: rx_bps, tx_bps, rx_pps, tx_pps, and rx_drops, tx_drops, tx_queue_drops, rx_errors, tx_errors only when the router returned them |
instantaneous rates from monitor-traffic |
mikroscope_ |
gauge | interface, label, type, role, bridge, default_name |
always 1, one series per interface: label is its RouterOS comment, type RouterOS’s own interface type, role its interface lists, bridge the bridge it is a port of, default_name the factory name of a physical port. An empty value is how the exposition spells “none” |
mikroscope_ |
counter | interface, counter |
every numeric per-port counter RouterOS keeps, under its own name (rx-overflow, fp-rx-byte, link-downs …), for every interface |
mikroscope_ |
gauge | none | /ip/firewall/connection count, held between polls; only with --conntrack-every |
Scroll sideways to see every column
What each interface is — comment, type, interface lists, bridge — is an info
family and not a set of labels on every rate and counter, because a human edits
those and a changed label starts a new series. The collector reads the
configuration once at start and again every --labels-every (5 minutes by
default), and the family holds one series per interface, with or without a
comment. Join it in a query:
mikroscope_api_interface_counter_total * on(interface) group_left(label, type, role) mikroscope_api_interface_infoThe join is worth making because RouterOS counts different things on different
types, and type is what says which: an ether port in a bridge counts its
wire, including the frames the switch chip forwarded in hardware, while the
bridge counts its CPU side. The two are different planes and neither is a
subset of the other: never sum a port and its bridge.
Sizes and configuration that happen to parse as integers — mtu, actual-mtu,
l2mtu, max-l2mtu and sfp-shutdown-temperature — are not in
mikroscope_, because a rate() of an MTU counts
nothing. The MTU travels with the interface inventory instead, which the row
sinks write as a field.
Where monitor-traffic returns rx-drops, tx-drops and tx-queue-drops
per second and no error keys at all, the rx_errors and tx_errors kinds are
absent (observed);
mikroscope_ carries the port’s typed errors
instead.