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:
@@ -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,
|
||||||
|
|||||||
@@ -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 {};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user