-- Usage summed as it is written, per key, person, project and model: into -- five-minute slices (usage_5m), hours (usage_1h) and days (usage_1d). -- -- Every chart and total read the raw table, one row per request, and summed it -- again on every page view: fine for thousands of requests a day, and a full -- scan of tens of millions on a cluster in real use. The sums are kept in the -- transaction that writes the rows, so they never disagree with them; the raw -- table stays for following one request, and can be given a retention of its -- own (auth.usage_retention). -- -- Three widths because how well a slice compresses depends on traffic: many -- keys each sending a little leave a five-minute slice with nearly a row per -- request, which an hour or a day folds much further. A chart reads the -- coarsest width its slices are made of; a total since a moment reads the -- rows up to the next five-minute slice, those slices up to the hour, hours -- up to the day and days from there — exact, and a month in about thirty -- rows per key and model. -- -- Latency and time to first token are kept as histograms, a count per fixed -- bucket (ms: <=100, 250, 500, 1000, 2500, 5000, 10000, 30000, 60000, 120000, -- and above), which is what a percentile per team or model is read from after -- the rows are gone; a mean cannot do that. ttft_* counts only requests whose -- first token was measured. limited counts requests refused with 429 — a rate, -- token or budget limit — which are recorded with no tokens and no cost. CREATE TABLE usage_5m ( bucket INTEGER NOT NULL, key_id TEXT NOT NULL, user_id TEXT NOT NULL, project_id TEXT NOT NULL, model TEXT NOT NULL, served_model TEXT NOT NULL, requests INTEGER NOT NULL DEFAULT 0, errors INTEGER NOT NULL DEFAULT 0, limited INTEGER NOT NULL DEFAULT 0, prompt_tokens INTEGER NOT NULL DEFAULT 0, completion_tokens INTEGER NOT NULL DEFAULT 0, cost_micros INTEGER NOT NULL DEFAULT 0, latency_ms_sum INTEGER NOT NULL DEFAULT 0, queue_ms_sum INTEGER NOT NULL DEFAULT 0, ttft_ms_sum INTEGER NOT NULL DEFAULT 0, ttft_n INTEGER NOT NULL DEFAULT 0, last_ts INTEGER NOT NULL DEFAULT 0, lat_0 INTEGER NOT NULL DEFAULT 0, lat_1 INTEGER NOT NULL DEFAULT 0, lat_2 INTEGER NOT NULL DEFAULT 0, lat_3 INTEGER NOT NULL DEFAULT 0, lat_4 INTEGER NOT NULL DEFAULT 0, lat_5 INTEGER NOT NULL DEFAULT 0, lat_6 INTEGER NOT NULL DEFAULT 0, lat_7 INTEGER NOT NULL DEFAULT 0, lat_8 INTEGER NOT NULL DEFAULT 0, lat_9 INTEGER NOT NULL DEFAULT 0, lat_10 INTEGER NOT NULL DEFAULT 0, ttft_0 INTEGER NOT NULL DEFAULT 0, ttft_1 INTEGER NOT NULL DEFAULT 0, ttft_2 INTEGER NOT NULL DEFAULT 0, ttft_3 INTEGER NOT NULL DEFAULT 0, ttft_4 INTEGER NOT NULL DEFAULT 0, ttft_5 INTEGER NOT NULL DEFAULT 0, ttft_6 INTEGER NOT NULL DEFAULT 0, ttft_7 INTEGER NOT NULL DEFAULT 0, ttft_8 INTEGER NOT NULL DEFAULT 0, ttft_9 INTEGER NOT NULL DEFAULT 0, ttft_10 INTEGER NOT NULL DEFAULT 0, PRIMARY KEY (bucket, key_id, user_id, project_id, model, served_model) ); CREATE INDEX usage_5m_by_bucket ON usage_5m(bucket); CREATE INDEX usage_5m_by_project ON usage_5m(project_id, bucket); CREATE INDEX usage_5m_by_user ON usage_5m(user_id, bucket); CREATE INDEX usage_5m_by_key ON usage_5m(key_id, bucket); INSERT INTO usage_5m (bucket, key_id, user_id, project_id, model, served_model, requests, errors, limited, prompt_tokens, completion_tokens, cost_micros, latency_ms_sum, queue_ms_sum, ttft_ms_sum, ttft_n, last_ts, lat_0, lat_1, lat_2, lat_3, lat_4, lat_5, lat_6, lat_7, lat_8, lat_9, lat_10, ttft_0, ttft_1, ttft_2, ttft_3, ttft_4, ttft_5, ttft_6, ttft_7, ttft_8, ttft_9, ttft_10) SELECT (ts / 300000) * 300000, key_id, COALESCE(user_id, ''), project_id, model, served_model, COUNT(*), SUM(CASE WHEN status >= 400 THEN 1 ELSE 0 END), SUM(CASE WHEN status = 429 THEN 1 ELSE 0 END), SUM(prompt_tokens), SUM(completion_tokens), SUM(cost_micros), SUM(latency_ms), SUM(queue_ms), SUM(ttft_ms), SUM(CASE WHEN ttft_ms > 0 THEN 1 ELSE 0 END), MAX(ts), SUM(CASE WHEN latency_ms <= 100 THEN 1 ELSE 0 END), SUM(CASE WHEN latency_ms > 100 AND latency_ms <= 250 THEN 1 ELSE 0 END), SUM(CASE WHEN latency_ms > 250 AND latency_ms <= 500 THEN 1 ELSE 0 END), SUM(CASE WHEN latency_ms > 500 AND latency_ms <= 1000 THEN 1 ELSE 0 END), SUM(CASE WHEN latency_ms > 1000 AND latency_ms <= 2500 THEN 1 ELSE 0 END), SUM(CASE WHEN latency_ms > 2500 AND latency_ms <= 5000 THEN 1 ELSE 0 END), SUM(CASE WHEN latency_ms > 5000 AND latency_ms <= 10000 THEN 1 ELSE 0 END), SUM(CASE WHEN latency_ms > 10000 AND latency_ms <= 30000 THEN 1 ELSE 0 END), SUM(CASE WHEN latency_ms > 30000 AND latency_ms <= 60000 THEN 1 ELSE 0 END), SUM(CASE WHEN latency_ms > 60000 AND latency_ms <= 120000 THEN 1 ELSE 0 END), SUM(CASE WHEN latency_ms > 120000 THEN 1 ELSE 0 END), SUM(CASE WHEN ttft_ms > 0 AND ttft_ms <= 100 THEN 1 ELSE 0 END), SUM(CASE WHEN ttft_ms > 0 AND ttft_ms > 100 AND ttft_ms <= 250 THEN 1 ELSE 0 END), SUM(CASE WHEN ttft_ms > 0 AND ttft_ms > 250 AND ttft_ms <= 500 THEN 1 ELSE 0 END), SUM(CASE WHEN ttft_ms > 0 AND ttft_ms > 500 AND ttft_ms <= 1000 THEN 1 ELSE 0 END), SUM(CASE WHEN ttft_ms > 0 AND ttft_ms > 1000 AND ttft_ms <= 2500 THEN 1 ELSE 0 END), SUM(CASE WHEN ttft_ms > 0 AND ttft_ms > 2500 AND ttft_ms <= 5000 THEN 1 ELSE 0 END), SUM(CASE WHEN ttft_ms > 0 AND ttft_ms > 5000 AND ttft_ms <= 10000 THEN 1 ELSE 0 END), SUM(CASE WHEN ttft_ms > 0 AND ttft_ms > 10000 AND ttft_ms <= 30000 THEN 1 ELSE 0 END), SUM(CASE WHEN ttft_ms > 0 AND ttft_ms > 30000 AND ttft_ms <= 60000 THEN 1 ELSE 0 END), SUM(CASE WHEN ttft_ms > 0 AND ttft_ms > 60000 AND ttft_ms <= 120000 THEN 1 ELSE 0 END), SUM(CASE WHEN ttft_ms > 0 AND ttft_ms > 120000 THEN 1 ELSE 0 END) FROM usage GROUP BY 1, 2, 3, 4, 5, 6; CREATE TABLE usage_1h ( bucket INTEGER NOT NULL, key_id TEXT NOT NULL, user_id TEXT NOT NULL, project_id TEXT NOT NULL, model TEXT NOT NULL, served_model TEXT NOT NULL, requests INTEGER NOT NULL DEFAULT 0, errors INTEGER NOT NULL DEFAULT 0, limited INTEGER NOT NULL DEFAULT 0, prompt_tokens INTEGER NOT NULL DEFAULT 0, completion_tokens INTEGER NOT NULL DEFAULT 0, cost_micros INTEGER NOT NULL DEFAULT 0, latency_ms_sum INTEGER NOT NULL DEFAULT 0, queue_ms_sum INTEGER NOT NULL DEFAULT 0, ttft_ms_sum INTEGER NOT NULL DEFAULT 0, ttft_n INTEGER NOT NULL DEFAULT 0, last_ts INTEGER NOT NULL DEFAULT 0, lat_0 INTEGER NOT NULL DEFAULT 0, lat_1 INTEGER NOT NULL DEFAULT 0, lat_2 INTEGER NOT NULL DEFAULT 0, lat_3 INTEGER NOT NULL DEFAULT 0, lat_4 INTEGER NOT NULL DEFAULT 0, lat_5 INTEGER NOT NULL DEFAULT 0, lat_6 INTEGER NOT NULL DEFAULT 0, lat_7 INTEGER NOT NULL DEFAULT 0, lat_8 INTEGER NOT NULL DEFAULT 0, lat_9 INTEGER NOT NULL DEFAULT 0, lat_10 INTEGER NOT NULL DEFAULT 0, ttft_0 INTEGER NOT NULL DEFAULT 0, ttft_1 INTEGER NOT NULL DEFAULT 0, ttft_2 INTEGER NOT NULL DEFAULT 0, ttft_3 INTEGER NOT NULL DEFAULT 0, ttft_4 INTEGER NOT NULL DEFAULT 0, ttft_5 INTEGER NOT NULL DEFAULT 0, ttft_6 INTEGER NOT NULL DEFAULT 0, ttft_7 INTEGER NOT NULL DEFAULT 0, ttft_8 INTEGER NOT NULL DEFAULT 0, ttft_9 INTEGER NOT NULL DEFAULT 0, ttft_10 INTEGER NOT NULL DEFAULT 0, PRIMARY KEY (bucket, key_id, user_id, project_id, model, served_model) ); CREATE INDEX usage_1h_by_bucket ON usage_1h(bucket); CREATE INDEX usage_1h_by_project ON usage_1h(project_id, bucket); CREATE INDEX usage_1h_by_user ON usage_1h(user_id, bucket); CREATE INDEX usage_1h_by_key ON usage_1h(key_id, bucket); INSERT INTO usage_1h (bucket, key_id, user_id, project_id, model, served_model, requests, errors, limited, prompt_tokens, completion_tokens, cost_micros, latency_ms_sum, queue_ms_sum, ttft_ms_sum, ttft_n, last_ts, lat_0, lat_1, lat_2, lat_3, lat_4, lat_5, lat_6, lat_7, lat_8, lat_9, lat_10, ttft_0, ttft_1, ttft_2, ttft_3, ttft_4, ttft_5, ttft_6, ttft_7, ttft_8, ttft_9, ttft_10) SELECT (ts / 3600000) * 3600000, key_id, COALESCE(user_id, ''), project_id, model, served_model, COUNT(*), SUM(CASE WHEN status >= 400 THEN 1 ELSE 0 END), SUM(CASE WHEN status = 429 THEN 1 ELSE 0 END), SUM(prompt_tokens), SUM(completion_tokens), SUM(cost_micros), SUM(latency_ms), SUM(queue_ms), SUM(ttft_ms), SUM(CASE WHEN ttft_ms > 0 THEN 1 ELSE 0 END), MAX(ts), SUM(CASE WHEN latency_ms <= 100 THEN 1 ELSE 0 END), SUM(CASE WHEN latency_ms > 100 AND latency_ms <= 250 THEN 1 ELSE 0 END), SUM(CASE WHEN latency_ms > 250 AND latency_ms <= 500 THEN 1 ELSE 0 END), SUM(CASE WHEN latency_ms > 500 AND latency_ms <= 1000 THEN 1 ELSE 0 END), SUM(CASE WHEN latency_ms > 1000 AND latency_ms <= 2500 THEN 1 ELSE 0 END), SUM(CASE WHEN latency_ms > 2500 AND latency_ms <= 5000 THEN 1 ELSE 0 END), SUM(CASE WHEN latency_ms > 5000 AND latency_ms <= 10000 THEN 1 ELSE 0 END), SUM(CASE WHEN latency_ms > 10000 AND latency_ms <= 30000 THEN 1 ELSE 0 END), SUM(CASE WHEN latency_ms > 30000 AND latency_ms <= 60000 THEN 1 ELSE 0 END), SUM(CASE WHEN latency_ms > 60000 AND latency_ms <= 120000 THEN 1 ELSE 0 END), SUM(CASE WHEN latency_ms > 120000 THEN 1 ELSE 0 END), SUM(CASE WHEN ttft_ms > 0 AND ttft_ms <= 100 THEN 1 ELSE 0 END), SUM(CASE WHEN ttft_ms > 0 AND ttft_ms > 100 AND ttft_ms <= 250 THEN 1 ELSE 0 END), SUM(CASE WHEN ttft_ms > 0 AND ttft_ms > 250 AND ttft_ms <= 500 THEN 1 ELSE 0 END), SUM(CASE WHEN ttft_ms > 0 AND ttft_ms > 500 AND ttft_ms <= 1000 THEN 1 ELSE 0 END), SUM(CASE WHEN ttft_ms > 0 AND ttft_ms > 1000 AND ttft_ms <= 2500 THEN 1 ELSE 0 END), SUM(CASE WHEN ttft_ms > 0 AND ttft_ms > 2500 AND ttft_ms <= 5000 THEN 1 ELSE 0 END), SUM(CASE WHEN ttft_ms > 0 AND ttft_ms > 5000 AND ttft_ms <= 10000 THEN 1 ELSE 0 END), SUM(CASE WHEN ttft_ms > 0 AND ttft_ms > 10000 AND ttft_ms <= 30000 THEN 1 ELSE 0 END), SUM(CASE WHEN ttft_ms > 0 AND ttft_ms > 30000 AND ttft_ms <= 60000 THEN 1 ELSE 0 END), SUM(CASE WHEN ttft_ms > 0 AND ttft_ms > 60000 AND ttft_ms <= 120000 THEN 1 ELSE 0 END), SUM(CASE WHEN ttft_ms > 0 AND ttft_ms > 120000 THEN 1 ELSE 0 END) FROM usage GROUP BY 1, 2, 3, 4, 5, 6; CREATE TABLE usage_1d ( bucket INTEGER NOT NULL, key_id TEXT NOT NULL, user_id TEXT NOT NULL, project_id TEXT NOT NULL, model TEXT NOT NULL, served_model TEXT NOT NULL, requests INTEGER NOT NULL DEFAULT 0, errors INTEGER NOT NULL DEFAULT 0, limited INTEGER NOT NULL DEFAULT 0, prompt_tokens INTEGER NOT NULL DEFAULT 0, completion_tokens INTEGER NOT NULL DEFAULT 0, cost_micros INTEGER NOT NULL DEFAULT 0, latency_ms_sum INTEGER NOT NULL DEFAULT 0, queue_ms_sum INTEGER NOT NULL DEFAULT 0, ttft_ms_sum INTEGER NOT NULL DEFAULT 0, ttft_n INTEGER NOT NULL DEFAULT 0, last_ts INTEGER NOT NULL DEFAULT 0, lat_0 INTEGER NOT NULL DEFAULT 0, lat_1 INTEGER NOT NULL DEFAULT 0, lat_2 INTEGER NOT NULL DEFAULT 0, lat_3 INTEGER NOT NULL DEFAULT 0, lat_4 INTEGER NOT NULL DEFAULT 0, lat_5 INTEGER NOT NULL DEFAULT 0, lat_6 INTEGER NOT NULL DEFAULT 0, lat_7 INTEGER NOT NULL DEFAULT 0, lat_8 INTEGER NOT NULL DEFAULT 0, lat_9 INTEGER NOT NULL DEFAULT 0, lat_10 INTEGER NOT NULL DEFAULT 0, ttft_0 INTEGER NOT NULL DEFAULT 0, ttft_1 INTEGER NOT NULL DEFAULT 0, ttft_2 INTEGER NOT NULL DEFAULT 0, ttft_3 INTEGER NOT NULL DEFAULT 0, ttft_4 INTEGER NOT NULL DEFAULT 0, ttft_5 INTEGER NOT NULL DEFAULT 0, ttft_6 INTEGER NOT NULL DEFAULT 0, ttft_7 INTEGER NOT NULL DEFAULT 0, ttft_8 INTEGER NOT NULL DEFAULT 0, ttft_9 INTEGER NOT NULL DEFAULT 0, ttft_10 INTEGER NOT NULL DEFAULT 0, PRIMARY KEY (bucket, key_id, user_id, project_id, model, served_model) ); CREATE INDEX usage_1d_by_bucket ON usage_1d(bucket); CREATE INDEX usage_1d_by_project ON usage_1d(project_id, bucket); CREATE INDEX usage_1d_by_user ON usage_1d(user_id, bucket); CREATE INDEX usage_1d_by_key ON usage_1d(key_id, bucket); INSERT INTO usage_1d (bucket, key_id, user_id, project_id, model, served_model, requests, errors, limited, prompt_tokens, completion_tokens, cost_micros, latency_ms_sum, queue_ms_sum, ttft_ms_sum, ttft_n, last_ts, lat_0, lat_1, lat_2, lat_3, lat_4, lat_5, lat_6, lat_7, lat_8, lat_9, lat_10, ttft_0, ttft_1, ttft_2, ttft_3, ttft_4, ttft_5, ttft_6, ttft_7, ttft_8, ttft_9, ttft_10) SELECT (ts / 86400000) * 86400000, key_id, COALESCE(user_id, ''), project_id, model, served_model, COUNT(*), SUM(CASE WHEN status >= 400 THEN 1 ELSE 0 END), SUM(CASE WHEN status = 429 THEN 1 ELSE 0 END), SUM(prompt_tokens), SUM(completion_tokens), SUM(cost_micros), SUM(latency_ms), SUM(queue_ms), SUM(ttft_ms), SUM(CASE WHEN ttft_ms > 0 THEN 1 ELSE 0 END), MAX(ts), SUM(CASE WHEN latency_ms <= 100 THEN 1 ELSE 0 END), SUM(CASE WHEN latency_ms > 100 AND latency_ms <= 250 THEN 1 ELSE 0 END), SUM(CASE WHEN latency_ms > 250 AND latency_ms <= 500 THEN 1 ELSE 0 END), SUM(CASE WHEN latency_ms > 500 AND latency_ms <= 1000 THEN 1 ELSE 0 END), SUM(CASE WHEN latency_ms > 1000 AND latency_ms <= 2500 THEN 1 ELSE 0 END), SUM(CASE WHEN latency_ms > 2500 AND latency_ms <= 5000 THEN 1 ELSE 0 END), SUM(CASE WHEN latency_ms > 5000 AND latency_ms <= 10000 THEN 1 ELSE 0 END), SUM(CASE WHEN latency_ms > 10000 AND latency_ms <= 30000 THEN 1 ELSE 0 END), SUM(CASE WHEN latency_ms > 30000 AND latency_ms <= 60000 THEN 1 ELSE 0 END), SUM(CASE WHEN latency_ms > 60000 AND latency_ms <= 120000 THEN 1 ELSE 0 END), SUM(CASE WHEN latency_ms > 120000 THEN 1 ELSE 0 END), SUM(CASE WHEN ttft_ms > 0 AND ttft_ms <= 100 THEN 1 ELSE 0 END), SUM(CASE WHEN ttft_ms > 0 AND ttft_ms > 100 AND ttft_ms <= 250 THEN 1 ELSE 0 END), SUM(CASE WHEN ttft_ms > 0 AND ttft_ms > 250 AND ttft_ms <= 500 THEN 1 ELSE 0 END), SUM(CASE WHEN ttft_ms > 0 AND ttft_ms > 500 AND ttft_ms <= 1000 THEN 1 ELSE 0 END), SUM(CASE WHEN ttft_ms > 0 AND ttft_ms > 1000 AND ttft_ms <= 2500 THEN 1 ELSE 0 END), SUM(CASE WHEN ttft_ms > 0 AND ttft_ms > 2500 AND ttft_ms <= 5000 THEN 1 ELSE 0 END), SUM(CASE WHEN ttft_ms > 0 AND ttft_ms > 5000 AND ttft_ms <= 10000 THEN 1 ELSE 0 END), SUM(CASE WHEN ttft_ms > 0 AND ttft_ms > 10000 AND ttft_ms <= 30000 THEN 1 ELSE 0 END), SUM(CASE WHEN ttft_ms > 0 AND ttft_ms > 30000 AND ttft_ms <= 60000 THEN 1 ELSE 0 END), SUM(CASE WHEN ttft_ms > 0 AND ttft_ms > 60000 AND ttft_ms <= 120000 THEN 1 ELSE 0 END), SUM(CASE WHEN ttft_ms > 0 AND ttft_ms > 120000 THEN 1 ELSE 0 END) FROM usage GROUP BY 1, 2, 3, 4, 5, 6;