Skip to content

Commit 929ed95

Browse files
committed
Document iter_deployment_logs in README and logs example
Signed-off-by: Honglin Cao <hocao@nvidia.com>
1 parent 59ff8db commit 929ed95

2 files changed

Lines changed: 44 additions & 44 deletions

File tree

‎README.md‎

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -55,13 +55,19 @@ delete the deployment automatically.
5555

5656
### Deployment logs SDK example
5757

58-
Logs are read per pod. Discover pod names with `get_deployment_pods()` (terminated
59-
pods still within log retention are included), then read with a
60-
`deployment_log_session()`: `fetch_older()` pages toward the beginning of history and
61-
`fetch_newer()` returns only new lines, while the session keeps the merged, ordered
62-
log in `.events`. `get_deployment_logs_range()` fetches a specific time window
63-
(epoch-millisecond bounds, both optional) and, with `pod=None`, merges every pod's
64-
stream chronologically. The same paging is available statelessly through
58+
`iter_deployment_logs()` streams a revision's logs lazily, oldest first, each line
59+
exactly once, with bounded memory however long the log is — by default merging every
60+
pod chronologically (each event carries its pod name). `follow=False` returns once
61+
caught up; `follow=True` keeps tailing and picks up new pods of the revision as they
62+
first log. `start_time` (epoch ms) bounds the beginning and `pod=` restricts to one
63+
pod — discover names with `get_deployment_pods()` (terminated pods still within log
64+
retention are included).
65+
66+
For non-streaming access: `get_deployment_logs_range()` fetches a specific time
67+
window as a list (epoch-millisecond bounds, both optional; `pod=None` merges every
68+
pod). A `deployment_log_session()` pages one pod statefully — `fetch_older()` toward
69+
the beginning of history, `fetch_newer()` for only-new lines — keeping the merged,
70+
ordered log in `.events`. The same paging is available statelessly through
6571
`get_deployment_logs(before=..., after=...)`, anchored on events you already hold
6672
or on a bare epoch-millisecond boundary:
6773

‎examples/sdk/get_deployment_logs.py‎

Lines changed: 31 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,54 @@
1-
import time
1+
import itertools
22
from datetime import datetime, timezone
33

44
from centml.sdk.api import get_centml_client
55

66
# --- Configuration ---
77
DEPLOYMENT_ID = 1234 # Replace with your deployment ID
88
REVISION_NUMBER = 10
9-
TAIL_SECONDS = 30 # How long to keep polling for new lines after reading history
10-
TAIL_LINES = 20 # How much history to print before tailing
9+
FOLLOW_LINES = 20 # How many tailed lines to print before stopping the follow
1110

1211

1312
def format_event(event) -> str:
1413
ts = datetime.fromtimestamp(event.timestamp / 1000, tz=timezone.utc).isoformat()
15-
return f"[{ts}] {event.message}"
14+
return f"[{ts}] {event.pod} {event.message}"
1615

1716

1817
def main():
1918
with get_centml_client() as cclient:
20-
# Logs are read per pod: discover the pods that have logged for this revision
21-
# (terminated pods within log retention are included).
22-
pods = cclient.get_deployment_pods(DEPLOYMENT_ID, REVISION_NUMBER)
23-
if not pods:
24-
print("No pods have logged for this revision yet.")
25-
return
26-
27-
pod = pods[0]
28-
print(f"Reading logs for deployment {DEPLOYMENT_ID} revision {REVISION_NUMBER}, pod {pod}\n")
29-
30-
# The session tracks what it has fetched and anchors every request itself.
31-
session = cclient.deployment_log_session(DEPLOYMENT_ID, REVISION_NUMBER, pod)
32-
33-
# Read the full history: newest page first, then page back to the beginning.
34-
while session.fetch_older():
35-
pass
36-
events = session.events
37-
print(f"Found {len(events)} log entries; showing the last {TAIL_LINES}:\n")
38-
for event in events[-TAIL_LINES:]:
19+
# Stream the revision's full history, all pods merged chronologically.
20+
# The iterator is lazy: pages are fetched as you consume it, and its held
21+
# state stays bounded no matter how many lines stream by.
22+
print(f"Logs for deployment {DEPLOYMENT_ID} revision {REVISION_NUMBER}:\n")
23+
count = 0
24+
for event in cclient.iter_deployment_logs(DEPLOYMENT_ID, REVISION_NUMBER):
25+
print(format_event(event))
26+
count += 1
27+
print(f"\nCaught up after {count} lines.")
28+
29+
# follow=True keeps tailing instead of returning: it re-polls caught-up pods
30+
# every poll_interval seconds and picks up new pods of the revision as they
31+
# first log. Stop by breaking out (or just abandon the iterator).
32+
print(f"\nFollowing; stopping after {FOLLOW_LINES} new lines...")
33+
stream = cclient.iter_deployment_logs(DEPLOYMENT_ID, REVISION_NUMBER, follow=True)
34+
for event in itertools.islice(stream, FOLLOW_LINES):
3935
print(format_event(event))
4036

41-
# Keep tailing: each call returns only the lines the session does not hold yet.
42-
print(f"\nPolling for new lines for {TAIL_SECONDS}s...")
43-
deadline = time.monotonic() + TAIL_SECONDS
44-
while time.monotonic() < deadline:
45-
for event in session.fetch_newer():
46-
print(format_event(event))
47-
time.sleep(2)
48-
49-
# The same paging is available statelessly via get_deployment_logs, anchored
50-
# on events you already hold — useful when you manage storage yourself:
51-
# page = cclient.get_deployment_logs(DEPLOYMENT_ID, REVISION_NUMBER, pod=pod) # tail
52-
# older = cclient.get_deployment_logs(..., pod=pod, before=page) # empty return = beginning
53-
# newer = cclient.get_deployment_logs(..., pod=pod, after=page) # empty return = nothing new
54-
# A specific time window (all pods merged, oldest first, pod on each event):
37+
# A single pod (discover names with get_deployment_pods) or a bounded start:
38+
# pods = cclient.get_deployment_pods(DEPLOYMENT_ID, REVISION_NUMBER)
39+
# for event in cclient.iter_deployment_logs(
40+
# DEPLOYMENT_ID, REVISION_NUMBER, pod=pods[0], start_time=t1_ms
41+
# ):
42+
# ...
43+
# A specific time window as a list (all pods merged, oldest first):
5544
# window = cclient.get_deployment_logs_range(
5645
# DEPLOYMENT_ID, REVISION_NUMBER, start_time=t1_ms, end_time=t2_ms
5746
# )
47+
# Manual paging, anchored on events you already hold — useful when you
48+
# manage storage yourself (deployment_log_session wraps this statefully):
49+
# page = cclient.get_deployment_logs(DEPLOYMENT_ID, REVISION_NUMBER, pod=pods[0]) # tail
50+
# older = cclient.get_deployment_logs(..., pod=pods[0], before=page) # empty return = beginning
51+
# newer = cclient.get_deployment_logs(..., pod=pods[0], after=page) # empty return = nothing new
5852

5953

6054
if __name__ == "__main__":

0 commit comments

Comments
 (0)