wip: add some error logging to the server

This commit is contained in:
Steve Korshakov 2025-08-26 20:47:38 -07:00
parent 8158668190
commit 25724eac23
2 changed files with 150 additions and 0 deletions

View File

@ -135,6 +135,102 @@ export async function startApi(): Promise<{ app: FastifyInstance; io: Server }>
httpRequestDurationHistogram.observe({ method, route, status }, duration);
});
// Global error handler
app.setErrorHandler(async (error, request, reply) => {
const method = request.method;
const url = request.url;
const userAgent = request.headers['user-agent'] || 'unknown';
const ip = request.ip || 'unknown';
// Log the error with comprehensive context
log({
module: 'fastify-error',
level: 'error',
method,
url,
userAgent,
ip,
statusCode: error.statusCode || 500,
errorCode: error.code,
stack: error.stack
}, `Unhandled error: ${error.message}`);
// Return appropriate error response
const statusCode = error.statusCode || 500;
if (statusCode >= 500) {
// Internal server errors - don't expose details
return reply.code(statusCode).send({
error: 'Internal Server Error',
message: 'An unexpected error occurred',
statusCode
});
} else {
// Client errors - can expose more details
return reply.code(statusCode).send({
error: error.name || 'Error',
message: error.message || 'An error occurred',
statusCode
});
}
});
// Error hook for additional logging
app.addHook('onError', async (request, reply, error) => {
const method = request.method;
const url = request.url;
const duration = (Date.now() - (request.startTime || Date.now())) / 1000;
log({
module: 'fastify-hook-error',
level: 'error',
method,
url,
duration,
statusCode: reply.statusCode || error.statusCode || 500,
errorName: error.name,
errorCode: error.code
}, `Request error: ${error.message}`);
});
// Handle uncaught exceptions in routes
app.addHook('preHandler', async (request, reply) => {
// Store original reply.send to catch errors in response serialization
const originalSend = reply.send.bind(reply);
reply.send = function(payload: any) {
try {
return originalSend(payload);
} catch (error: any) {
log({
module: 'fastify-serialization-error',
level: 'error',
method: request.method,
url: request.url,
stack: error.stack
}, `Response serialization error: ${error.message}`);
throw error;
}
};
});
// Not found handler
app.setNotFoundHandler(async (request, reply) => {
log({
module: 'fastify-not-found',
level: 'warn',
method: request.method,
url: request.url,
userAgent: request.headers['user-agent'] || 'unknown',
ip: request.ip || 'unknown'
}, `404 Not Found: ${request.method} ${request.url}`);
return reply.code(404).send({
error: 'Not Found',
message: `Route ${request.method} ${request.url} not found`,
statusCode: 404
});
});
// Authentication decorator
app.decorate('authenticate', async function (request: any, reply: any) {
try {

View File

@ -46,6 +46,60 @@ async function main() {
log('Shutting down...');
}
// Process-level error handling
process.on('uncaughtException', (error) => {
log({
module: 'process-error',
level: 'error',
stack: error.stack,
name: error.name
}, `Uncaught Exception: ${error.message}`);
console.error('Uncaught Exception:', error);
process.exit(1);
});
process.on('unhandledRejection', (reason, promise) => {
const errorMsg = reason instanceof Error ? reason.message : String(reason);
const errorStack = reason instanceof Error ? reason.stack : undefined;
log({
module: 'process-error',
level: 'error',
stack: errorStack,
reason: String(reason)
}, `Unhandled Rejection: ${errorMsg}`);
console.error('Unhandled Rejection at:', promise, 'reason:', reason);
process.exit(1);
});
process.on('warning', (warning) => {
log({
module: 'process-warning',
level: 'warn',
name: warning.name,
stack: warning.stack
}, `Process Warning: ${warning.message}`);
});
// Log when the process is about to exit
process.on('exit', (code) => {
if (code !== 0) {
log({
module: 'process-exit',
level: 'error',
exitCode: code
}, `Process exiting with code: ${code}`);
} else {
log({
module: 'process-exit',
level: 'info',
exitCode: code
}, 'Process exiting normally');
}
});
main().catch((e) => {
console.error(e);
process.exit(1);