diff --git a/backend/middleware/logger.js b/backend/middleware/logger.js new file mode 100644 index 0000000..0d1d64d --- /dev/null +++ b/backend/middleware/logger.js @@ -0,0 +1,51 @@ +const { format, createLogger, transports } = require('winston'); + +const logger = createLogger({ + format: format.combine( + format.timestamp(), + format.json() + ), + transports: [ + new transports.Console() + ] +}); + +// Middleware to generate a unique request ID +const requestId = (req, res, next) => { + req.id = `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; + next(); +}; + +// Middleware to log requests +const requestLogger = (req, res, next) => { + logger.info({ + timestamp: new Date().toISOString(), + method: req.method, + url: req.url, + requestId: req.id + }); + next(); +}; + +// Middleware to log errors +const errorLogger = (err, req, res, next) => { + const isSecurityEvent = err.message.includes('Authentication') || + err.message.includes('Authorization') || + err.message.includes('Security'); + const level = isSecurityEvent ? 'security' : 'error'; + + logger[level]({ + timestamp: new Date().toISOString(), + error: err.message, + stack: err.stack, + requestId: req.id, + route: req.route ? req.route.path : req.path + }); + next(err); +}; + +module.exports = { + requestId, + requestLogger, + errorLogger +}; \ No newline at end of file diff --git a/backend/src/middleware/logger.js b/backend/src/middleware/logger.js index 8b26de4..e852db5 100644 --- a/backend/src/middleware/logger.js +++ b/backend/src/middleware/logger.js @@ -5,7 +5,8 @@ function logger(req, res, next) { method: req.method, url: req.url, requestId: req.requestId, - level: 'info' + level: 'info', + route: req.route ? req.route.path : 'unknown' })); res.on('finish', () => { const securityEvent = [401, 403].includes(res.statusCode); @@ -16,7 +17,8 @@ function logger(req, res, next) { status: res.statusCode, requestId: req.requestId, level: res.statusCode >= 400 ? 'error' : 'info', - securityEvent: securityEvent + securityEvent: securityEvent, + route: req.route ? req.route.path : 'unknown' })); }); next(); diff --git a/docs/adr/structured-logging.md b/docs/adr/structured-logging.md new file mode 100644 index 0000000..e26e19c --- /dev/null +++ b/docs/adr/structured-logging.md @@ -0,0 +1,22 @@ +# Structured Logging + +## Status + +Accepted + +## Context + +For operational debugging, structured logs are needed for API errors and security events. This includes timestamps, log levels, request IDs, and routes. + +## Decision + +We implement a centralized logging middleware that: +1. Logs all requests with timestamp, method, URL, request ID, and route +2. Logs error responses with correlation via request ID +3. Marks security-relevant events (401, 403) separately + +## Consequences + +- Logs are structured and filterable +- Security events can be easily identified +- Debugging is improved through correlation of requests and errors \ No newline at end of file