|
1 | | -import time |
| 1 | +import itertools |
2 | 2 | from datetime import datetime, timezone |
3 | 3 |
|
4 | 4 | from centml.sdk.api import get_centml_client |
5 | 5 |
|
6 | 6 | # --- Configuration --- |
7 | 7 | DEPLOYMENT_ID = 1234 # Replace with your deployment ID |
8 | 8 | 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 |
11 | 10 |
|
12 | 11 |
|
13 | 12 | def format_event(event) -> str: |
14 | 13 | ts = datetime.fromtimestamp(event.timestamp / 1000, tz=timezone.utc).isoformat() |
15 | | - return f"[{ts}] {event.message}" |
| 14 | + return f"[{ts}] {event.pod} {event.message}" |
16 | 15 |
|
17 | 16 |
|
18 | 17 | def main(): |
19 | 18 | 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): |
39 | 35 | print(format_event(event)) |
40 | 36 |
|
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): |
55 | 44 | # window = cclient.get_deployment_logs_range( |
56 | 45 | # DEPLOYMENT_ID, REVISION_NUMBER, start_time=t1_ms, end_time=t2_ms |
57 | 46 | # ) |
| 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 |
58 | 52 |
|
59 | 53 |
|
60 | 54 | if __name__ == "__main__": |
|
0 commit comments