Prometheus Metrics¶
kvmd ships a small exporter at /api/export/prometheus/metrics.
get_metrics() returns its output verbatim, as a string.
What the output looks like¶
Every metric is a gauge, and each one is preceded by a single # TYPE line:
# TYPE pikvm_atx_enabled gauge
pikvm_atx_enabled 0
# TYPE pikvm_atx_power gauge
pikvm_atx_power 0
# TYPE pikvm_hw_cpu_percent gauge
pikvm_hw_cpu_percent 47
# TYPE pikvm_hw_temp_cpu gauge
pikvm_hw_temp_cpu 38.459
Note
There are no # HELP lines — kvmd does not emit them. Anything that
parses the output must not require a description per metric.
What is covered¶
The exporter reads four subsystems and nothing else:
| Prefix | Source | Metrics |
|---|---|---|
pikvm_atx_* |
ATX | exactly two: pikvm_atx_enabled and pikvm_atx_power, the latter from the power LED |
pikvm_gpio_* |
GPIO | two per visible channel |
pikvm_hw_* |
health | CPU, memory, temperatures, throttling flags |
pikvm_fan_* |
fan | pikvm_fan_monitored, plus the fan readings when one is fitted |
There is no MSD, streamer, HID or switch metric, and no ATX HDD LED. Read those through the corresponding resource instead.
Only numbers are exported: booleans become 0/1, and any string or null
in the underlying state is skipped silently. That is why a device with no fan
exports pikvm_fan_monitored alone, and why the set of pikvm_hw_* names
differs between boards.
GPIO channel names¶
A channel lives in exactly one direction, so it produces one pair of metrics:
pikvm_gpio_input_online_<channel> and pikvm_gpio_input_state_<channel> for
an input, the output spelling for an output. Two rules apply to the channel
part of the name:
- channels whose name starts with
__are hidden from the export; - every character that is not a letter, digit or underscore is replaced with
_, soled-1andled.1collide asled_1.
Upstream bug
kvmd fills both pikvm_gpio_*_online_* and pikvm_gpio_*_state_*
from the channel's state, so the online metric does not report
online-ness at all — it is a duplicate of state. Do not alert on it;
read gpio.get_state() for a truthful online flag.
Caching¶
kvmd caches the whole export server-side for 5 seconds
(alru_cache(maxsize=1, ttl=5)). Scraping more often than that returns the
same body; a scrape interval below 5 s buys nothing.
Integration example¶
import asyncio
from aiopikvm import PiKVM
async def collect_metrics() -> None:
async with PiKVM("https://pikvm.local", user="admin", passwd="admin") as kvm:
metrics = await kvm.prometheus.get_metrics()
# Write to a file for the node_exporter textfile collector.
with open("/var/lib/prometheus/pikvm.prom", "w") as file:
file.write(metrics)
asyncio.run(collect_metrics())
Full example¶
import asyncio
from aiopikvm import PiKVM
async def main() -> None:
async with PiKVM("https://pikvm.local", user="admin", passwd="admin") as kvm:
metrics = await kvm.prometheus.get_metrics()
for line in metrics.splitlines():
if line and not line.startswith("#"):
name, value = line.split(maxsplit=1)
print(f"{name:45} {value}")
asyncio.run(main())