UNPKG

logixlysia

Version:

🦊 Logixlysia is a logger for Elysia

169 lines (168 loc) • 6.42 kB
import { Elysia } from "elysia"; import { Logger as PinoLogger, LoggerOptions as PinoLoggerOptions } from "pino"; type Pino = PinoLogger<never, boolean>; type RequestInfo = Request; type LogLevel = "DEBUG" | "INFO" | "WARNING" | "ERROR"; interface StoreData { beforeTime: bigint; } interface LogixlysiaStore { beforeTime?: bigint; logger: Logger; pino: Pino; } interface Transport { log: (level: LogLevel, message: string, meta?: Record<string, unknown>) => void | Promise<void>; } interface LogRotationConfig { compress?: boolean; compression?: "gzip"; /** * Rotate at a fixed interval, e.g. '1d', '12h'. */ interval?: string; /** * Keep at most N files or keep files for a duration like '7d'. */ maxFiles?: number | string; /** * Max log file size before rotation, e.g. '10m', '5k', or a byte count. */ maxSize?: string | number; } interface LogFilter { /** * Array of log levels to allow. If specified, only logs with these levels will be processed. * If not specified, all log levels will be allowed. */ level?: LogLevel[]; } /** * Configuration for pino-pretty transport output. * * - `true`: Enable pretty printing with default options * - `false` or `undefined`: Disable pretty printing * - Object: Enable with custom pino-pretty options (colorize, translateTime, messageKey, errorKey, etc.) * * @see https://github.com/pinojs/pino-pretty#options */ type PrettyPrintConfig = boolean | Record<string, unknown>; type LogPreset = "dev" | "prod" | "json"; interface Options { config?: { showStartupMessage?: boolean; startupMessageFormat?: "simple" | "banner"; useColors?: boolean; ip?: boolean; timestamp?: { translateTime?: string; }; customLogFormat?: string; /** Service name shown in `{service}` token (e.g. evlog-style `[my-app]`). */ service?: string; /** Duration (ms) below this uses green; default 500. */ slowThreshold?: number; /** Duration (ms) at or above this uses red + `{speed}` badge; default 1000. */ verySlowThreshold?: number; /** Render `data.context` as tree lines under the main log line; default true. */ showContextTree?: boolean; /** How many object nesting levels to expand in the context tree; default 1. */ contextDepth?: number; /** Include query parameters in the logged URL path; default false. */ logQueryParams?: boolean; /** Skip automatic WebSocket lifecycle logs from `wrapWs`; default false. */ disableWebSocketLogging?: boolean; logFilter?: LogFilter; transports?: Transport[]; useTransportsOnly?: boolean; disableInternalLogger?: boolean; disableFileLogging?: boolean; logFilePath?: string; logRotation?: LogRotationConfig; /** * Automatically redact sensitive information (PII) from logs. * Masks emails, IP addresses, Luhn-valid payment card numbers, and JWTs in strings and deeply nested objects. */ autoRedact?: boolean; pino?: (PinoLoggerOptions & { prettyPrint?: PrettyPrintConfig; }) | undefined; }; /** * Opinionated defaults for common environments. * Explicit `config` fields override preset values. */ preset?: LogPreset; } interface Logger { debug: (request: RequestInfo, message: string, context?: Record<string, unknown>) => void; error: (request: RequestInfo, message: string, context?: Record<string, unknown>) => void; getContext: (key: RequestInfo | object) => Readonly<Record<string, unknown>>; handleHttpError: (request: RequestInfo, error: unknown, store: StoreData) => void; info: (request: RequestInfo, message: string, context?: Record<string, unknown>) => void; log: (level: LogLevel, request: RequestInfo, data: Record<string, unknown>, store: StoreData) => void; mergeContext: (key: RequestInfo | object, partial: Record<string, unknown>) => void; pino: Pino; warn: (request: RequestInfo, message: string, context?: Record<string, unknown>) => void; } interface LogixlysiaContext { request: Request; store: LogixlysiaStore; } /** HTTP `Request` or WebSocket instance for accumulated context. */ type ContextKey = Request | object; interface RequestContextStore { clearContext: (key: ContextKey) => void; getContext: (key: ContextKey) => Readonly<Record<string, unknown>>; mergeContext: (key: ContextKey, partial: Record<string, unknown>) => void; } interface WebSocketLike { readonly data?: { store?: { logger?: Logger; }; }; readonly id?: string; } interface WsHandlerHooks< TMessage = unknown, TWs extends WebSocketLike = WebSocketLike > { close?: (ws: TWs) => void; message?: (ws: TWs, message: TMessage) => void; open?: (ws: TWs) => void; } declare const createWsHandlerWrapper: (options: Options, logger: Logger, contextStore: RequestContextStore) => < TMessage, TWs extends WebSocketLike, const THooks extends WsHandlerHooks<TMessage, TWs> >(path: string, hooks: THooks) => THooks; /** Applies preset defaults; explicit `config` keys override preset values. */ declare const resolveOptions: (options?: Options) => Options; import pino from "pino"; declare const createLogger: (options?: Options, pinoFactory?: typeof pino, externalContextStore?: RequestContextStore) => Logger; /** Plugin entry: shares one request-context store across the Elysia lifecycle. */ declare const createPluginLogger: (options: Options, contextStore: RequestContextStore) => Logger; /** * Empty singleton slots must not use `Record<string, never>`: intersecting that with Elysia's `Context` * makes every key (including `store`) become `never` because each key is merged with `never`. */ interface EmptyElysiaSlot { readonly __logixlysiaEmpty?: never; } /** * Explicit singleton without Elysia's `SingletonBase` `Record<string, unknown>` on decorator/derive/resolve so * merged `Context` and WebSocket `ws.data` keep precise keys after `.use(logixlysia())`. */ interface LogixlysiaSingleton { decorator: EmptyElysiaSlot; derive: EmptyElysiaSlot; resolve: EmptyElysiaSlot; store: LogixlysiaStore; } type Logixlysia = Elysia<"", LogixlysiaSingleton>; type LogixlysiaPlugin = Logixlysia & { wrapWs: ReturnType<typeof createWsHandlerWrapper>; }; declare const logixlysia: (rawOptions?: Options) => LogixlysiaPlugin; export { resolveOptions, logixlysia, logixlysia as default, createWsHandlerWrapper, createPluginLogger, createLogger, WsHandlerHooks, Transport, StoreData, Pino, Options, LogixlysiaStore, LogixlysiaSingleton, LogixlysiaPlugin, LogixlysiaContext, Logixlysia, Logger, LogPreset, LogLevel, EmptyElysiaSlot };