canistergeek_ic_rust
is the open-source tool for Internet Computer to track your project canisters cycles and memory status.
canistergeek_ic_rust
can be integrated into your canisters as rust library which exposes the canistergeek_ic_rust::monitor
- public module that collects the data for specific canister by 5 minutes intervals.
canistergeek_ic_rust
should be used together with Canistergeek-IC-JS - Javascript library that fetches the data from canisters, perform all necessary calculations and displays it on a webpage
Stored data consumes ~6.5Mb per year per canister (assuming data points every 5 minutes).
Data can be collected in two ways: automatically and manually
collectCanisterMetrics
external public methodcanistergeek_ic_rust::monitor::collec_metrics();
in "update" methods in your canister to guarantee desired "Collect metrics" frequency. In some cases you may want to collect metrics in every "update" method to get the full picture in realtime and see how "update" methods influence canister price and capacity.Monitor collects the number of canister update calls
Monitor collects how many cycles left at particular time using ic_cdk::api::canister_balance()
.
Monitor collects how many memory bytes the canister consumes at particular time using ic_cdk::api::stable::stable64_size() * WASM_PAGE_SIZE + core::arch::wasm32::memory_size(0) * WASM_PAGE_SIZE
.
Monitor collects how many heap memory bytes the canister consumes at particular time using core::arch::wasm32::memory_size(0) * WASM_PAGE_SIZE
.
In file Cargo.toml
your project, add dependency on crate:
toml
canistergeek_ic_rust = "0.1.1"
Please perform the following steps
Implement pre/post upgrade hooks. This step is necessary to save collected data between canister upgrades.
```rust
fn preupgradefunction() { let stabledata = canistergeekicrust::monitor::preupgradestabledata(); iccdk::storage::stablesave(stable_data); }
fn postupgradefunction() {
let stabledata: Result
Implement public methods in the canister in order to query collected data and optionally force collecting the data
```rust
// CANISTER MONITORING
/// Returns collected data based on passed parameters. Called from browser. ///
pub async fn getcanistermetrics(parameters: apitype::GetMetricsParameters) -> Option
/// Force collecting the data at current time.
/// Called from browser or any canister update
method.
///
pub async fn collectcanistermetrics() -> () { validatecaller(); canistergeekicrust::monitor::collectmetrics(); }
fn validate_caller() -> () { // limit access here! } ```
did
fileIn your canister did file your_canister.did
, add next declaration:
```candid ...
type UpdateCallsAggregatedData = vec nat64; type NumericEntity = record { avg: nat64; first: nat64; last: nat64; max: nat64; min: nat64; }; type MetricsGranularity = variant { daily; hourly; }; type HourlyMetricsData = record { canisterCycles: CanisterCyclesAggregatedData; canisterHeapMemorySize: CanisterHeapMemoryAggregatedData; canisterMemorySize: CanisterMemoryAggregatedData; timeMillis: int; updateCalls: UpdateCallsAggregatedData; }; type GetMetricsParameters = record { dateFromMillis: nat; dateToMillis: nat; granularity: MetricsGranularity; }; type DailyMetricsData = record { canisterCycles: NumericEntity; canisterHeapMemorySize: NumericEntity; canisterMemorySize: NumericEntity; timeMillis: int; updateCalls: nat64; }; type CanisterMetricsData = variant { daily: vec DailyMetricsData; hourly: vec HourlyMetricsData; }; type CanisterMetrics = record {data: CanisterMetricsData;}; type CanisterMemoryAggregatedData = vec nat64; type CanisterHeapMemoryAggregatedData = vec nat64; type CanisterCyclesAggregatedData = vec nat64;
service : { ...
collectCanisterMetrics: () -> (); getCanisterMetrics: (GetMetricsParameters) -> (opt CanisterMetrics) query; } ```
Call canistergeek_ic_rust::monitor::collect_metrics()
method in all "update" methods in your canister in order to automatically collect all data.
🔴🔴🔴 We highly recommend limiting access by checking caller principal 🔴🔴🔴
rust
fn validate_caller() {
match ic_cdk::export::Principal::from_text("hozae-racaq-aaaaa-aaaaa-c") {
Ok(caller) if caller == ic_cdk::caller() => (),
_ => ic_cdk::trap("Invalid caller")
}
}
```rust
fn preupgradefunction() { let stabledata = canistergeekicrust::monitor::preupgradestabledata(); iccdk::storage::stablesave(stable_data); }
fn postupgradefunction() {
let stabledata: Result
pub async fn getcanistermetrics(parameters: apitype::GetMetricsParameters) -> Option
pub async fn collectcanistermetrics() -> () { validatecaller(); canistergeekicrust::monitor::collectmetrics(); }
fn validatecaller() -> () { match iccdk::export::Principal::fromtext("hozae-racaq-aaaaa-aaaaa-c") { Ok(caller) if caller == iccdk::caller() => (), _ => ic_cdk::trap("Invalid caller") } }
pub async fn dothis() -> () { canistergeekicrust::monitor::collectmetrics(); // rest part of the your method... } ```