UNPKG

@rollercoaster-dev/rd-logger

Version:

A neurodivergent-friendly logger for Rollercoaster.dev projects

107 lines 4.36 kB
import onFinished from "on-finished"; import { Logger } from "../core/logger.service.js"; import { runWithRequestContext, getRequestStore, } from "../core/request-context.js"; /** * Express middleware for neuro-friendly logging and request context management. * * @param options Configuration options for the logger middleware. * @returns Express RequestHandler. */ export const expressLogger = (options = {}) => { const logger = options.loggerInstance || new Logger(options.loggerOptions); return (req, res, next) => { const existingRequestId = req.header("x-request-id"); // Wrap the request handling in the async context runWithRequestContext(() => { const store = getRequestStore(); const requestId = store.requestId; const startTime = store.requestStartTime; // Make requestId easily accessible on the request object req.id = requestId; // Set response header res.setHeader("x-request-id", requestId); // Check if logging should be skipped if (options.skip?.(req, res)) { next(); return; } // Log incoming request const method = req.method; const path = req.originalUrl || req.url; const requestMsg = options.requestMessage ? options.requestMessage(req, store) : `▶ Incoming request`; logger.info(requestMsg, { method, path, requestId, }); // Log response when it finishes onFinished(res, (err, finishedRes) => { const duration = Date.now() - startTime; const status = finishedRes.statusCode; const responseMsg = options.responseMessage ? options.responseMessage(req, finishedRes, store, duration, status) : `◀ Request completed`; const logLevel = status >= 500 ? "error" : status >= 400 ? "warn" : "info"; const logContext = { method, path, status, duration: `${duration}ms`, requestId, }; // Include error in log if onFinished reported one if (err) { logContext.error = err; logger.error(`Error during response finish: ${err.message}`, logContext); } else { logger[logLevel](responseMsg, logContext); } }); // Continue to the next middleware next(); }, existingRequestId); }; }; /** * Express error handling middleware that logs errors using the logger and request context. * * Place this AFTER your routes and other middleware, but BEFORE the default Express error handler. * * Usage: * ```typescript * import express from 'express'; * import { expressLogger, expressErrorHandler } from './path/to/expressAdapter/index.js'; * import { Logger } from './path/to/logger/index.js'; * * const app = express(); * const logger = new Logger(); * * app.use(expressLogger({ loggerInstance: logger })); * // ... routes ... * app.use(expressErrorHandler(logger)); * ``` * * @param loggerInstance An instance of the Logger. * @returns Express ErrorRequestHandler. */ export const expressErrorHandler = (loggerInstance) => { return (err, // Express errors can be of any type req, res, next) => { const store = getRequestStore(); // Get context established by expressLogger middleware // Fallback to req.id or header if context is somehow lost const requestId = store?.requestId || req.id || req.header("x-request-id") || "unknown"; const errorMessage = err instanceof Error ? err.message : "Unknown error occurred"; loggerInstance.error(`Unhandled Express error: ${errorMessage}`, { error: err, // Pass the raw error object requestId, method: req.method, path: req.originalUrl || req.url, }); // Ensure the error is passed to the next error handler (e.g., Express default) next(err); }; }; //# sourceMappingURL=express.js.map