Skip to content

Commit 3665ee0

Browse files
committed
docs(logs): clarify canister log trimming direction
Emphasize that an unfiltered fetch_canister_logs read trims the oldest records (response ends with the newest record) while a filtered read trims the newest records (response starts with the oldest matching record). Bound the trimming by an unspecified max response size. Also drop the stale duplicate "Canister logs (query call)" section re-introduced by the merge from main, which carried a duplicate anchor and pre-filter semantics.
1 parent bfa60a5 commit 3665ee0

3 files changed

Lines changed: 26 additions & 60 deletions

File tree

docs/guides/canister-management/logs.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,8 @@ icp canister logs <canister-name> -e ic --since-index 100 --until-index 200
102102

103103
Timestamp and index filters cannot be combined with `--follow`.
104104

105+
Filtering also changes which records are dropped when the selected logs exceed the response size. An unfiltered read trims the oldest records, so it returns the most recent logs (the output ends with the newest record). A filtered read trims the newest records instead, so it returns the oldest records that match the filter (the output starts with the oldest matching record), which lets you page forward through a range by advancing the start of the filter.
106+
105107
To output logs as JSON for programmatic processing:
106108

107109
```bash

docs/references/ic-interface-spec/abstract-behavior.md

Lines changed: 20 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -3823,12 +3823,21 @@ Given a state `S`, `Canister_id`, `filter`, and `Sender`, we define
38233823
```html
38243824

38253825
canister_logs(S, Canister_id, filter) =
3826-
if filter = by_idx Range:
3827-
{ Log | Log S.canister_logs[Canister_id] Range.start <= Log.idx Log.idx < Range.end }
3828-
else if filter = by_timestamp_nanos Range:
3829-
{ Log | Log S.canister_logs[Canister_id] Range.start <= Log.timestamp_nanos Log.timestamp_nanos < Range.end }
3830-
else:
3831-
S.canister_logs[Canister_id]
3826+
let Selected_logs = the sublist of S.canister_logs[Canister_id] (preserving order) such that
3827+
if filter = by_idx Range:
3828+
Log Selected_logs Log S.canister_logs[Canister_id] Range.start <= Log.idx Log.idx < Range.end
3829+
else if filter = by_timestamp_nanos Range:
3830+
Log Selected_logs Log S.canister_logs[Canister_id] Range.start <= Log.timestamp_nanos Log.timestamp_nanos < Range.end
3831+
else:
3832+
Log Selected_logs Log S.canister_logs[Canister_id]
3833+
in
3834+
if filter = null:
3835+
the longest suffix Younger_logs of Selected_logs
3836+
such that canister_log_memory_usage(Younger_logs) max_response_size
3837+
else:
3838+
the longest prefix Older_logs of Selected_logs
3839+
such that canister_log_memory_usage(Older_logs) max_response_size
3840+
max_response_size = <implementation-specific>
38323841
fetch_canister_logs_cost(S, Canister_id) = <implementation-specific>
38333842
is_sender_authorized(S, Canister_id, Sender) =
38343843
(S[Canister_id].canister_log_visibility = Public)
@@ -3839,6 +3848,11 @@ is_sender_authorized(S, Canister_id, Sender) =
38393848

38403849
```
38413850

3851+
When the selected logs do not all fit within a single response, they are trimmed to fit and the direction of trimming depends on whether a filter is provided.
3852+
An unfiltered read trims the oldest log records (keeps the longest suffix), so the response ends with the newest log record.
3853+
A filtered read trims the newest log records (keeps the longest prefix), so the response starts with the oldest log record satisfying the filter.
3854+
Thus an unfiltered read surfaces the most recent activity, while a filtered read can page forward through logs starting from the beginning of the requested range.
3855+
38423856
Conditions
38433857

38443858
```html
@@ -4440,60 +4454,6 @@ S with
44404454

44414455
```
44424456

4443-
#### IC Management Canister: Canister logs (query call) {#ic-mgmt-canister-fetch-canister-logs}
4444-
4445-
This section specifies management canister query calls.
4446-
They are calls to `/api/v3/canister/<ECID>/query`
4447-
with CBOR content `Q` such that `Q.canister_id = ic_principal`.
4448-
4449-
The management canister offers the method `fetch_canister_logs`
4450-
that can be called as a query call and
4451-
returns logs of a requested canister.
4452-
4453-
Submitted request to `/api/v3/canister/<ECID>/query`
4454-
4455-
```html
4456-
4457-
E : Envelope
4458-
4459-
```
4460-
4461-
Conditions
4462-
4463-
```html
4464-
4465-
E.content = CanisterQuery Q
4466-
Q.canister_id = ic_principal
4467-
Q.method_name = 'fetch_canister_logs'
4468-
|Q.nonce| <= 32
4469-
is_effective_canister_id(E.content, ECID)
4470-
S.system_time <= Q.ingress_expiry or Q.sender = anonymous_id
4471-
Q.arg = candid(A)
4472-
A.canister_id ∈ verify_envelope(E, Q.sender, S.system_time)
4473-
(S[A.canister_id].canister_log_visibility = Public)
4474-
or
4475-
(S[A.canister_id].canister_log_visibility = Controllers and Q.sender in S[A.canister_id].controllers)
4476-
or
4477-
(S[A.canister_id].canister_log_visibility = AllowedViewers Principals and (Q.sender in S[A.canister_id].controllers or Q.sender in Principals))
4478-
4479-
```
4480-
4481-
Query response `R`:
4482-
4483-
```html
4484-
4485-
{status: "replied"; reply: {arg: candid(S.canister_logs[A.canister_id])}, signatures: Sigs}
4486-
4487-
```
4488-
4489-
where the query `Q`, the response `R`, and a certificate `Cert` that is obtained by requesting the path `/subnet` in a **separate** read state request to `/api/v3/canister/<ECID>/read_state` satisfy the following:
4490-
4491-
```html
4492-
4493-
verify_response(Q, R, Cert) ∧ lookup(["time"], Cert) = Found S.system_time // or "recent enough"
4494-
4495-
```
4496-
44974457
#### IC Management Canister: List canisters (query call) {#ic-mgmt-canister-list-canisters}
44984458

44994459
This section specifies the `list_canisters` management canister query call.

docs/references/ic-interface-spec/management-canister.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -954,6 +954,10 @@ To filter canister logs, an optional filter can be provided and have one of the
954954
- `by_idx` (`record { start : nat64; end : nat64 }`): only logs are returned whose `idx` is within the provided range (`start` is inclusive, but `end` is exclusive);
955955
- `by_timestamp_nanos` (`record { start : nat64; end : nat64 }`): only logs are returned whose `timestamp_nanos` is within the provided range (`start` is inclusive, but `end` is exclusive).
956956

957+
When the logs selected for the response do not all fit within a single response, they are trimmed to fit, and the direction of trimming differs between filtered and unfiltered reads:
958+
- An **unfiltered** read trims the **oldest** log records, so the response ends with the newest log record. This surfaces the most recent activity.
959+
- A **filtered** read trims the **newest** log records, so the response starts with the oldest log record satisfying the filter. This lets a filtered read page forward through logs starting from the beginning of the requested range.
960+
957961
Cycles to pay for the call must be explicitly transferred with the call, i.e., they are not automatically deducted from the caller's balance implicitly (e.g., as for inter-canister calls).
958962

959963
:::warning

0 commit comments

Comments
 (0)