ProjectsisbDocs

Metrics history

To see whether an app's memory creeps up over a week, or which replica ate the CPU last night, you need more than the live numbers. isb serve samples every instance every 2 s (the live numbers overview and stack_status show) and keeps a month of history per org, for the web UI's Monitoring tab and anything else that asks. It survives daemon restarts and needs no separate metrics stack.

What is kept#

Per instance of an isb org (instances in other incus projects are not kept):

Metric Unit From
cpu percent of one core (four busy cores read 400) incus instance state
memory bytes in use incus instance state
net_rx, net_tx bytes per second, every interface but loopback the interface counters
disk_read, disk_write bytes per second, every disk incus /1.0/metrics, read every 10 s

Rates come from counters; a counter that goes backwards (a restart) gives no rate for that sample rather than a negative one. Stopped instances are not recorded.

Tiers#

Step Kept
10 s 24 hours
1 min 7 days
10 min 30 days

Each 10 s bucket (the average of the samples in it) is written as it closes; once a minute the coarser tiers are rolled up from the one below and older rows are deleted. The history lives in <state>/orgs/<org>/metrics.db (SQLite, WAL), one database per org.

Disk use is bounded by the number of instances: about 23 000 rows per instance at the steady state. Measured with 20 instances over 31 simulated days (cargo test --release --lib measure_disk_use -- --ignored): 460 620 rows in 20.5 MiB; writing one 10 s bucket of 20 instances takes 1.7 ms, a roll-up and retention pass 0.2 s (once a minute), and a 24 h query summing a service over them 0.2 s. Memory is one open bucket per running instance; samples reach the writer through a queue of 8 and are dropped (never block the sampler) when the disk falls behind.

Querying#

The metrics_query tool (over REST: POST /api/v1/tools/metrics_query) answers series ready for a chart:

{"org": "acme", "app": "web", "metric": "cpu", "range": "6h", "aggregate": "sum"}
Argument
metric cpu, memory, net_rx, net_tx, disk_read, disk_write
app an app: its service in its project environment's stack
stack, service a stack (all its services), or one service of it
instance one instance
range how far back from to (1h default, 24h, 7d, 30d)
from, to unix seconds instead (to defaults to now)
step seconds per point; widened to the step of the tier that still holds from, and so that there are at most 2000 points
aggregate sum, avg, max or min over the instances, bucket by bucket (a service's replicas); without it, one series per instance
{"metric": "cpu", "from": 1791000000, "to": 1791021600, "step": 60, "tier_step": 10,
 "series": [{"name": "shop-production/web", "stack": "shop-production", "service": "web",
             "replicas": [2, 2, ...], "points": [[1791000000, 12.5], ...]}]}

points are [bucket start, value], oldest first; a bucket with no samples is absent (a gap), not zero. replicas (aggregates only) counts the instances with a value in each bucket. A replaced replica is a new instance, so a per-instance query over a rolling update shows the old series ending and the new one starting; an aggregate over the service runs straight through. The coarser tiers lag their roll-up by a minute or two, so a query reading them takes its newest buckets from the tier below.

With an API token, from anywhere that reaches the daemon:

curl -s -H "Authorization: Bearer $ISB_TOKEN" -H 'Content-Type: application/json' \
  -d '{"app": "web", "metric": "memory", "range": "24h", "aggregate": "max"}' \
  "$ISB_URL/orgs/acme/api/v1/tools/metrics_query"

The org is the boundary: members of an org query its instances and no other org's (Users, roles and superadmins).

In the web UI#

An app's Monitoring tab charts this history over 1 hour, 24 hours, 7 days or 30 days (The web UI); the workspace's Resources tab and the org overview show live CPU and memory with a sparkline.