Metrics from Motoko
mo:metra-client records metrics in your canister and sends them to your Agent
in small batches. Recording never makes a network call; sending happens when
you flush.
Before you start
Section titled “Before you start”- Add your canister as a sender of the Agent’s Metrics connection. Send telemetry from your code.
- The package ships with icLens’s source and isn’t on Mops yet. Vendor it into your project.
Define a metric
Section titled “Define a metric”Create one client state when your canister initialises, and keep it across upgrades. Then register each metric once. This one is a gauge of queue depth:
import Client "mo:metra-client";import Result "mo:core/Result";
module { public func registerQueueDepth( client : Client.State ) : Result.Result<Nat64, Client.Error> { client.registerInstrument({ description = "Items waiting for processing"; identity = { name = "app.queue.depth"; unit = "1"; pointKind = #gauge; monotonic = null; temporality = null; }; metadata = []; resource = { schemaUrl = null; attributes = [ { key = "service.name"; value = #text("worker") } ]; }; scope = { name = "worker.metrics"; version = ?"1"; schemaUrl = null; attributes = []; }; }); };};Create the state with Client.initialize(Client.defaultPolicy()).
Record a value
Section titled “Record a value”Pass the metric’s ID, the value, and the current time in nanoseconds:
import Client "mo:metra-client";import Result "mo:core/Result";
module { public func recordQueueDepth( client : Client.State, instrumentId : Nat64, depth : Nat, nowNanos : Nat64 ) : Result.Result<(), Client.Error> { client.recordGauge( instrumentId, [], #number(#nat128(depth)), null, nowNanos, nowNanos ); };};Use addSum for counters and observeHistogram for durations. If the buffer
is full, recording returns an error rather than dropping the value.
Send to the Agent
Section titled “Send to the Agent”-
Open a lane to the Agent with
configureLane, thenprepareOpen. -
Register your metrics with the Agent:
prepareRegistration. -
Flush on a timer. Ask
flushStatus; when a flush is due, callprepareAppendfor one batch. -
Save, send, settle. Save the attempt with
beginAttemptbeforeClient.execute, then settle the reply withsettleAppend.
If a send times out
Section titled “If a send times out”A timeout doesn’t mean the batch was lost. Call markUnknown, then
reconcileRemote and reconcile: the client asks the Agent what it received
before sending anything else. New values keep collecting in the meantime.
After an upgrade, restore the client state and start your timer again. Never clear a pending batch to restart sending.