From dbabec1fd1a45763cb0ad006877ce625fc3238e4 Mon Sep 17 00:00:00 2001 From: Martin Raszyk Date: Thu, 9 Oct 2025 08:28:07 +0200 Subject: [PATCH] feat: canister log memory limit in canister settings --- .../canister-management/settings.mdx | 9 +++-- docs/references/_attachments/ic.did | 2 + docs/references/ic-interface-spec.md | 37 ++++++++++++++++--- 3 files changed, 39 insertions(+), 9 deletions(-) diff --git a/docs/building-apps/canister-management/settings.mdx b/docs/building-apps/canister-management/settings.mdx index a691a6a265..dc34a735e1 100644 --- a/docs/building-apps/canister-management/settings.mdx +++ b/docs/building-apps/canister-management/settings.mdx @@ -13,7 +13,7 @@ import { GlossaryTooltip } from "/src/components/Tooltip/GlossaryTooltip"; Each canister has a group of possible settings that control its behavior. Only a controller of the canister can read and modify a canister's settings. -Currently, there are nine canister setting fields: +Currently, there are ten canister settings fields: 1. `controllers`: The list of controllers of the canister. 2. `compute_allocation`: Amount of compute that the canister has allocated. @@ -22,8 +22,9 @@ Currently, there are nine canister setting fields: 5. `reserved_cycles_limit`: A safety threshold to protect against spending too many cycles for resource reservation. 6. `wasm_memory_limit`: A safety threshold to protect against reaching the 4GiB hard limit of 32-bit Wasm memory. 7. `log_visibility`: Controls who can read the canister logs. -8. `wasm_memory_threshold`: A threshold that triggers the "on low wasm memory" hook when the canister's remaining wasm memory falls below the provided value. -9. `environment_variables`: A set of key-value pairs that configure canister behavior without code changes. +8. `log_memory_limit`: The maximum amount of memory used for canister logs. +9. `wasm_memory_threshold`: A threshold that triggers the "on low wasm memory" hook when the canister's remaining wasm memory falls below the provided value. +10. `environment_variables`: A set of key-value pairs that configure canister behavior without code changes. ## Viewing current settings @@ -211,4 +212,4 @@ The default value of the field is `controllers`. Common errors related to canister settings include: -- [Invalid settings](/docs/references/execution-errors#invalid-settings). \ No newline at end of file +- [Invalid settings](/docs/references/execution-errors#invalid-settings). diff --git a/docs/references/_attachments/ic.did b/docs/references/_attachments/ic.did index 4622a2f78c..558770112f 100644 --- a/docs/references/_attachments/ic.did +++ b/docs/references/_attachments/ic.did @@ -20,6 +20,7 @@ type canister_settings = record { freezing_threshold : opt nat; reserved_cycles_limit : opt nat; log_visibility : opt log_visibility; + log_memory_limit : opt nat; wasm_memory_limit : opt nat; wasm_memory_threshold : opt nat; environment_variables : opt vec environment_variable; @@ -32,6 +33,7 @@ type definite_canister_settings = record { freezing_threshold : nat; reserved_cycles_limit : nat; log_visibility : log_visibility; + log_memory_limit : nat; wasm_memory_limit : nat; wasm_memory_threshold : nat; environment_variables : vec environment_variable; diff --git a/docs/references/ic-interface-spec.md b/docs/references/ic-interface-spec.md index 32edc73e9a..4d9669e0e5 100644 --- a/docs/references/ic-interface-spec.md +++ b/docs/references/ic-interface-spec.md @@ -2412,6 +2412,13 @@ The optional `settings` parameter can be used to set the following settings: Default value: `controllers`. +- `log_memory_limit` (`nat`) + + Must be equal to 4096 and indicates the maximum amount of memory used for canister logs. + Oldest canister logs are purged if the total memory used for canister logs exceeds this value. + + Default value: `4096`. + - `wasm_memory_threshold` (`nat`) Must be a number between 0 and 264-1, inclusively, and indicates the threshold on the remaining wasm memory size of the canister in bytes: @@ -3152,8 +3159,8 @@ This method can only be called by external users via non-replicated calls, i.e., 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](#system-api-imports)) and the canister logs are *purged* when the canister is reinstalled or uninstalled. -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. +The total size of all returned logs does not exceed the value `log_memory_limit` in canister settings. +Oldest canister logs are purged if the total memory used for canister logs exceeds the value `log_memory_limit` in canister settings. Logs persist across canister upgrades and they are deleted if the canister is reinstalled or uninstalled. The log visibility is defined in the `log_visibility` field of `canister_settings` and can be one of the following variants: @@ -4035,6 +4042,7 @@ S = { certified_data: CanisterId ↦ Blob; canister_history: CanisterId ↦ CanisterHistory; canister_log_visibility: CanisterId ↦ CanisterLogVisibility; + canister_log_memory_limit: CanisterId ↦ Nat; canister_logs: CanisterId ↦ [CanisterLog]; query_stats: CanisterId ↦ [QueryStats]; system_time : Timestamp @@ -4143,6 +4151,7 @@ The initial state of the IC is certified_data = (); canister_history = (); canister_log_visibility = (); + canister_log_memory_limit = (); canister_logs = (); query_stats = (); system_time = T; @@ -5134,6 +5143,11 @@ if A.settings.log_visibility is not null: else: New_canister_log_visibility = Controllers +if A.settings.log_memory_limit is not null: + New_canister_log_memory_limit = A.settings.log_memory_limit +else: + New_canister_log_memory_limit = 4096 + ``` State after @@ -5161,6 +5175,7 @@ S' = S with query_stats[Canister_id] = [] canister_history[Canister_id] = New_canister_history canister_log_visibility[Canister_id] = New_canister_log_visibility + canister_log_memory_limit[Canister_id] = New_canister_log_memory_limit canister_logs[Canister_id] = [] messages = Older_messages · Younger_messages · ResponseMessage { @@ -5305,6 +5320,8 @@ S' = S with canister_version[A.canister_id] = S.canister_version[A.canister_id] + 1 if A.settings.log_visibility is not null: canister_log_visibility[A.canister_id] = A.settings.log_visibility + if A.settings.log_memory_limit is not null: + canister_log_memory_limit[A.canister_id] = A.settings.log_memory_limit messages = Older_messages · Younger_messages · ResponseMessage { origin = M.origin @@ -6182,6 +6199,7 @@ S with certified_data[A.canister_id] = (deleted) canister_history[A.canister_id] = (deleted) canister_log_visibility[A.canister_id] = (deleted) + canister_log_memory_limit[A.canister_id] = (deleted) canister_logs[A.canister_id] = (deleted) query_stats[A.canister_id] = (deleted) chunk_store[A.canister_id] = (deleted) @@ -6417,6 +6435,11 @@ if A.settings.log_visibility is not null: else: New_canister_log_visibility = Controllers +if A.settings.log_memory_limit is not null: + New_canister_log_memory_limit = A.settings.log_memory_limit +else: + New_canister_log_memory_limit = 4096 + ``` State after @@ -6442,6 +6465,7 @@ S' = S with certified_data[Canister_id] = "" canister_history[Canister_id] = New_canister_history canister_log_visibility[Canister_id] = New_canister_log_visibility + canister_log_memory_limit[Canister_id] = New_canister_log_memory_limit canister_logs[Canister_id] = [] query_stats[CanisterId] = [] messages = Older_messages · Younger_messages · @@ -7322,16 +7346,19 @@ S with ``` -#### Trimming canister logs +#### Purging canister logs + +Oldest canister logs are purged if the total memory used for canister logs exceeds the value `log_memory_limit` in canister settings. -Canister logs can be trimmed if their total length exceeds 4KiB. +The (unspecified) function `canister_log_memory_usage(logs)` models the total memory used by `logs`. Conditions ```html S.canister_logs[CanisterId] = Older_logs · Newer_logs -SUM { |l| | l <- Older_logs } > 4KiB +canister_log_memory_usage(Older_logs · Newer_logs) > S.canister_log_memory_limit[CanisterId] +canister_log_memory_usage(Newer_logs) ≤ S.canister_log_memory_limit[CanisterId] ```