Skip to content
209 linesCodeBlameRaw

Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.

Projects have Observability: their requests, logs, traces, metrics and errors, from apps on g1t.page with nothing to set up, and from software anywhere else over OpenTelemetry.1/**
2 * The tables of a project's store, in the Durable Object's own SQLite.
3 * Each step runs once, in order; the store keeps how many have run.
4 *
5 * Raw rows (requests, logs, spans, metric points) are kept for the
6 * project's retention. `rollups` are per-minute counts of requests by
7 * service, environment, deployment and route, with latency and CPU as
8 * histograms (./histogram.ts): what the overview's charts read, kept for
9 * `ROLLUP_DAYS` whatever the retention. Each minute also has one row of
10 * all routes together (method and route `*`), which the charts read.
11 */
12export const ROLLUP_DAYS = 90;
13
14export const MIGRATIONS: string[] = [
15 `
16 CREATE TABLE requests (
17 id TEXT PRIMARY KEY,
18 time_us INTEGER NOT NULL,
19 duration_us INTEGER NOT NULL DEFAULT 0,
20 trigger TEXT NOT NULL DEFAULT 'fetch',
21 method TEXT,
22 url TEXT,
23 route TEXT,
24 status INTEGER,
25 outcome TEXT NOT NULL DEFAULT 'ok',
26 cpu_ms REAL,
27 region TEXT,
28 country TEXT,
29 trace_id TEXT,
30 log_count INTEGER NOT NULL DEFAULT 0,
31 error_name TEXT,
32 error_message TEXT,
33 service TEXT NOT NULL DEFAULT '',
34 environment TEXT,
35 deployment_id TEXT,
36 commit_sha TEXT,
37 source TEXT NOT NULL,
38 -- Which halves have arrived: the dispatcher's (edge) and the app's.
39 edge INTEGER NOT NULL DEFAULT 0,
40 app INTEGER NOT NULL DEFAULT 0,
41 -- Counted into rollups yet.
42 rolled INTEGER NOT NULL DEFAULT 0
43 );
44 CREATE INDEX requests_by_time ON requests (time_us);
45 CREATE INDEX requests_by_trace ON requests (trace_id);
46 CREATE INDEX requests_to_roll ON requests (rolled, time_us);
47
48 CREATE TABLE logs (
49 id TEXT PRIMARY KEY,
50 time_us INTEGER NOT NULL,
51 severity_number INTEGER NOT NULL,
52 body TEXT NOT NULL,
53 trace_id TEXT,
54 span_id TEXT,
55 request_id TEXT,
56 attributes TEXT NOT NULL DEFAULT '{}',
57 service TEXT NOT NULL DEFAULT '',
58 environment TEXT,
59 deployment_id TEXT,
60 commit_sha TEXT,
61 source TEXT NOT NULL
62 );
63 CREATE INDEX logs_by_time ON logs (time_us);
64 CREATE INDEX logs_by_trace ON logs (trace_id);
65 CREATE INDEX logs_by_request ON logs (request_id);
66
67 CREATE TABLE spans (
68 trace_id TEXT NOT NULL,
69 span_id TEXT NOT NULL,
70 parent_span_id TEXT,
71 name TEXT NOT NULL,
72 kind TEXT NOT NULL,
73 start_us INTEGER NOT NULL,
74 duration_us INTEGER NOT NULL,
75 status TEXT NOT NULL,
76 status_message TEXT,
77 attributes TEXT NOT NULL DEFAULT '{}',
78 resource TEXT NOT NULL DEFAULT '{}',
79 events TEXT NOT NULL DEFAULT '[]',
80 links TEXT NOT NULL DEFAULT '[]',
81 service TEXT NOT NULL DEFAULT '',
82 environment TEXT,
83 deployment_id TEXT,
84 commit_sha TEXT,
85 source TEXT NOT NULL,
86 PRIMARY KEY (trace_id, span_id)
87 );
88 CREATE INDEX spans_by_time ON spans (start_us);
89
90 CREATE TABLE metric_points (
91 name TEXT NOT NULL,
92 kind TEXT NOT NULL,
93 time_us INTEGER NOT NULL,
94 value REAL,
95 count REAL,
96 sum REAL,
97 min REAL,
98 max REAL,
99 bounds TEXT,
100 counts TEXT,
101 quantiles TEXT,
102 monotonic INTEGER NOT NULL DEFAULT 0,
103 attributes TEXT NOT NULL DEFAULT '{}',
104 service TEXT NOT NULL DEFAULT '',
105 environment TEXT,
106 deployment_id TEXT,
107 source TEXT NOT NULL
108 );
109 CREATE INDEX metric_points_by_name ON metric_points (name, time_us);
110 CREATE INDEX metric_points_by_time ON metric_points (time_us);
111
112 CREATE TABLE metric_names (
113 name TEXT PRIMARY KEY,
114 kind TEXT NOT NULL,
115 unit TEXT NOT NULL DEFAULT '',
116 description TEXT NOT NULL DEFAULT '',
117 services TEXT NOT NULL DEFAULT '[]',
118 last_us INTEGER NOT NULL
119 );
120
121 CREATE TABLE rollups (
122 minute INTEGER NOT NULL,
123 service TEXT NOT NULL,
124 environment TEXT NOT NULL DEFAULT '',
125 deployment_id TEXT NOT NULL DEFAULT '',
126 commit_sha TEXT,
127 source TEXT NOT NULL,
128 method TEXT NOT NULL DEFAULT '',
129 route TEXT NOT NULL DEFAULT '',
130 requests INTEGER NOT NULL DEFAULT 0,
131 errors INTEGER NOT NULL DEFAULT 0,
132 s2 INTEGER NOT NULL DEFAULT 0,
133 s3 INTEGER NOT NULL DEFAULT 0,
134 s4 INTEGER NOT NULL DEFAULT 0,
135 s5 INTEGER NOT NULL DEFAULT 0,
136 latency TEXT NOT NULL DEFAULT '',
137 cpu TEXT NOT NULL DEFAULT '',
138 PRIMARY KEY (minute, service, environment, deployment_id, method, route)
139 );
140
141 CREATE TABLE error_groups (
142 fingerprint TEXT PRIMARY KEY,
143 name TEXT NOT NULL,
144 message TEXT NOT NULL,
145 stack TEXT,
146 service TEXT NOT NULL,
147 environment TEXT,
148 first_us INTEGER NOT NULL,
149 last_us INTEGER NOT NULL,
150 count INTEGER NOT NULL DEFAULT 0,
151 first_deployment_id TEXT,
152 last_request_id TEXT,
153 last_trace_id TEXT,
154 state TEXT NOT NULL DEFAULT 'open',
155 issue_number INTEGER
156 );
157 CREATE INDEX error_groups_by_last ON error_groups (last_us);
158
159 CREATE TABLE tokens (
160 id TEXT PRIMARY KEY,
161 name TEXT NOT NULL,
162 hash TEXT NOT NULL UNIQUE,
163 hint TEXT NOT NULL,
164 created_by TEXT,
165 created_us INTEGER NOT NULL,
166 last_used_us INTEGER,
167 managed INTEGER NOT NULL DEFAULT 0,
168 -- The deployments' own token is kept so each upload can bind it.
169 secret TEXT
170 );
171
172 CREATE TABLE exports (
173 id TEXT PRIMARY KEY,
174 name TEXT NOT NULL,
175 endpoint TEXT NOT NULL,
176 signals TEXT NOT NULL,
177 headers TEXT NOT NULL DEFAULT '{}',
178 enabled INTEGER NOT NULL DEFAULT 1,
179 last_error TEXT,
180 last_sent_us INTEGER
181 );
182
183 CREATE TABLE settings (key TEXT PRIMARY KEY, value TEXT NOT NULL);
184
185 CREATE TABLE usage (
186 month TEXT PRIMARY KEY,
187 ingested_bytes INTEGER NOT NULL DEFAULT 0,
188 requests INTEGER NOT NULL DEFAULT 0,
189 logs INTEGER NOT NULL DEFAULT 0,
190 spans INTEGER NOT NULL DEFAULT 0,
191 metric_points INTEGER NOT NULL DEFAULT 0
192 );
193 `,
194];
195
196/**
197 * Full-text search over log bodies, made apart from the tables: SQLite
198 * builds without FTS5 exist, and logs are still searched (more slowly,
199 * with LIKE) without it.
200 */
201export const FTS = `
202 CREATE VIRTUAL TABLE IF NOT EXISTS logs_fts USING fts5(body, content='logs', content_rowid='rowid');
203 CREATE TRIGGER IF NOT EXISTS logs_fts_insert AFTER INSERT ON logs BEGIN
204 INSERT INTO logs_fts (rowid, body) VALUES (new.rowid, new.body);
205 END;
206 CREATE TRIGGER IF NOT EXISTS logs_fts_delete AFTER DELETE ON logs BEGIN
207 INSERT INTO logs_fts (logs_fts, rowid, body) VALUES ('delete', old.rowid, old.body);
208 END;
209`;