Skip to content

Commit

Permalink
v0.0.7: New static method Canistergeek.getInformation added to redu…
Browse files Browse the repository at this point in the history
…ce information from monitor and logger.
  • Loading branch information
the-geekfactory committed Dec 16, 2022
1 parent 3f615d5 commit 6be013e
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 153 deletions.
148 changes: 22 additions & 126 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ Canistergeek-IC-Motoko should be used together with [Canistergeek-IC-JS](https:/
- `Monitor` - stored data for cycles and memory consumes ~6.5Mb per year per canister (assuming data points every 5 minutes).
- `Logger` - depends on the length of messages and their number. (canister with e.g. 10000 messages with 4096 characters each consumes 120Mb after upgrade).

## API change in 0.0.7 version

New static method `Canistergeek.getInformation` added to reduce information from monitor and logger.

## API change in 0.0.6 version

> Starting from version 0.0.6 `Monitor` has new API methods:
Expand Down Expand Up @@ -74,7 +78,7 @@ let
additions =
[{ name = "canistergeek"
, repo = "https://github.com/usergeek/canistergeek-ic-motoko"
, version = "v0.0.6"
, version = "v0.0.7"
, dependencies = ["base"] : List Text
}] : List Package
```
Expand All @@ -91,8 +95,6 @@ dependencies = [ ..., "canistergeek" ],
import Canistergeek "mo:canistergeek/canistergeek";
```



### Option 2: Copy Paste

- Copy `src` folder from this repository into your project, renaming it to `canistergeek`.
Expand All @@ -104,39 +106,48 @@ import Canistergeek "../canistergeek/canistergeek";

## Usage

### Monitor
### Monitor/Logger

Please perform the following steps

#### Initialize the monitor

Initialize Canistergeek Monitor as a private constant.
Initialize Canistergeek Monitor and(or) Logger as a private constant(s).

```motoko
actor {
private let canistergeekMonitor = Canistergeek.Monitor();
private let canistergeekLogger = Canistergeek.Logger();
}
```

#### Add post/pre upgrade monitor hooks

Add stable variable and implement pre/post upgrade hooks.
Add stable variable(s) and implement pre/post upgrade hooks.
This step is necessary to save collected data between canister upgrades.

```motoko
actor {
stable var _canistergeekMonitorUD: ? Canistergeek.UpgradeData = null;
stable var _canistergeekLoggerUD: ? Canistergeek.LoggerUpgradeData = null;
system func preupgrade() {
_canistergeekMonitorUD := ? canistergeekMonitor.preupgrade();
_canistergeekLoggerUD := ? canistergeekLogger.preupgrade();
};
system func postupgrade() {
canistergeekMonitor.postupgrade(_canistergeekMonitorUD);
_canistergeekMonitorUD := null;
canistergeekLogger.postupgrade(_canistergeekLoggerUD);
_canistergeekLoggerUD := null;
//Optional: override default number of log messages to your value
canistergeekLogger.setMaxMessagesCount(3000);
};
}
Expand All @@ -157,7 +168,7 @@ actor {
*/
public query ({caller}) func getCanistergeekInformation(request: Canistergeek.GetInformationRequest): async Canistergeek.GetInformationResponse {
validateCaller(caller);
canistergeekMonitor.getInformation(request);
Canistergeek.getInformation(?canistergeekMonitor, ?canistergeekLogger, request);
};
/**
Expand All @@ -169,22 +180,6 @@ actor {
canistergeekMonitor.updateInformation(request);
};
/**
* legacy
*/
public query ({caller}) func getCanisterMetrics(parameters: Canistergeek.GetMetricsParameters): async ?Canistergeek.CanisterMetrics {
validateCaller(caller);
canistergeekMonitor.getMetrics(parameters);
};
/**
* legacy
*/
public shared ({caller}) func collectCanisterMetrics(): async () {
validateCaller(caller);
canistergeekMonitor.collectMetrics();
};
private func validateCaller(principal: Principal) : () {
//limit access here!
};
Expand All @@ -196,101 +191,19 @@ actor {

Call `canistergeekMonitor.collectMetrics()` (it is a shortcut for generic method `canistergeekMonitor.updateInformation({metrics = ?#normal});`) method in all "update" methods in your canister in order to automatically collect all data.

```motoko
actor {
public shared ({caller}) func doThis(): async () {
canistergeekMonitor.collectMetrics();
// rest part of the your method...
};
public shared ({caller}) func doThat(): async () {
canistergeekMonitor.collectMetrics();
// rest part of the your method...
};
}
```

### Logger

Please perform the following steps

#### Initialize the logger

Initialize Canistergeek Logger as a private constant.

```motoko
actor {
private let canistergeekLogger = Canistergeek.Logger();
}
```

#### Add post/pre upgrade logger hooks

Add stable variable and implement pre/post upgrade hooks.
This step is necessary to save collected log messages between canister upgrades.

```motoko
actor {
stable var _canistergeekLoggerUD: ? Canistergeek.LoggerUpgradeData = null;
system func preupgrade() {
_canistergeekLoggerUD := ? canistergeekLogger.preupgrade();
};
system func postupgrade() {
canistergeekLogger.postupgrade(_canistergeekLoggerUD);
_canistergeekLoggerUD := null;
//Optional: override default number of log messages to your value
canistergeekLogger.setMaxMessagesCount(3000);
};
}
```

#### Implement public methods

Implement public methods in the canister in order to query collected log messages

```motoko
actor {
// CANISTER LOGGER
/**
* Returns collected log messages based on passed parameters.
* Called from browser.
*/
public query ({caller}) func getCanisterLog(request: ?Canistergeek.CanisterLogRequest) : async ?Canistergeek.CanisterLogResponse {
validateCaller(caller);
canistergeekLogger.getLog(request);
};
private func validateCaller(principal: Principal) : () {
//limit access here!
};
}
```

#### Adjust "update" methods

Call `canistergeekLogger.logMessage()` method where you want to log a message.

```motoko
actor {
public shared ({caller}) func doThis(): async () {
canistergeekMonitor.collectMetrics();
canistergeekLogger.logMessage("doThis");
// rest part of the your method...
};
public shared ({caller}) func doThat(): async () {
canistergeekMonitor.collectMetrics();
canistergeekLogger.logMessage("doThat");
// rest part of the your method...
};
Expand Down Expand Up @@ -352,31 +265,14 @@ actor {
public query ({caller}) func getCanistergeekInformation(request: Canistergeek.GetInformationRequest): async Canistergeek.GetInformationResponse {
validateCaller(caller);
canistergeekMonitor.getInformation(request);
Canistergeek.getInformation(?canistergeekMonitor, ?canistergeekLogger, request);
};
public shared ({caller}) func updateCanistergeekInformation(request: Canistergeek.UpdateInformationRequest): async () {
validateCaller(caller);
canistergeekMonitor.updateInformation(request);
};
public query ({caller}) func getCanisterLog(request: ?Canistergeek.CanisterLogRequest) : async ?Canistergeek.CanisterLogResponse {
validateCaller(caller);
return canistergeekLogger.getLog(request);
};
/* legacy */
public query ({caller}) func getCanisterMetrics(parameters: Canistergeek.GetMetricsParameters): async ?Canistergeek.CanisterMetrics {
validateCaller(caller);
canistergeekMonitor.getMetrics(parameters);
};
/* legacy */
public shared ({caller}) func collectCanisterMetrics(): async () {
validateCaller(caller);
canistergeekMonitor.collectMetrics();
};
private func validateCaller(principal: Principal) : () {
//data is available only for specific principal
if (not (Principal.toText(principal) == adminPrincipal)) {
Expand Down
66 changes: 39 additions & 27 deletions src/canistergeek.mo
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,44 @@ module Canistergeek {

public type UpdateInformationRequest = TypesModule.UpdateInformationRequest;

private func getCurrentVersion(): Nat { return 1; };

public func getInformation(monitor: ?Monitor, logger:?Logger, request: GetInformationRequest): GetInformationResponse {
//version
var version: ?Nat = null;
if (request.version) {
version := ?getCurrentVersion();
};
//status
var statusResponse: ?TypesModule.StatusResponse = TypesModule.getStatus(request.status);
//metrics
var metricsResponse: ?TypesModule.MetricsResponse = null;
switch((monitor, request.metrics)) {
case ((?monitor, ?metricsRequest)) {
metricsResponse := ?{
metrics = monitor.getMetrics(metricsRequest.parameters);
};
};
case ((_, _)) {};
};
//logger
var logsResponse: ?LoggerTypesModule.CanisterLogResponse = null;
switch(logger) {
case (?logger) {
logsResponse := logger.getLog(request.logs);
};
case (null) {};
};

return {
version = version;
status = statusResponse;
metrics = metricsResponse;
logs = logsResponse;
}
};

public class Monitor() {

private var VERSION: Nat = 1;

private var granularitySeconds: Nat = 60 * 5;

Expand Down Expand Up @@ -81,29 +116,6 @@ module Canistergeek {
};
};

public func getInformation(request: GetInformationRequest): GetInformationResponse {
var version: ?Nat = null;
if (request.version) {
version := ?VERSION;
};
var statusResponse: ?TypesModule.StatusResponse = TypesModule.getStatus(request.status);
var metricsResponse: ?TypesModule.MetricsResponse = null;
switch (request.metrics) {
case (null) {};
case (?metricsRequest) {
metricsResponse := ?{
metrics = CalculatorModule.getMetrics(state, metricsRequest.parameters);
};
};
};
let response = {
version = version;
status = statusResponse;
metrics = metricsResponse;
};
return response;
};

// Private

private func collectMetrics_int(forceCollect: Bool) {
Expand All @@ -128,7 +140,7 @@ module Canistergeek {
private func getDataIntervalIndex(time: Int): ?Nat {
let secondsFromDayStart: ?Nat = DateModule.Date.secondsFromDayStart(time);
switch(secondsFromDayStart) {
case (null) { null; };
case (null) { null; };
case (?value) { ?(value / granularitySeconds); }
};
}
Expand All @@ -137,7 +149,7 @@ module Canistergeek {
/****************************************************************
* Logger
****************************************************************/

public type LoggerUpgradeData = LoggerTypesModule.UpgradeData;
public type LoggerMessage = LoggerTypesModule.Message;
public type CanisterLogRequest = LoggerTypesModule.CanisterLogRequest;
Expand Down
4 changes: 4 additions & 0 deletions src/typesModule.mo
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import Nat64 "mo:base/Nat64";
import Option "mo:base/Option";
import Prim "mo:prim";

import LoggerTypesModule "logger/typesModule";

module {

// DayData types
Expand Down Expand Up @@ -201,12 +203,14 @@ module {
version: Bool;
status: ?StatusRequest;
metrics: ?MetricsRequest;
logs: ?LoggerTypesModule.CanisterLogRequest;
};

public type GetInformationResponse = {
version: ?Nat;
status: ?StatusResponse;
metrics: ?MetricsResponse;
logs: ?LoggerTypesModule.CanisterLogResponse;
};

// Init / Pre-Post Upgrade functions
Expand Down

0 comments on commit 6be013e

Please sign in to comment.