const base = `/projects/${projectId}/service-instances/${serviceId}/units/logs`;const page = await api("GET", `${base}?limit=100`);for (const l of page.lines) console.log(l.at, `u${l.unit_ordinal}`, l.text);console.log(page.coverage);
Code
base = f"/projects/{project_id}/service-instances/{service_id}/units/logs"page = api("GET", base, limit=100)for l in page["lines"]: print(l["at"], f"u{l['unit_ordinal']}", l["text"])print(page["coverage"])
Scroll back
next_cursor is where to continue in the direction you read. Hand it back exactly as given. It is null once the 30 days of retention are exhausted.
Code
let cursor: string | null = null;for (let i = 0; i < 5; i++) { const q = new URLSearchParams({ limit: "500", ...(cursor ? { cursor } : {}) }); const p = await api("GET", `${base}?${q}`); for (const l of p.lines) console.log(l.at, l.text); cursor = p.next_cursor; if (!cursor) break;}
Code
cursor = Nonefor _ in range(5): p = api("GET", base, limit=500, **({"cursor": cursor} if cursor else {})) for l in p["lines"]: print(l["at"], l["text"]) cursor = p["next_cursor"] if not cursor: break
let follow: string | null = (await api("GET", `${base}?limit=20`)).follow_cursor;for (;;) { const q = new URLSearchParams({ direction: "forward", ...(follow ? { cursor: follow } : {}) }); const p = await api("GET", `${base}?${q}`); for (const l of p.lines) console.log(l.at, `u${l.unit_ordinal}`, l.text); follow = p.follow_cursor ?? follow; await new Promise((r) => setTimeout(r, p.poll_after_ms));}
Code
import timefollow = api("GET", base, limit=20)["follow_cursor"]while True: p = api("GET", base, direction="forward", **({"cursor": follow} if follow else {})) for l in p["lines"]: print(l["at"], f"u{l['unit_ordinal']}", l["text"]) follow = p["follow_cursor"] or follow time.sleep(p["poll_after_ms"] / 1000)
A line has the same id wherever it is read, so if you restart a follower you can drop lines you already printed.
Markers
markers holds lifecycle facts between the lines: a pod started, replaced or lost, and container_restarted with a reason such as OOMKilled or Error. When a container writes more than 500 lines per second, the rest go to an archive and an overflow marker says how many and when; nothing is lost, and the download route puts them back in order.
Download
GET .../units/logs/download returns a file with the archived overflow merged back in, for when you need every line.