From 97cdf039b2cf60335998a63d39bb98df3201ecf2 Mon Sep 17 00:00:00 2001 From: Jan Leon Date: Wed, 27 May 2026 12:48:58 +0200 Subject: [PATCH] fix(logging): sync database log settings with pipeline toggle --- src/app/api/logs/detail/route.ts | 9 +++++ src/lib/db/databaseSettings.ts | 36 +++++++++++++++++++ .../database-settings-maintenance.test.ts | 18 ++++++++++ 3 files changed, 63 insertions(+) diff --git a/src/app/api/logs/detail/route.ts b/src/app/api/logs/detail/route.ts index 4a85321e42..90fa93ca2d 100644 --- a/src/app/api/logs/detail/route.ts +++ b/src/app/api/logs/detail/route.ts @@ -9,6 +9,7 @@ import { getRequestDetailLogCount, isDetailedLoggingEnabled, } from "@/lib/db/detailedLogs"; +import { getUserDatabaseSettings, updateDatabaseSettings } from "@/lib/db/databaseSettings"; import { updateSettings } from "@/lib/db/settings"; export const dynamic = "force-dynamic"; @@ -36,6 +37,14 @@ export async function POST(req: NextRequest) { const enabled = body.enabled === true || body.enabled === "1"; await updateSettings({ call_log_pipeline_enabled: enabled }); + const databaseSettings = getUserDatabaseSettings(); + updateDatabaseSettings({ + logs: { + ...databaseSettings.logs, + detailedLogsEnabled: enabled, + callLogPipelineEnabled: enabled, + }, + }); return NextResponse.json({ success: true, diff --git a/src/lib/db/databaseSettings.ts b/src/lib/db/databaseSettings.ts index f9fa21b109..1d890151a4 100644 --- a/src/lib/db/databaseSettings.ts +++ b/src/lib/db/databaseSettings.ts @@ -83,6 +83,17 @@ function parseStoredValue(rawValue: unknown): unknown { } } +function toBooleanSetting(value: unknown): boolean | null { + if (typeof value === "boolean") return value; + if (typeof value === "number") return value !== 0; + if (typeof value !== "string") return null; + + const normalized = value.trim().toLowerCase(); + if (["1", "true", "yes", "on"].includes(normalized)) return true; + if (["0", "false", "no", "off"].includes(normalized)) return false; + return null; +} + function readNamespace(namespace: string): Record { const db = getDbInstance(); const rows = db @@ -119,6 +130,18 @@ function mergeTopLevelSections(target: UserDatabaseSettings, values: Record) { + const pipelineEnabled = toBooleanSetting(values.call_log_pipeline_enabled); + if (pipelineEnabled !== null) { + target.logs.callLogPipelineEnabled = pipelineEnabled; + } + + const legacyDetailedEnabled = toBooleanSetting(values.detailed_logs_enabled); + if (legacyDetailedEnabled !== null) { + target.logs.detailedLogsEnabled = legacyDetailedEnabled; + } +} + function mergeDatabaseSettingsNamespace( target: UserDatabaseSettings, values: Record @@ -195,6 +218,7 @@ export function getUserDatabaseSettings(): UserDatabaseSettings { mergeTopLevelSections(settings, mainSettings); mergeDatabaseSettingsNamespace(settings, readNamespace(DATABASE_SETTINGS_NAMESPACE)); + mergeRuntimeLogSettings(settings, mainSettings); return settings; } @@ -236,6 +260,14 @@ export function updateDatabaseSettings( const insert = db.prepare( "INSERT OR REPLACE INTO key_value (namespace, key, value) VALUES (?, ?, ?)" ); + const settingsInsert = db.prepare( + "INSERT OR REPLACE INTO key_value (namespace, key, value) VALUES ('settings', ?, ?)" + ); + + const requestedLogs = updates.logs as Partial | undefined; + const pipelineEnabled = + requestedLogs?.callLogPipelineEnabled ?? requestedLogs?.detailedLogsEnabled; + const tx = db.transaction(() => { for (const section of DATABASE_SETTINGS_SECTIONS) { const sectionValues = nextSettings[section] as Record; @@ -244,6 +276,10 @@ export function updateDatabaseSettings( insert.run(DATABASE_SETTINGS_NAMESPACE, `${section}.${key}`, JSON.stringify(value)); } } + + if (pipelineEnabled !== undefined) { + settingsInsert.run("call_log_pipeline_enabled", JSON.stringify(Boolean(pipelineEnabled))); + } }); tx(); diff --git a/tests/unit/database-settings-maintenance.test.ts b/tests/unit/database-settings-maintenance.test.ts index 299c7fa370..fa553eb687 100644 --- a/tests/unit/database-settings-maintenance.test.ts +++ b/tests/unit/database-settings-maintenance.test.ts @@ -11,6 +11,7 @@ process.env.DISABLE_SQLITE_AUTO_BACKUP = "true"; const core = await import("../../src/lib/db/core.ts"); const databaseSettings = await import("../../src/lib/db/databaseSettings.ts"); const databaseSettingsRoute = await import("../../src/app/api/settings/database/route.ts"); +const settingsDb = await import("../../src/lib/db/settings.ts"); const cleanup = await import("../../src/lib/db/cleanup.ts"); const aggregateHistory = await import("../../src/lib/usage/aggregateHistory.ts"); @@ -101,6 +102,23 @@ test("database settings reader supports legacy flat keys and lets nested saves w assert.equal(databaseSettings.getUserDatabaseSettings().retention.callLogs, 7); }); +test("database log settings mirror the runtime pipeline toggle", async () => { + await settingsDb.updateSettings({ call_log_pipeline_enabled: false }); + + assert.equal(databaseSettings.getUserDatabaseSettings().logs.callLogPipelineEnabled, false); + + databaseSettings.updateDatabaseSettings({ + logs: { + ...databaseSettings.getUserDatabaseSettings().logs, + callLogPipelineEnabled: true, + }, + }); + + const settings = await settingsDb.getSettings(); + assert.equal(settings.call_log_pipeline_enabled, true); + assert.equal(databaseSettings.getUserDatabaseSettings().logs.callLogPipelineEnabled, true); +}); + test("purgeDetailedLogs deletes request_detail_logs", async () => { const db = core.getDbInstance(); db.prepare("INSERT INTO request_detail_logs (id, timestamp, duration_ms) VALUES (?, ?, ?)").run(