Enrich 500 error logs with request context and actual error messages

- pino-http customErrorMessage now includes the real error message
- customProps includes reqBody, reqParams, reqQuery, and routePath for 4xx/5xx
- Error handler logs full request context (body, params, query) for both
  HttpError 500s and unhandled errors

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Dotta
2026-03-06 10:58:22 -06:00
parent 1179d7e75a
commit 8151331375
2 changed files with 44 additions and 4 deletions

View File

@@ -12,6 +12,21 @@ export function errorHandler(
if (err instanceof HttpError) { if (err instanceof HttpError) {
if (err.status >= 500) { if (err.status >= 500) {
(res as any).err = err; (res as any).err = err;
logger.error(
{
err: { message: err.message, stack: err.stack, name: err.name, details: err.details },
method: req.method,
url: req.originalUrl,
reqBody: req.body,
reqParams: req.params,
reqQuery: req.query,
},
"HttpError %d: %s %s — %s",
err.status,
req.method,
req.originalUrl,
err.message,
);
} }
res.status(err.status).json({ res.status(err.status).json({
error: err.message, error: err.message,
@@ -35,7 +50,14 @@ export function errorHandler(
(res as any).err = realError; (res as any).err = realError;
logger.error( logger.error(
{ err: errObj, method: req.method, url: req.originalUrl }, {
err: errObj,
method: req.method,
url: req.originalUrl,
reqBody: req.body,
reqParams: req.params,
reqQuery: req.query,
},
"Unhandled error: %s %s — %s", "Unhandled error: %s %s — %s",
req.method, req.method,
req.originalUrl, req.originalUrl,

View File

@@ -52,10 +52,28 @@ export const httpLogger = pinoHttp({
customSuccessMessage(req, res) { customSuccessMessage(req, res) {
return `${req.method} ${req.url} ${res.statusCode}`; return `${req.method} ${req.url} ${res.statusCode}`;
}, },
customErrorMessage(req, res) { customErrorMessage(req, res, err) {
return `${req.method} ${req.url} ${res.statusCode}`; const errMsg = err?.message || (res as any).err?.message || "unknown error";
return `${req.method} ${req.url} ${res.statusCode}${errMsg}`;
}, },
customProps() { customProps(req, res) {
if (res.statusCode >= 400) {
const props: Record<string, unknown> = {};
const { body, params, query } = req as any;
if (body && typeof body === "object" && Object.keys(body).length > 0) {
props.reqBody = body;
}
if (params && typeof params === "object" && Object.keys(params).length > 0) {
props.reqParams = params;
}
if (query && typeof query === "object" && Object.keys(query).length > 0) {
props.reqQuery = query;
}
if ((req as any).route?.path) {
props.routePath = (req as any).route.path;
}
return props;
}
return {}; return {};
}, },
}); });