diff --git a/.env.example b/.env.example index aca1ba9640..d96a2c72d6 100644 --- a/.env.example +++ b/.env.example @@ -1364,6 +1364,10 @@ APP_LOG_TO_FILE=true # Default: 100000 # CALL_LOGS_TABLE_MAX_ROWS=100000 +# Force detailed request logging on or off, overriding the dashboard setting. +# Values: true | false | Default: unset (follow dashboard setting) +# ENABLE_REQUEST_LOGS=false + # Maximum age for orphaned active request log entries before the in-memory # pending-request reaper removes them. Accepts milliseconds. # Default: 3600000 (1 hour) diff --git a/changelog.d/fixes/9187-enable-request-logs.md b/changelog.d/fixes/9187-enable-request-logs.md new file mode 100644 index 0000000000..9ba8a3ca87 --- /dev/null +++ b/changelog.d/fixes/9187-enable-request-logs.md @@ -0,0 +1 @@ +- **fix(db):** honor the `ENABLE_REQUEST_LOGS` environment override for detailed request persistence. (thanks @RobertsXML) diff --git a/docs/reference/ENVIRONMENT.md b/docs/reference/ENVIRONMENT.md index b7ed53a2b0..244d7024eb 100644 --- a/docs/reference/ENVIRONMENT.md +++ b/docs/reference/ENVIRONMENT.md @@ -718,6 +718,7 @@ The logging system writes to both stdout and rotated log files. All configuratio | `CALL_LOG_RETENTION_DAYS` | `7` | Days to keep request/call log entries in the database. | | `CALL_LOG_MAX_ENTRIES` | `10000` | Max call log entries in the in-memory buffer. | | `CALL_LOGS_TABLE_MAX_ROWS` | `100000` | Max rows in the `call_logs` SQLite table before pruning. | +| `ENABLE_REQUEST_LOGS` | _(unset)_ | Force detailed request logging on or off, overriding the dashboard setting. | | `MAX_PENDING_REQUEST_AGE_MS` | `3600000` (1 hour) | Max age for orphaned active request log entries before in-memory cleanup. | | `CALL_LOG_PIPELINE_CAPTURE_STREAM_CHUNKS` | `true` | Store stream chunks in pipeline artifacts when `call_log_pipeline_enabled=true`. | | `CALL_LOG_PIPELINE_MAX_SIZE_KB` | `512` | Max pipeline call log artifact size in KB when `call_log_pipeline_enabled=true`. | diff --git a/src/lib/db/detailedLogs.ts b/src/lib/db/detailedLogs.ts index 7fdab54e15..0ff34fe773 100644 --- a/src/lib/db/detailedLogs.ts +++ b/src/lib/db/detailedLogs.ts @@ -54,6 +54,11 @@ export function resetRequestDetailLogsTableExistsCache(): void { /** Returns true if detailed logging is enabled in settings */ export async function isDetailedLoggingEnabled(): Promise { + const envOverride = process.env.ENABLE_REQUEST_LOGS; + if (envOverride !== undefined) { + return envOverride.trim().toLowerCase() === "true"; + } + try { const settings = await getSettings(); const val = settings.call_log_pipeline_enabled; @@ -120,8 +125,7 @@ export function getRequestDetailLogById(id: string): RequestDetailLog | null { if (!requestDetailLogsTableExists()) return null; const db = getDbInstance(); const row = db.prepare("SELECT * FROM request_detail_logs WHERE id = ?").get(id) as - | Record - | undefined; + Record | undefined; return row ? mapDetailedLogRow(row) : null; } diff --git a/tests/unit/db-detailed-logs.test.ts b/tests/unit/db-detailed-logs.test.ts index 639be62404..4469c7baf7 100644 --- a/tests/unit/db-detailed-logs.test.ts +++ b/tests/unit/db-detailed-logs.test.ts @@ -9,6 +9,7 @@ process.env.DATA_DIR = TEST_DATA_DIR; const ORIGINAL_PII_ENABLED = process.env.PII_RESPONSE_SANITIZATION; const ORIGINAL_PII_MODE = process.env.PII_RESPONSE_SANITIZATION_MODE; +const ORIGINAL_ENABLE_REQUEST_LOGS = process.env.ENABLE_REQUEST_LOGS; process.env.PII_RESPONSE_SANITIZATION = "true"; process.env.PII_RESPONSE_SANITIZATION_MODE = "redact"; process.env.API_KEY_SECRET = process.env.API_KEY_SECRET || "task-303-detailed-secret"; @@ -44,6 +45,7 @@ async function resetStorage() { } test.beforeEach(async () => { + delete process.env.ENABLE_REQUEST_LOGS; await resetStorage(); }); @@ -63,6 +65,12 @@ test.after(async () => { } else { process.env.PII_RESPONSE_SANITIZATION_MODE = ORIGINAL_PII_MODE; } + + if (ORIGINAL_ENABLE_REQUEST_LOGS === undefined) { + delete process.env.ENABLE_REQUEST_LOGS; + } else { + process.env.ENABLE_REQUEST_LOGS = ORIGINAL_ENABLE_REQUEST_LOGS; + } }); test("isDetailedLoggingEnabled follows the stored setting", async () => { @@ -73,6 +81,20 @@ test("isDetailedLoggingEnabled follows the stored setting", async () => { assert.equal(await detailedLogsDb.isDetailedLoggingEnabled(), true); }); +test("ENABLE_REQUEST_LOGS=false disables detailed logging despite the stored setting", async () => { + await settingsDb.updateSettings({ call_log_pipeline_enabled: "true" }); + process.env.ENABLE_REQUEST_LOGS = "false"; + + assert.equal(await detailedLogsDb.isDetailedLoggingEnabled(), false); +}); + +test("ENABLE_REQUEST_LOGS=true enables detailed logging despite the stored setting", async () => { + await settingsDb.updateSettings({ call_log_pipeline_enabled: "false" }); + process.env.ENABLE_REQUEST_LOGS = "true"; + + assert.equal(await detailedLogsDb.isDetailedLoggingEnabled(), true); +}); + test("legacy detailed log helpers tolerate databases without request_detail_logs", () => { const db = core.getDbInstance(); db.exec("DROP TABLE request_detail_logs");