From 758a5538c525b2364764b14f6bb18760c647673a Mon Sep 17 00:00:00 2001 From: Dotta Date: Thu, 5 Mar 2026 07:39:05 -0600 Subject: [PATCH] Improve 500 error logging with actual error details and correct log levels pino-http was logging 500s at INFO level with a generic "failed with status code 500" message. Now 500s log at ERROR level and include the actual error (message, stack, name) via res.locals handoff from the error handler. Co-Authored-By: Claude Opus 4.6 --- server/src/middleware/error-handler.ts | 3 +++ server/src/middleware/logger.ts | 26 +++++++++++++++++++++++++- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/server/src/middleware/error-handler.ts b/server/src/middleware/error-handler.ts index 35a298db..e9d6c5a8 100644 --- a/server/src/middleware/error-handler.ts +++ b/server/src/middleware/error-handler.ts @@ -26,6 +26,9 @@ export function errorHandler( ? { message: err.message, stack: err.stack, name: err.name } : { raw: err }; + // Attach the real error so pino-http can include it in its response log + res.locals.serverError = errObj; + logger.error( { err: errObj, method: req.method, url: req.originalUrl }, "Unhandled error: %s %s — %s", diff --git a/server/src/middleware/logger.ts b/server/src/middleware/logger.ts index bfcebd22..8f915b85 100644 --- a/server/src/middleware/logger.ts +++ b/server/src/middleware/logger.ts @@ -2,8 +2,20 @@ import path from "node:path"; import fs from "node:fs"; import pino from "pino"; import { pinoHttp } from "pino-http"; +import { readConfigFile } from "../config-file.js"; +import { resolveDefaultLogsDir, resolveHomeAwarePath } from "../home-paths.js"; -const logDir = path.resolve(process.cwd(), ".paperclip", "logs"); +function resolveServerLogDir(): string { + const envOverride = process.env.PAPERCLIP_LOG_DIR?.trim(); + if (envOverride) return resolveHomeAwarePath(envOverride); + + const fileLogDir = readConfigFile()?.logging.logDir?.trim(); + if (fileLogDir) return resolveHomeAwarePath(fileLogDir); + + return resolveDefaultLogsDir(); +} + +const logDir = resolveServerLogDir(); fs.mkdirSync(logDir, { recursive: true }); const logFile = path.join(logDir, "server.log"); @@ -32,10 +44,22 @@ export const logger = pino({ export const httpLogger = pinoHttp({ logger, + customLogLevel(_req, res, err) { + if (err || res.statusCode >= 500) return "error"; + if (res.statusCode >= 400) return "warn"; + return "info"; + }, customSuccessMessage(req, res) { return `${req.method} ${req.url} ${res.statusCode}`; }, customErrorMessage(req, res) { return `${req.method} ${req.url} ${res.statusCode}`; }, + customProps(_req, res) { + const serverError = (res as any).locals?.serverError; + if (serverError) { + return { serverError }; + } + return {}; + }, });