@rollercoaster-dev/rd-logger
Version:
A neurodivergent-friendly logger for Rollercoaster.dev projects
105 lines • 4.06 kB
JavaScript
import { Logger } from "../core/logger.service.js";
import { runWithRequestContext, getRequestStore, } from "../core/request-context.js";
/**
* Hono middleware for neuro-friendly logging and request context management.
*
* @param options Configuration options for the logger middleware.
* @returns Hono MiddlewareHandler.
*/
export const honoLogger = (options = {}) => {
const logger = options.loggerInstance || new Logger(options.loggerOptions);
return async (c, next) => {
const existingRequestId = c.req.header("x-request-id");
await runWithRequestContext(async () => {
const store = getRequestStore();
const requestId = store.requestId;
const startTime = store.requestStartTime;
// Set requestId in Hono context for access in handlers
c.set("requestId", requestId);
// Set response header
c.res.headers.set("x-request-id", requestId);
// Check if logging should be skipped
if (options.skip?.(c)) {
await next();
return;
}
// Log incoming request
const method = c.req.method;
const path = new URL(c.req.url).pathname;
const requestMsg = options.requestMessage
? options.requestMessage(c, store)
: `▶ Incoming request`;
logger.info(requestMsg, {
method,
path,
requestId,
});
// Proceed with the request handling
try {
await next();
}
catch (error) {
// Log uncaught errors that might bypass Hono's default error handler
// Note: It's generally better to rely on Hono's built-in .onError
if (error instanceof Error) {
logger.error(`Middleware error: ${error.message}`, {
error: error, // Pass the raw error object
requestId,
});
}
// Re-throw the error to let Hono handle the response
throw error;
}
// Log outgoing response
const duration = Date.now() - startTime;
const status = c.res.status;
const responseMsg = options.responseMessage
? options.responseMessage(c, store, duration, status)
: `◀ Request completed`;
const logLevel = status >= 500 ? "error" : status >= 400 ? "warn" : "info";
logger[logLevel](responseMsg, {
method,
path,
status,
duration: `${duration}ms`,
requestId,
});
}, existingRequestId);
};
};
/**
* Hono error handler that logs errors using the logger and request context.
*
* Usage:
* ```typescript
* import { Hono } from 'hono';
* import { honoErrorHandler } from './path/to/honoErrorHandler/index.js';
* import { Logger } from './path/to/logger/index.js';
*
* const app = new Hono();
* const logger = new Logger();
*
* app.onError(honoErrorHandler(logger));
* // ... other middleware and routes
* ```
*
* @param loggerInstance An instance of the Logger.
* @returns Hono ErrorHandler.
*/
export const honoErrorHandler = (loggerInstance) => {
return (err, c) => {
const store = getRequestStore(); // Get context established by honoLogger middleware
const requestId = store?.requestId || c.req.header("x-request-id") || "unknown";
loggerInstance.error(`Unhandled Hono error: ${err.message}`, {
error: err,
requestId,
method: c.req.method,
path: new URL(c.req.url).pathname,
});
// Default Hono error response
console.error(err); // Log the raw error for visibility
const message = "Internal Server Error";
return c.json({ ok: false, message }, 500);
};
};
//# sourceMappingURL=hono.js.map