Skip to content

Metrics

Catalog, under Telemetry: Metrics (with metric_type:read, covered by every viewer’s *:read floor) is the numeric lane of the fleet’s signal catalog: the directory of the quantities the fleet measures. A metric is a quantity: a numeric reading that aggregates, so an average, a p95, a rate over time all mean something, and beside its name and data type it carries the numeric facts, a display unit and a precision, that the property lane never holds. A property is the other lane: a value, including a number used as a name (a serial number identifies a unit, it measures nothing).

A metric is used in three moves, and this page walks all three: the catalog names it, a classifier declares it (with a default, and whether it is required), and telemetry fills it, one series row per reading, with the current value read from the series. The name is the metric’s canonical identifier, a single lowercase kebab segment, and the same metric is the same comparable series wherever it appears: registering icmp-rtt-avg once means every device’s round-trip time lands under one name, in one unit, across vendors.

The catalog is fleet-wide reference data, not a scoped resource, so every metric is visible to every reader; the write gates decide who may change it.

  • The directory lists every metric sorted by name, each showing its name (the canonical identifier, with its label on the line above it), type (int or float), unit, and origin (official or custom). name filters by the name or its label; type, unit, and official narrow the list.

  • New metric (with metric_type:create, granted to operators) opens a create drawer: give it a name (a single lowercase kebab segment, for example icmp-rtt-avg or cpu-load), choose its data type (int or float; a metric is always a number, a categorical signal is a property), and optionally add a label, a description, a unit (ms, dB, percent), and a precision (the decimal places a rendered value keeps). An invalid name (an uppercase letter, an underscore, a leading hyphen, a dot) is refused with a message.

  • The unit is canonical: stored values are always in it, so every threshold and calculation compares like with like. A genuinely different measurement is a different metric; the unit names the scale, it never rides along per sample.

  • Pick a row to open its detail blade. The footer Edit pencil (with metric_type:update) edits the label, description, unit, and precision; the name and data type are fixed at creation, since changing a series’ value type under the rows that already use it is unsafe and a name is what every driver and contract maps onto. Delete (with metric_type:delete) removes a custom metric, behind a confirm. A verb you lack greys just that button, its hover reason naming the permission (Requires metric_type:update, Requires metric_type:delete); the pair never disappears.

  • An official metric is always read-only: the blade keeps the Edit and Delete pair in place, greyed, with the reason on hover: “Official: ships with Omniglass and updates with it.” The shared vocabulary is the same from install to install, the same deliberate exception to the operator-owned rule the Properties catalog makes, and for the same reason: a metric name is the vocabulary a driver maps onto, so a release has to be able to correct it (the seed model).

    The baseline ships this catalog, rendered from the seed itself (make gen) so the list cannot drift from the binary:

    NameDescription
    icmp-reachableICMP inline probe result (1 = at least one echo returned, 0 = none).
    icmp-rtt-avgAverage round-trip time over the task's echoes; absent when unreachable.
    tcp-openTCP-connect probe result (1 = the port accepted a connection, 0 = refused/timeout).
    tcp-connect-timeTime to establish the TCP connection; absent when the port is closed.
    room-temperatureAmbient temperature reported for the space, in degrees Celsius.
    occupancy-countPeople detected in the space by the room's occupancy source.
  • A duplicate name is refused (409), and an attempt to change an official metric is refused too. The refusal reaches across lanes: the metric, property, and event catalogs share one namespace, so a name one of them holds cannot be registered in another, which is what keeps per-lane routing unambiguous.

The catalog is also the collection vocabulary: a pushed sample lands in the metric series only if its name is registered here; an unregistered name is rejected and reported in the push response, not silently dropped and not invented.

The catalog says a metric exists; a classifier says which metrics its instances carry. The contract shape is the same as the property contract, held in the metric siblings of the property contract tables (product_metric, standard_metric, location_type_metric): a product declares for its components, a standard for its systems, and a location type for the locations of that type. Each line names a catalog metric, optionally gives it a default, and optionally marks it required: a product ships a default sample rate, a standard requires a seat count.

Type, unit, and precision are not repeated in the contract; they stay on the catalog entry, so a metric means one thing everywhere. The contract lines that predate the two-lane split moved into these tables when the catalog divided, and the classifier blades edit both lanes: a Declared metrics panel sits beside the declared-properties one on the product, standard, and location type blades, over the contract’s own routes (/products/{id}/metrics and its standard and location-type siblings, mirrored in the generated CLI). An instance resolves a declared metric to its series’ latest observed or calculated sample, falling back to the contract default until one arrives; the per-owner reads (/components/{name}/metrics and its system and location siblings) answer that resolution beside any off-contract series the owner holds.

A metric’s values are telemetry, not something typed on an instance’s detail:

  • An observed value arrives through collection: a task samples the device and pushes the reading. The shipped probes are the seeded set above: the TCP-connect probe writes tcp-open and tcp-connect-time, the ICMP probe writes icmp-reachable and icmp-rtt-avg.
  • A calculated value is produced by a rule from other telemetry, and the row names the rule that produced it, so a derived number is never mistaken for a reading.
  • A command that targets a metric (set a volume) records the value it intends, landing beside the observed series so intent and reality can be compared.

The current value is the latest series row: “what is this metric now?” is answered by reading the newest row for that metric on that owner, not from a separately maintained copy (the sample lanes). A declared metric value is not writable today: the metric lane refuses declared provenance until a writer exists, so a number an operator asserts by hand has nowhere to land yet.

From the CLI, the catalog is omniglass metric-type list|get|create|update|delete (see the CLI reference).