@metamask/logger
Version:
A lightweight logging package using @metamask/streams
1 lines • 7.17 kB
Source Map (JSON)
{"version":3,"file":"logger.mjs","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * A Logger is a logging facility that supports multiple transports and tags.\n * The transports are the actual logging functions, and the tags are used to\n * identify the source of the log message independent of its location in the\n * code.\n *\n * @example\n * ```ts\n * const logger = new Logger('my-logger');\n * logger.info('Hello, world!');\n * >>> [my-logger] Hello, world!\n * ```\n *\n * Sub-loggers can be created by calling the `subLogger` method. They inherit\n * the tags and transports of their parent logger, and can add additional tags\n * to their own messages.\n *\n *\n * @example\n * ```ts\n * const subLogger = logger.subLogger('sub');\n * subLogger.info('Hello, world!');\n * >>> [my-logger, sub] Hello, world!\n * ```\n *\n * The transports can be configured to ignore certain log levels, or to write\n * different tags to different destinations, and so on. The default transports\n * write to the console, but other transports can be added by passing a custom\n * transport function to the constructor. The transports must be synchronous,\n * but they can initiate asynchronous operations if needed.\n *\n * @example\n * ```ts\n * const logger = new Logger({\n * tags: ['my-logger'],\n * transports: [\n * (entry) => {\n * if (entry.tags.includes('vat')) {\n * fs.writeFile('vat.log', `${entry.message}\\n`, { flag: 'a' }).catch(\n * (error) => {\n * console.error('Error writing to vat.log:', error);\n * },\n * );\n * }\n * },\n * ],\n * });\n * ```\n */\n\nimport type { DuplexStream } from '@metamask/streams';\n\nimport { parseOptions, mergeOptions } from './options.ts';\nimport { lunser } from './stream.ts';\nimport type { LogMessage } from './stream.ts';\nimport type {\n LogLevel,\n LogEntry,\n LoggerOptions,\n LogMethod,\n LogArgs,\n} from './types.ts';\n\n// We make use of harden() if it exists, but we don't want to fail if it doesn't.\nconst harden = globalThis.harden ?? ((value: unknown) => value);\n\n/**\n * The logger class.\n */\nexport class Logger {\n readonly #options: LoggerOptions;\n\n log: LogMethod;\n\n debug: LogMethod;\n\n info: LogMethod;\n\n warn: LogMethod;\n\n error: LogMethod;\n\n /**\n * The constructor for the logger. Sub-loggers can be created by calling the\n * `subLogger` method. Sub-loggers inherit the transports and tags of their\n * parent logger.\n *\n * @param options - The options for the logger, or a string to use as the\n * logger's tag.\n * @param options.transports - The transports, which deliver the log messages\n * to the appropriate destination.\n * @param options.level - The log level for the logger, used as a default\n * argument for the transports.\n * @param options.tags - The tags for the logger, which are accumulated by\n * sub-loggers and passed to the transports.\n */\n constructor(options: LoggerOptions | string | undefined = undefined) {\n this.#options = parseOptions(options);\n\n // Create aliases for the log methods, allowing them to be used in a\n // manner similar to the console object.\n const bind = (level: LogLevel): LogMethod =>\n harden(\n this.#dispatch.bind(this, {\n ...this.#options,\n level,\n }),\n ) as LogMethod;\n this.log = bind('log');\n this.debug = bind('debug');\n this.info = bind('info');\n this.warn = bind('warn');\n this.error = bind('error');\n }\n\n /**\n * Creates a sub-logger with the given options.\n *\n * @param options - The options for the sub-logger, or a string to use as the\n * sub-logger's tag.\n * @returns The sub-logger.\n */\n subLogger(options: LoggerOptions | string = {}): Logger {\n return new Logger(\n mergeOptions(\n this.#options,\n typeof options === 'string' ? { tags: [options] } : options,\n ),\n );\n }\n\n /**\n * Injects a stream of log messages into the logger.\n *\n * @param stream - The stream of log messages to inject.\n * @param onError - The function to call if an error occurs while draining\n * the stream. If not provided, the error will be lost to the void.\n */\n injectStream(\n stream: DuplexStream<LogMessage>,\n onError?: (error: unknown) => void,\n ): void {\n stream\n .drain(async ({ params }) => {\n const [, args]: ['logger', string] = params;\n const { level, tags, message, data } = lunser(args);\n const logArgs: LogArgs =\n message === undefined ? [] : [message, ...(data ?? [])];\n this.#dispatch({ level, tags }, ...logArgs);\n })\n .catch((problem) => onError?.(problem));\n }\n\n #dispatch(options: LoggerOptions, ...args: LogArgs): void {\n const { transports, level, tags } = mergeOptions(this.#options, options);\n const [message, ...data] = args;\n const entry: LogEntry = harden({ level, tags, message, data });\n transports.forEach((transport) => transport(entry));\n }\n}\nharden(Logger);\n"]}