github-docs-arabic-enhanced / src /observability /logger /middleware /get-automatic-request-logger.ts
| import chalk from 'chalk' | |
| import { getLoggerContext } from '@/observability/logger/lib/logger-context' | |
| import type { NextFunction, Request, Response } from 'express' | |
| import { getLogLevelNumber, useProductionLogging } from '@/observability/logger/lib/log-levels' | |
| import { toLogfmt } from '@/observability/logger/lib/to-logfmt' | |
| /** | |
| * Check if automatic development logging is enabled. | |
| * We don't turn on automatic logging for tests & GitHub Actions by default, | |
| * but you can override this using the ENABLE_DEV_LOGGING environment variable. | |
| */ | |
| function shouldEnableAutomaticDevLogging(): boolean { | |
| const isTest = process.env.NODE_ENV === 'test' || process.env.GITHUB_ACTIONS === 'true' | |
| return Boolean( | |
| process.env.ENABLE_DEV_LOGGING ? JSON.parse(process.env.ENABLE_DEV_LOGGING) : !isTest, | |
| ) | |
| } | |
| /** | |
| * Returns a custom middleware that automatically logs request details. | |
| * | |
| * e.g. `GET /path/to/resource 200 5.000 ms - 1234` | |
| * | |
| * In production, we include the logger context and print in logfmt format | |
| * In development, we print colored strings for better readability | |
| * In test, the request details are not logged. | |
| */ | |
| export function getAutomaticRequestLogger() { | |
| return (req: Request, res: Response, next: NextFunction) => { | |
| const startTime = Date.now() | |
| // Store original end method to capture response completion | |
| const originalEnd = res.end | |
| // Override res.end to log when response completes | |
| res.end = function (chunk?: any, encoding?: any) { | |
| const responseTime = Date.now() - startTime | |
| const status = res.statusCode || 200 | |
| const contentLength = res.getHeader('content-length') || '-' | |
| const method = req.method | |
| const url = req.originalUrl || req.url | |
| if (useProductionLogging()) { | |
| // Production: log in logfmt format with full context | |
| const loggerContext = getLoggerContext() | |
| console.log( | |
| toLogfmt({ | |
| ...loggerContext, | |
| status, | |
| responseTime: `${responseTime} ms`, | |
| contentLength: String(contentLength), | |
| method, | |
| url, | |
| }), | |
| ) | |
| } else if (shouldEnableAutomaticDevLogging()) { | |
| // Development: log colored strings for readability | |
| const logLevelNum = getLogLevelNumber() | |
| // Don't log `/_next/` requests unless LOG_LEVEL is `debug` or higher | |
| if (url?.startsWith('/_next/') && logLevelNum < 3) { | |
| return originalEnd.call(this, chunk, encoding) | |
| } | |
| // Choose color based on status code | |
| const color = | |
| status >= 500 ? 'red' : status >= 400 ? 'yellow' : status >= 300 ? 'cyan' : 'green' | |
| const logLine = [ | |
| '[AUTO]', | |
| chalk.reset(method), | |
| chalk.reset(url), | |
| chalk[color](status), | |
| chalk.reset(`${responseTime} ms`), | |
| chalk.reset('-'), | |
| chalk.reset(String(contentLength)), | |
| ].join(' ') | |
| console.log(logLine) | |
| } | |
| // Call the original end method to complete the response | |
| return originalEnd.call(this, chunk, encoding) | |
| } | |
| next() | |
| } | |
| } | |