ic-analytics-sdk 0.2.1

IC Analytics SDK
Documentation

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-forgetrecord_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> {
    // ... your transfer logic ...

    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 {
    /// Creates a new client pointing at the given analytics canister.
    pub fn new(backend_canister_id: Principal) -> Self;

    /// Enqueues a one-way call to record a metric. Non-blocking.
    pub fn record_metric(&self, metric: Metric) -> Result<(), String>;
}

Metric

pub struct Metric {
    /// Stable identifier used to look up this metric. Fixed on first write.
    pub key: String,
    /// Human-readable label shown in the dashboard.
    pub name: String,
    /// The value and its storage semantics.
    pub value: MetricValue,
}

MetricValue

pub enum MetricValue {
    Counter(i64),      // Delta applied to a running total
    Gauge(f64),        // Absolute value; replaces previous
    TimeSeries(f64),   // Appended with canister timestamp
    Log(String),       // Appended with canister timestamp
}