const morgan = require('morgan'); const requestIp = require('request-ip'); const config = require('./config'); const logger = require('./logger'); // Custom tokens morgan.token('clientIp', (req) => { const ip = requestIp.getClientIp(req); // Anonymize IP in production for GDPR compliance return config.env === 'production' && ip ? ip.replace(/\.\d+$/, '.XXX') : ip || 'unknown'; }); morgan.token('error', (req, res) => res.locals.error?.message || ''); // Formats const getFormat = (isError = false) => { const base = `${config.env === 'development' ? ':date[iso] ' : ''}:clientIp - :method :url :status`; return isError ? `${base} - :response-time ms - error: :error - referrer: :referrer` : `${base} - :response-time ms`; }; // Success handler (2xx, 3xx responses) const successHandler = morgan(getFormat(), { skip: (req, res) => res.statusCode >= 400, stream: { write: (msg) => logger.info(msg.trim()) } }); // Error handler (4xx, 5xx responses) const errorHandler = morgan(getFormat(true), { skip: (req, res) => res.statusCode < 400, stream: { write: (msg) => { const status = msg.match(/:status (\d+)/)?.[1] || 500; status >= 500 ? logger.error(msg.trim()) : logger.warn(msg.trim()); } } }); module.exports = { successHandler, errorHandler };