atproto pds in zig
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380const std = @import("std");const http_api = @import("api.zig");const router = @import("router.zig");const telemetry = @import("../internal/telemetry.zig");
const http = std.http;
const Row = struct { stats: telemetry.EndpointStats, path: []const u8, group: []const u8,};
const TrafficSummary = struct { requests: u64 = 0, failures: u64 = 0, writes: u64 = 0, proxy_count: u64 = 0, proxy_p95_ms: f64 = 0,};
const TROUBLE_US = 1000 * std.time.us_per_ms;const TROUBLE_LIMIT = 12;
pub fn serve(request: *http_api.Request) !void { var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); defer arena.deinit(); const body = try render(arena.allocator()); try http_api.respond(request, .ok, body, &html_headers);}
fn render(allocator: std.mem.Allocator) ![]const u8 { const snap = telemetry.snapshot(); const rows = try collectRows(allocator, snap); sortRows(rows);
const service_rows = try filterServiceRows(allocator, rows); const summary = summarizeTraffic(service_rows); const appview_rows = try renderRouteRows(allocator, try filterAppviewRows(allocator, service_rows), "no appview proxy samples yet."); const pds_rows = try renderRouteRows(allocator, try filterPdsRows(allocator, service_rows), "no local PDS samples yet."); const write_rows = try renderWriteRows(allocator, try filterWrites(allocator, rows)); const trouble_rows = try renderTroubleRows(allocator, snap); const uptime = try formatDuration(allocator, snap.uptime_s); const failure_rate = if (summary.requests == 0) "0%" else try std.fmt.allocPrint(allocator, "{d:.1}%", .{@as(f64, @floatFromInt(summary.failures)) * 100.0 / @as(f64, @floatFromInt(summary.requests))}); const proxy_p95 = try formatMaybeMs(allocator, summary.proxy_count, summary.proxy_p95_ms);
return std.fmt.allocPrint(allocator, \\<!doctype html> \\<html lang="en"> \\<head> \\ <meta charset="utf-8"> \\ <meta name="viewport" content="width=device-width, initial-scale=1"> \\ <title>zds / health</title> \\ <style> \\ :root{{--bg:#070807;--panel:#101210;--panel-2:#151915;--line:#273026;--text:#f0f1ec;--muted:#aaa69b;--dim:#69645c;--accent:#91adff;--green:#39c178;--pink:#f05f8e;color-scheme:dark}} \\ @media (prefers-color-scheme:light){{:root{{--bg:#f6f4ed;--panel:#fffdf7;--panel-2:#ece8dd;--line:#d8d0c0;--text:#161412;--muted:#625c53;--dim:#8f8679;--accent:#315dcb;--green:#1b7340;--pink:#b72e5c;color-scheme:light}}}} \\ *{{box-sizing:border-box}}html{{background:var(--bg)}}body{{margin:0;min-height:100vh;background:linear-gradient(135deg,color-mix(in srgb,var(--green) 13%,var(--bg)),var(--bg) 58%);color:var(--text);font:14px/1.5 ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono",monospace}} \\ a{{color:inherit}}.shell{{width:min(100%,780px);margin:0 auto;padding:22px 16px 40px}}header{{display:flex;justify-content:space-between;align-items:center;gap:14px;margin-bottom:26px;color:var(--muted);font-size:12px}}.brand{{color:var(--text);font-weight:700;text-decoration:none}}nav{{display:flex;gap:10px;flex-wrap:wrap}}nav a{{color:var(--muted);text-decoration:none}}nav a:hover{{color:var(--text)}}h1{{font-size:clamp(34px,8vw,68px);line-height:.95;margin:0 0 10px;letter-spacing:0}}.lede{{margin:0 0 22px;color:var(--muted);max-width:64ch}} \\ .metrics{{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:10px;margin:0 0 18px}}.metric{{border:1px solid var(--line);background:color-mix(in srgb,var(--panel) 88%,transparent);border-radius:8px;padding:12px}}.label{{color:var(--dim);font-size:11px;text-transform:lowercase}}.value{{font-size:22px;color:var(--text);font-variant-numeric:tabular-nums}} \\ section{{margin-top:18px}}.section-head{{display:flex;justify-content:space-between;align-items:end;gap:12px;margin-bottom:8px}}h2{{font-size:13px;margin:0;color:var(--text);font-weight:700}}.hint{{color:var(--dim);font-size:11px;margin:0}}.table-wrap{{overflow:auto;border:1px solid var(--line);border-radius:8px;background:color-mix(in srgb,var(--panel) 86%,transparent)}}table{{width:100%;border-collapse:collapse;min-width:720px}}th,td{{padding:9px 10px;border-bottom:1px solid color-mix(in srgb,var(--line) 74%,transparent);text-align:left;vertical-align:top}}th{{position:sticky;top:0;background:var(--panel-2);color:var(--dim);font-size:11px;font-weight:400;text-transform:lowercase}}td{{font-variant-numeric:tabular-nums}}tr:last-child td{{border-bottom:0}}.method{{display:inline-block;border-radius:7px;padding:2px 5px;color:#071008;font-size:11px;font-weight:700}}.get{{background:#7dd3fc}}.head{{background:#f5d85d}}.post{{background:var(--green)}}.options,.other{{background:var(--muted)}}.path{{overflow-wrap:anywhere;color:var(--text)}}.group{{color:var(--dim)}}.empty{{padding:16px;color:var(--dim)}}.bad{{color:var(--pink)}}.good{{color:var(--green)}}@media (max-width:620px){{.shell{{padding-inline:12px}}header{{align-items:flex-start;flex-direction:column}}.value{{font-size:19px}}table{{min-width:0}}th,td{{padding:8px 7px}}th:nth-child(3),td:nth-child(3),th:nth-child(7),td:nth-child(7),th:nth-child(8),td:nth-child(8),th:nth-child(9),td:nth-child(9){{display:none}}}} \\ </style> \\</head> \\<body> \\ <main class="shell"> \\ <header><a class="brand" href="/">zds</a><nav><a href="/">home</a><a href="/api">api</a><a href="/xrpc/_health">health</a></nav></header> \\ <h1>pds health</h1> \\ <p class="lede">Live health for this PDS. Counts reset when the service restarts; this page does not count its own refreshes.</p> \\ <div class="metrics"> \\ <div class="metric"><div class="label">status</div><div class="value good">ok</div></div> \\ <div class="metric"><div class="label">uptime</div><div class="value">{s}</div></div> \\ <div class="metric"><div class="label">api requests</div><div class="value">{d}</div></div> \\ <div class="metric"><div class="label">writes</div><div class="value">{d}</div></div> \\ <div class="metric"><div class="label">appview p95</div><div class="value">{s}</div></div> \\ <div class="metric"><div class="label">failures</div><div class="value {s}">{d}</div></div> \\ <div class="metric"><div class="label">failure rate</div><div class="value">{s}</div></div> \\ </div> \\ <section> \\ <div class="section-head"><h2>needs attention</h2><p class="hint">newest first; only 1s+ requests or server failures</p></div> \\ <div class="table-wrap">{s}</div> \\ </section> \\ <section> \\ <div class="section-head"><h2>writes</h2><p class="hint">likes usually createRecord; batches use applyWrites</p></div> \\ <div class="table-wrap">{s}</div> \\ </section> \\ <section> \\ <div class="section-head"><h2>appview proxy</h2><p class="hint">client reads forwarded to Bluesky/chat appviews</p></div> \\ <div class="table-wrap">{s}</div> \\ </section> \\ <section> \\ <div class="section-head"><h2>pds routes</h2><p class="hint">local repository, sync, auth, and preference routes</p></div> \\ <div class="table-wrap">{s}</div> \\ </section> \\ </main> \\</body> \\</html> , .{ uptime, summary.requests, summary.writes, proxy_p95, if (summary.failures == 0) "good" else "bad", summary.failures, failure_rate, trouble_rows, write_rows, appview_rows, pds_rows, });}
fn collectRows(allocator: std.mem.Allocator, snap: telemetry.Snapshot) ![]Row { var rows: std.ArrayList(Row) = .empty; for (0..@typeInfo(router.Route).@"enum".fields.len) |route_idx| { for (0..@typeInfo(telemetry.Method).@"enum".fields.len) |method_idx| { const stats = snap.routes[route_idx][method_idx]; if (stats.count == 0) continue; const meta = endpointMeta(stats.route, stats.method); try rows.append(allocator, .{ .stats = stats, .path = meta.path, .group = meta.group }); } } return rows.toOwnedSlice(allocator);}
fn renderRows(allocator: std.mem.Allocator, rows: []const Row) ![]const u8 { if (rows.len == 0) return allocator.dupe(u8, "<div class=\"empty\">no samples yet.</div>"); var out: std.Io.Writer.Allocating = .init(allocator); defer out.deinit(); try out.writer.writeAll("<table><thead><tr><th>method</th><th>route</th><th>group</th><th>count</th><th>p50</th><th>p95</th><th>avg</th><th>max</th><th>fail</th></tr></thead><tbody>"); for (rows) |row| { try out.writer.print( "<tr><td><span class=\"method {s}\">{s}</span></td><td class=\"path\">{s}</td><td class=\"group\">{s}</td><td>{d}</td><td>{d:.1}ms</td><td>{d:.1}ms</td><td>{d:.1}ms</td><td>{d:.1}ms</td><td>{d}</td></tr>", .{ @tagName(row.stats.method), row.stats.method.label(), row.path, row.group, row.stats.count, row.stats.p50_ms, row.stats.p95_ms, row.stats.avg_ms, row.stats.max_ms, row.stats.failure_count, }, ); } try out.writer.writeAll("</tbody></table>"); return out.toOwnedSlice();}
fn renderRouteRows(allocator: std.mem.Allocator, rows: []const Row, empty: []const u8) ![]const u8 { if (rows.len == 0) return std.fmt.allocPrint(allocator, "<div class=\"empty\">{s}</div>", .{empty}); var out: std.Io.Writer.Allocating = .init(allocator); defer out.deinit(); try out.writer.writeAll("<table><thead><tr><th>method</th><th>route</th><th>count</th><th>p50</th><th>p95</th><th>max</th><th>fail</th></tr></thead><tbody>"); for (rows) |row| { try out.writer.print( "<tr><td><span class=\"method {s}\">{s}</span></td><td class=\"path\">{s}</td><td>{d}</td><td>{d:.1}ms</td><td>{d:.1}ms</td><td>{d:.1}ms</td><td>{d}</td></tr>", .{ @tagName(row.stats.method), row.stats.method.label(), row.path, row.stats.count, row.stats.p50_ms, row.stats.p95_ms, row.stats.max_ms, row.stats.failure_count, }, ); } try out.writer.writeAll("</tbody></table>"); return out.toOwnedSlice();}
fn renderWriteRows(allocator: std.mem.Allocator, rows: []const Row) ![]const u8 { if (rows.len == 0) return allocator.dupe(u8, "<div class=\"empty\">no write samples yet.</div>"); var out: std.Io.Writer.Allocating = .init(allocator); defer out.deinit(); try out.writer.writeAll("<table><thead><tr><th>kind</th><th>endpoint</th><th>count</th><th>p50</th><th>p95</th><th>max</th><th>fail</th></tr></thead><tbody>"); for (rows) |row| { try out.writer.print( "<tr><td class=\"path\">{s}</td><td class=\"path\">{s}</td><td>{d}</td><td>{d:.1}ms</td><td>{d:.1}ms</td><td>{d:.1}ms</td><td>{d}</td></tr>", .{ writeKind(row.stats.route), row.path, row.stats.count, row.stats.p50_ms, row.stats.p95_ms, row.stats.max_ms, row.stats.failure_count, }, ); } try out.writer.writeAll("</tbody></table>"); return out.toOwnedSlice();}
fn renderTroubleRows(allocator: std.mem.Allocator, snap: telemetry.Snapshot) ![]const u8 { var out: std.Io.Writer.Allocating = .init(allocator); defer out.deinit(); try out.writer.writeAll("<table><thead><tr><th>when</th><th>method</th><th>class</th><th>route</th><th>elapsed</th><th>status</th></tr></thead><tbody>"); var i = snap.slow_len; var rendered: usize = 0; while (i > 0) { i -= 1; const item = snap.slow_requests[i]; if (!needsAttention(item)) continue; try out.writer.print( "<tr><td>{d}s ago</td><td><span class=\"method {s}\">{s}</span></td><td class=\"group\">{s}</td><td class=\"path\">{s}</td><td>{d:.1}ms</td><td class=\"{s}\">{d}</td></tr>", .{ if (item.at_s > 0) @max(0, snap.started_at_s + @as(i64, @intCast(snap.uptime_s)) - item.at_s) else 0, @tagName(item.method), item.method.label(), item.class.label(), item.labelText(), @as(f64, @floatFromInt(item.elapsed_us)) / 1000.0, statusClass(item), item.status, }, ); rendered += 1; if (rendered == TROUBLE_LIMIT) break; } if (rendered == 0) return allocator.dupe(u8, "<div class=\"empty\">nothing needs attention right now.</div>"); try out.writer.writeAll("</tbody></table>"); return out.toOwnedSlice();}
fn needsAttention(item: telemetry.SlowRequest) bool { return item.failed() or item.elapsed_us >= TROUBLE_US;}
fn statusClass(item: telemetry.SlowRequest) []const u8 { if (item.failed()) return "bad"; if (item.status >= 400) return "group"; return "good";}
fn filterWrites(allocator: std.mem.Allocator, rows: []const Row) ![]Row { var filtered: std.ArrayList(Row) = .empty; for (rows) |row| { if (isWriteRoute(row.stats.route, row.stats.method)) try filtered.append(allocator, row); } return filtered.toOwnedSlice(allocator);}
fn filterServiceRows(allocator: std.mem.Allocator, rows: []const Row) ![]Row { var filtered: std.ArrayList(Row) = .empty; for (rows) |row| { if (!isNoiseRoute(row.stats.route)) try filtered.append(allocator, row); } return filtered.toOwnedSlice(allocator);}
fn filterAppviewRows(allocator: std.mem.Allocator, rows: []const Row) ![]Row { var filtered: std.ArrayList(Row) = .empty; for (rows) |row| { if (row.stats.route == .proxy_xrpc) try filtered.append(allocator, row); } return filtered.toOwnedSlice(allocator);}
fn filterPdsRows(allocator: std.mem.Allocator, rows: []const Row) ![]Row { var filtered: std.ArrayList(Row) = .empty; for (rows) |row| { if (row.stats.route != .proxy_xrpc and !isWriteRoute(row.stats.route, row.stats.method)) { try filtered.append(allocator, row); } } return filtered.toOwnedSlice(allocator);}
fn summarizeTraffic(rows: []const Row) TrafficSummary { var summary: TrafficSummary = .{}; for (rows) |row| { summary.requests += row.stats.count; summary.failures += row.stats.failure_count; if (isWriteRoute(row.stats.route, row.stats.method)) summary.writes += row.stats.count; if (row.stats.route == .proxy_xrpc and row.stats.method == .get) { summary.proxy_count += row.stats.count; summary.proxy_p95_ms = @max(summary.proxy_p95_ms, row.stats.p95_ms); } } return summary;}
fn sortRows(rows: []Row) void { std.mem.sort(Row, rows, {}, struct { fn lessThan(_: void, a: Row, b: Row) bool { if (a.stats.p95_ms != b.stats.p95_ms) return a.stats.p95_ms > b.stats.p95_ms; if (a.stats.max_ms != b.stats.max_ms) return a.stats.max_ms > b.stats.max_ms; return a.stats.count > b.stats.count; } }.lessThan);}
fn isNoiseRoute(route: router.Route) bool { return switch (route) { .stats_page, .health, .root, .api_docs, .api_openapi, .favicon, .og_image, .cors_preflight, .not_found, => true, else => false, };}
fn isWriteRoute(route: router.Route, method: telemetry.Method) bool { if (method != .post) return false; return switch (route) { .app_preferences_put, .repo_create_record, .repo_put_record, .repo_delete_record, .repo_apply_writes, .repo_import_repo, .repo_upload_blob, .permissioned_data, => true, else => false, };}
fn writeKind(route: router.Route) []const u8 { return switch (route) { .repo_create_record => "single record create", .repo_put_record => "replace by rkey", .repo_delete_record => "record delete", .repo_apply_writes => "batched repo writes", .repo_import_repo => "repo import", .repo_upload_blob => "blob upload", .app_preferences_put => "preferences update", .permissioned_data => "permissioned-data write", else => "write", };}
const EndpointMeta = struct { path: []const u8, group: []const u8 };
fn endpointMeta(route: router.Route, method: telemetry.Method) EndpointMeta { if (route == .proxy_xrpc) return .{ .path = "proxied XRPC", .group = "proxy" }; if (route == .not_found) return .{ .path = "unmatched request", .group = "unknown" }; for (router.endpoints) |endpoint| { if (endpoint.route == route and std.mem.eql(u8, endpoint.method, method.label())) return .{ .path = endpoint.path, .group = endpoint.group }; } for (router.endpoints) |endpoint| { if (endpoint.route == route) return .{ .path = endpoint.path, .group = endpoint.group }; } return .{ .path = @tagName(route), .group = "internal" };}
fn formatDuration(allocator: std.mem.Allocator, seconds: u64) ![]const u8 { const days = seconds / 86_400; const hours = (seconds % 86_400) / 3_600; const minutes = (seconds % 3_600) / 60; if (days > 0) return std.fmt.allocPrint(allocator, "{d}d {d}h", .{ days, hours }); if (hours > 0) return std.fmt.allocPrint(allocator, "{d}h {d}m", .{ hours, minutes }); return std.fmt.allocPrint(allocator, "{d}m", .{minutes});}
fn formatMaybeMs(allocator: std.mem.Allocator, count: u64, ms: f64) ![]const u8 { if (count == 0) return allocator.dupe(u8, "none"); return std.fmt.allocPrint(allocator, "{d:.1}ms", .{ms});}
const html_headers = [_]http.Header{ .{ .name = "content-type", .value = "text/html; charset=utf-8" }, .{ .name = "cache-control", .value = "no-store" }, .{ .name = "access-control-allow-origin", .value = "*" }, .{ .name = "access-control-allow-private-network", .value = "true" }, .{ .name = "connection", .value = "close" },};