ic-analytics-sdk
Rust SDK for sending metrics from any Internet Computer canister to an
ICAnalytics analytics canister.
Installation
Add the crate to your canister's Cargo.toml:
[dependencies]
ic-analytics-sdk = "0.2.1"
Or with cargo add:
cargo add ic-analytics-sdk
Quick start
1. Initialise the client
AnalyticsClient holds the principal of your analytics canister. Create it
once and store it in a thread_local!.
use ic_analytics_sdk::AnalyticsClient;
use candid::Principal;
thread_local! {
static ANALYTICS: AnalyticsClient = AnalyticsClient::new(
Principal::from_text("YOUR-ANALYTICS-CANISTER-ID").unwrap()
);
}
Find your analytics canister ID on the ICAnalytics dashboard after creating
an analytics canister for your Dapp.
2. Record a metric
All recording is fire-and-forget — record_metric enqueues a one-way
inter-canister call that does not block your canister's execution.
use ic_analytics_sdk::{Metric, MetricValue};
ANALYTICS.with(|a| {
a.record_metric(Metric {
key: "user_signups".to_string(),
name: "User Sign-ups".to_string(),
value: MetricValue::Counter(1),
})
.expect("record_metric failed");
});
Metric types
| Variant |
Payload |
Behaviour |
Counter(i64) |
Delta (positive or negative) |
Accumulated running total |
Gauge(f64) |
Absolute value |
Overwritten on each call |
TimeSeries(f64) |
Data point |
Appended with canister timestamp |
Log(String) |
Text entry |
Appended with canister timestamp |
The key field is the stable identifier for a metric. The name field is the
human-readable label shown in the dashboard. The key is fixed on first write —
changing the metric type for an existing key will trap.
Examples
Counter
Increment a running total. Pass a negative delta to decrement.
a.record_metric(Metric {
key: "transfers_total".to_string(),
name: "Total Transfers".to_string(),
value: MetricValue::Counter(1),
})?;
Gauge
Store the latest absolute value. Useful for memory usage, queue depth, etc.
let heap_mb = (ic_cdk::api::stable_size() * 65536) as f64 / 1_048_576.0;
a.record_metric(Metric {
key: "heap_usage_mb".to_string(),
name: "Heap Usage (MB)".to_string(),
value: MetricValue::Gauge(heap_mb),
})?;
Time Series
Append a data point with the current canister timestamp. Useful for request
rates, latency, or any trend data.
a.record_metric(Metric {
key: "response_latency_ms".to_string(),
name: "Response Latency (ms)".to_string(),
value: MetricValue::TimeSeries(42.5),
})?;
Log
Append a timestamped text entry. Useful for events, errors, or audit trails.
a.record_metric(Metric {
key: "canister_events".to_string(),
name: "Canister Events".to_string(),
value: MetricValue::Log("[INFO] Upgrade completed to v2.1.0".to_string()),
})?;
Full example
use candid::Principal;
use ic_analytics_sdk::{AnalyticsClient, Metric, MetricValue};
use ic_cdk_macros::{init, update};
use std::cell::RefCell;
thread_local! {
static ANALYTICS: RefCell<Option<AnalyticsClient>> = RefCell::new(None);
}
#[init]
fn init(analytics_canister_id: Principal) {
ANALYTICS.with(|a| {
*a.borrow_mut() = Some(AnalyticsClient::new(analytics_canister_id));
});
}
#[update]
fn transfer(to: Principal, amount: u64) -> Result<(), String> {
ANALYTICS.with(|a| {
if let Some(client) = a.borrow().as_ref() {
let _ = client.record_metric(Metric {
key: "transfers_total".to_string(),
name: "Transfers".to_string(),
value: MetricValue::Counter(1),
});
let _ = client.record_metric(Metric {
key: "transfer_log".to_string(),
name: "Transfer Log".to_string(),
value: MetricValue::Log(format!("Transfer of {} to {}", amount, to)),
});
}
});
Ok(())
}
API Reference
AnalyticsClient
pub struct AnalyticsClient {
pub backend_canister_id: Principal,
}
impl AnalyticsClient {
pub fn new(backend_canister_id: Principal) -> Self;
pub fn record_metric(&self, metric: Metric) -> Result<(), String>;
}
Metric
pub struct Metric {
pub key: String,
pub name: String,
pub value: MetricValue,
}
MetricValue
pub enum MetricValue {
Counter(i64), Gauge(f64), TimeSeries(f64), Log(String), }