Chapter 12: Error Handling and Logging
Chapter 12 of 15
Chapter 12: Error Handling and Logging
12.1 Error Handling Patterns
Proper error handling ensures applications fail gracefully and provide useful information for debugging.
// Custom error class
class AppError extends Error {
constructor(message, statusCode) {
super(message);
this.statusCode = statusCode;
this.isOperational = true;
Error.captureStackTrace(this, this.constructor);
}
}
// Async error wrapper
const asyncHandler = (fn) => (req, res, next) => {
Promise.resolve(fn(req, res, next)).catch(next);
};
// Global error handler
app.use((err, req, res, next) => {
err.statusCode = err.statusCode || 500;
err.status = err.status || 'error';
if (process.env.NODE_ENV === 'development') {
res.status(err.statusCode).json({
status: err.status,
error: err,
message: err.message,
stack: err.stack
});
} else {
res.status(err.statusCode).json({
status: err.status,
message: err.message
});
}
});
12.2 Logging Strategies
// Winston logger
const winston = require('winston');
const logger = winston.createLogger({
level: 'info',
format: winston.format.json(),
transports: [
new winston.transports.File({ filename: 'error.log', level: 'error' }),
new winston.transports.File({ filename: 'combined.log' })
]
});
if (process.env.NODE_ENV !== 'production') {
logger.add(new winston.transports.Console({
format: winston.format.simple()
}));
}
// Usage
logger.info('User logged in', { userId: 123 });
logger.error('Database error', { error: err });
12.3 Structured Logging
// Pino logger (faster)
const pino = require('pino');
const logger = pino({
level: 'info',
transport: {
target: 'pino-pretty'
}
});
logger.info({ userId: 123, action: 'login' }, 'User logged in');
logger.error({ err }, 'Error occurred');