From 2a6c2764313c8af6f29b73b149884daae8a86c86 Mon Sep 17 00:00:00 2001 From: Kalle <38327916+Sendouc@users.noreply.github.com> Date: Thu, 14 May 2026 15:30:18 +0300 Subject: [PATCH] Log SQL queries as spans --- app/db/sql.ts | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/app/db/sql.ts b/app/db/sql.ts index 5385b85ed..2868edeea 100644 --- a/app/db/sql.ts +++ b/app/db/sql.ts @@ -1,4 +1,5 @@ import { styleText } from "node:util"; +import * as Sentry from "@sentry/react-router"; import Database from "better-sqlite3"; import { Kysely, @@ -35,10 +36,30 @@ export const db = new Kysely({ dialect: new SqliteDialect({ database: sql, }), - log: LOG_LEVEL === "trunc" || LOG_LEVEL === "full" ? logQuery : logError, + log, plugins: [new ParseJSONResultsPlugin()], }); +function log(event: LogEvent) { + if (event.level === "query") { + // Backdated span so the query nests under the active loader/action span + // in Sentry's waterfall. `onlyIfParent: true` skips emission when there's + // no active trace (e.g. cron routines), avoiding orphan root spans. + Sentry.startInactiveSpan({ + name: event.query.sql, + op: "db.sql.query", + startTime: new Date(Date.now() - event.queryDurationMillis), + onlyIfParent: true, + }).end(); + } + + if (LOG_LEVEL === "trunc" || LOG_LEVEL === "full") { + logQuery(event); + } else { + logError(event); + } +} + function logQuery(event: LogEvent) { const isSelectQuery = Boolean((event.query.query as any).from?.froms);