UNPKG

@neodx/log

Version:

A lightweight universal logging framework

146 lines (143 loc) 4.55 kB
import { colors } from '@neodx/colors'; import { i as identity } from '../_internal/read-arguments-BklHPmep.mjs'; import { H as HTTP_LOG_START_TIME_SYMBOL, c as createLogger, a as createRequestIdGenerator, f as formatIncomingMessage, b as formatResponseTime, d as formatOutgoingMessageStatus } from '../_internal/index-BK5YuVsW.mjs'; function createHttpLogger({ simple = process.env.NODE_ENV === 'development', colors: colors$1 = colors, logger: rootLogger = createLogger(), getRequestId = createRequestIdGenerator(), getMeta, getErrorMeta, getErrorMessage = simple ? simpleErrorMessage : defaultErrorMessage, getRequestMeta, getRequestMessage = defaultRequestMessage, getResponseMeta, getResponseMessage = defaultResponseMessage, shouldLog = true, shouldLogError = true, shouldLogRequest = false, shouldLogResponse = true } = {}) { function handleEnd(ctx) { const { error, logger, res, responseTime } = ctx; const err = error || res.err || (res.statusCode >= 500 && new Error('failed with status code ' + res.statusCode)); if (err) { if (!condition(shouldLogError, ctx)) return; const errorMeta = getErrorMeta?.(ctx) ?? { err, res, responseTime }; if (simple) { logger.error( { err }, getErrorMessage(ctx) ); logger.debug(errorMeta, 'Error details:'); return; } logger.error(errorMeta, getErrorMessage(ctx)); return; } if (!condition(shouldLogResponse, ctx)) return; const responseMeta = getResponseMeta?.(ctx) ?? { res, responseTime }; if (simple) { logger.done(getResponseMessage(ctx)); logger.debug(responseMeta, 'Response details:'); return; } logger.done(responseMeta, getResponseMessage(ctx)); } return function httpLogger(req, res, next) { if (!condition(shouldLog, req, res)) return next?.(); // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition req.id ??= getRequestId(req, res); const startTime = Date.now(); const logger = rootLogger.fork({ meta: { ...rootLogger.meta, ...getMeta?.(req, res), ...(!simple && { requestId: req.id, req }) } }); const baseContext = { req, res, logger, colors: colors$1, responseTime: 0 }; // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition req.log ??= logger; res[HTTP_LOG_START_TIME_SYMBOL] = startTime; const handleResponse = error => { res.removeListener('finish', handleResponse); res.removeListener('close', handleResponse); res.removeListener('error', handleResponse); return handleEnd({ ...baseContext, error, responseTime: Date.now() - startTime }); }; res.on('error', handleResponse); res.on('close', handleResponse); res.on('finish', handleResponse); if (condition(shouldLogRequest, baseContext)) { if (!simple) { logger.info(getRequestMeta?.(baseContext) ?? {}, getRequestMessage(baseContext)); } else { logger.info(getRequestMessage(baseContext)); if (getRequestMeta) { logger.debug(getRequestMeta(baseContext), 'Request details:'); } } } next?.(); }; } const createMessageFormatter = (fn, { ignoreWritableEnded = false, delimiter = _ => ' ' } = {}) => ctx => { const requestMessage = formatIncomingMessage(ctx.req, ctx.colors, delimiter(ctx)); return ignoreWritableEnded || ctx.res.writableEnded ? fn(requestMessage, ctx) : `(aborted) ${requestMessage}`; }; const defaultRequestMessage = createMessageFormatter(identity, { ignoreWritableEnded: true }); const defaultResponseMessage = createMessageFormatter( (msg, ctx) => `${ctx.colors.greenBright(formatResponseTime(ctx.responseTime))} ${msg}` ); const defaultErrorMessage = createMessageFormatter( (msg, ctx) => `${ctx.colors.redBright(formatResponseTime(ctx.responseTime))} ${msg}` ); const simpleErrorMessage = createMessageFormatter( (msg, ctx) => `${ctx.colors.redBright(formatResponseTime(ctx.responseTime))} ${msg}`, { delimiter: ({ colors, res }) => colors.italic(` (${formatOutgoingMessageStatus(res)}) `) } ); const condition = (condition, ...args) => typeof condition === 'function' ? condition(...args) : condition; export { createHttpLogger }; //# sourceMappingURL=index.mjs.map