Build the Usage Dashboard

aggregating logs into a dashboard

Part of: Ship & Monitor an LLM App (Capstone)

A pile of individual log records isn't a dashboard, it's a haystack. This lesson turns the raw log into the rolled-up numbers a dashboard shows: requests and cost broken down by model, plus the totals across everything. The technique is a single pass over your records, grouping as you go. Group, don't re-scan The naive way to get total cost for sonnet is to filter the whole log every time you need a number: sum(r["cost usd"] for r in log if r["model"] == "sonnet"). That works for one number. But a dashboard needs a dozen numbers, and re-scanning the whole log for each one is wasteful and easy to get subtly inconsistent. Do one grouped pass instead. defaultdict is what keeps this clean. The first time you touch by model["sonnet"], it creates a fresh {"count": 0, ...} bucket instead of raising a KeyError. You never write "have I seen this model before" checks. The dict handles it. Serving it The simplest dashboard is one more route that returns this dict as JSON, which any front-end can render as a table or chart: You don't need a charting library to start. A JSON summary endpoint, or even a plain HTML table built with an f-string, is a real dashboard. Polish comes later. The numbers

Challenge: Aggregate by Model