diff --git a/packages/ic-management/src/ic-management.canister.spec.ts b/packages/ic-management/src/ic-management.canister.spec.ts index baf0c06e..55b48bda 100644 --- a/packages/ic-management/src/ic-management.canister.spec.ts +++ b/packages/ic-management/src/ic-management.canister.spec.ts @@ -25,7 +25,10 @@ import { type StoredChunksParams, type UploadChunkParams, } from "./types/ic-management.params"; -import { CanisterStatusResponse } from "./types/ic-management.responses"; +import { + CanisterStatusResponse, + type FetchCanisterLogsResponse, +} from "./types/ic-management.responses"; describe("ICManagementCanister", () => { const mockAgent: HttpAgent = mock(); @@ -667,4 +670,52 @@ describe("ICManagementCanister", () => { expect(call).rejects.toThrowError(Error); }); }); + + describe("fetchCanisterLogs", () => { + it("returns canister logs when success", async () => { + const settings = { + freezing_threshold: BigInt(2), + controllers: [mockPrincipal], + memory_allocation: BigInt(4), + compute_allocation: BigInt(10), + reserved_cycles_limit: BigInt(11), + log_visibility: { controllers: null }, + wasm_memory_limit: BigInt(500_00), + }; + const response: FetchCanisterLogsResponse = { + canister_log_records: [ + { + idx: 123n, + content: [1, 2, 3], + timestamp_nanos: 12345n, + }, + { + idx: 456n, + content: [9, 8, 7], + timestamp_nanos: 12346n, + }, + ], + }; + const service = mock(); + service.fetch_canister_logs.mockResolvedValue(response); + + const icManagement = await createICManagement(service); + + const res = await icManagement.fetchCanisterLogs(mockCanisterId); + + expect(res).toEqual(response); + }); + + it("throws Error", async () => { + const error = new Error("Test"); + const service = mock(); + service.fetch_canister_logs.mockRejectedValue(error); + + const icManagement = await createICManagement(service); + + const call = () => icManagement.fetchCanisterLogs(mockCanisterId); + + expect(call).rejects.toThrowError(Error); + }); + }); }); diff --git a/packages/ic-management/src/ic-management.canister.ts b/packages/ic-management/src/ic-management.canister.ts index b10c19e1..4cb9f0e3 100644 --- a/packages/ic-management/src/ic-management.canister.ts +++ b/packages/ic-management/src/ic-management.canister.ts @@ -25,7 +25,10 @@ import { type UpdateSettingsParams, type UploadChunkParams, } from "./types/ic-management.params"; -import type { CanisterStatusResponse } from "./types/ic-management.responses"; +import type { + CanisterStatusResponse, + FetchCanisterLogsResponse, +} from "./types/ic-management.responses"; export class ICManagementCanister { private constructor(private readonly service: IcManagementService) { @@ -308,4 +311,17 @@ export class ICManagementCanister { return canister_id; }; + + /** + * Given a canister ID as input, this method returns a vector of logs of that canister including its trap messages. The canister logs are not collected in canister methods running in non-replicated mode (NRQ, CQ, CRy, CRt, CC, and F modes, as defined in Overview of imports). The total size of all returned logs does not exceed 4KiB. If new logs are added resulting in exceeding the maximum total log size of 4KiB, the oldest logs will be removed. Logs persist across canister upgrades and they are deleted if the canister is reinstalled or uninstalled. + * + * @param {Principal} canisterId + * @returns {Promise} + */ + fetchCanisterLogs = ( + canisterId: Principal, + ): Promise => + this.service.fetch_canister_logs({ + canister_id: canisterId, + }); } diff --git a/packages/ic-management/src/types/ic-management.responses.ts b/packages/ic-management/src/types/ic-management.responses.ts index 37204781..2d06b8ef 100644 --- a/packages/ic-management/src/types/ic-management.responses.ts +++ b/packages/ic-management/src/types/ic-management.responses.ts @@ -5,3 +5,8 @@ export type CanisterStatusResponse = ServiceResponse< IcManagementService, "canister_status" >; + +export type FetchCanisterLogsResponse = ServiceResponse< + IcManagementService, + "fetch_canister_logs" +>;