requestLogger.js 1.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657
  1. const { logInfo, logError } = require('../utils/logger')
  2. const SENSITIVE_KEYS = ['password', 'token', 'otp', 'authorization']
  3. const sanitize = (obj) => {
  4. if (!obj || typeof obj !== 'object') return obj
  5. const clone = { ...obj }
  6. Object.keys(clone).forEach((key) => {
  7. if (SENSITIVE_KEYS.includes(key.toLowerCase())) clone[key] = '[REDACTED]'
  8. })
  9. return clone
  10. }
  11. /**
  12. * Logs every request (method, url, body, query, params) and its response
  13. * (status code, body) to application.log. Errors (4xx/5xx or thrown) are
  14. * logged via logError with full detail.
  15. */
  16. const middleware = (req, res, next) => {
  17. const start = Date.now()
  18. const originalJson = res.json.bind(res)
  19. res.json = (body) => {
  20. const durationMs = Date.now() - start
  21. const meta = {
  22. method: req.method,
  23. url: req.originalUrl,
  24. status: res.statusCode,
  25. durationMs,
  26. requestBody: sanitize(req.body),
  27. requestQuery: sanitize(req.query),
  28. responseBody: body,
  29. }
  30. if (res.statusCode >= 400) {
  31. logError('HTTP', `${req.method} ${req.originalUrl} failed`, meta)
  32. } else {
  33. logInfo('HTTP', `${req.method} ${req.originalUrl}`, meta)
  34. }
  35. return originalJson(body)
  36. }
  37. next()
  38. }
  39. middleware.logUncaughtError = (req, err) => {
  40. logError('HTTP_UNCAUGHT', `${req.method} ${req.originalUrl} threw`, {
  41. method: req.method,
  42. url: req.originalUrl,
  43. requestBody: sanitize(req.body),
  44. error: err.message,
  45. stack: err.stack,
  46. })
  47. }
  48. module.exports = middleware