UNPKG

@metamask/logger

Version:

A lightweight logging package using @metamask/streams

135 lines 5.97 kB
/** * A Logger is a logging facility that supports multiple transports and tags. * The transports are the actual logging functions, and the tags are used to * identify the source of the log message independent of its location in the * code. * * @example * ```ts * const logger = new Logger('my-logger'); * logger.info('Hello, world!'); * >>> [my-logger] Hello, world! * ``` * * Sub-loggers can be created by calling the `subLogger` method. They inherit * the tags and transports of their parent logger, and can add additional tags * to their own messages. * * * @example * ```ts * const subLogger = logger.subLogger('sub'); * subLogger.info('Hello, world!'); * >>> [my-logger, sub] Hello, world! * ``` * * The transports can be configured to ignore certain log levels, or to write * different tags to different destinations, and so on. The default transports * write to the console, but other transports can be added by passing a custom * transport function to the constructor. The transports must be synchronous, * but they can initiate asynchronous operations if needed. * * @example * ```ts * const logger = new Logger({ * tags: ['my-logger'], * transports: [ * (entry) => { * if (entry.tags.includes('vat')) { * fs.writeFile('vat.log', `${entry.message}\n`, { flag: 'a' }).catch( * (error) => { * console.error('Error writing to vat.log:', error); * }, * ); * } * }, * ], * }); * ``` */ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { if (kind === "m") throw new TypeError("Private method is not writable"); if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; }; var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); }; var _Logger_instances, _Logger_options, _Logger_dispatch; import { parseOptions, mergeOptions } from "./options.mjs"; import { lunser } from "./stream.mjs"; // We make use of harden() if it exists, but we don't want to fail if it doesn't. const harden = globalThis.harden ?? ((value) => value); /** * The logger class. */ export class Logger { /** * The constructor for the logger. Sub-loggers can be created by calling the * `subLogger` method. Sub-loggers inherit the transports and tags of their * parent logger. * * @param options - The options for the logger, or a string to use as the * logger's tag. * @param options.transports - The transports, which deliver the log messages * to the appropriate destination. * @param options.level - The log level for the logger, used as a default * argument for the transports. * @param options.tags - The tags for the logger, which are accumulated by * sub-loggers and passed to the transports. */ constructor(options = undefined) { _Logger_instances.add(this); _Logger_options.set(this, void 0); __classPrivateFieldSet(this, _Logger_options, parseOptions(options), "f"); // Create aliases for the log methods, allowing them to be used in a // manner similar to the console object. const bind = (level) => harden(__classPrivateFieldGet(this, _Logger_instances, "m", _Logger_dispatch).bind(this, { ...__classPrivateFieldGet(this, _Logger_options, "f"), level, })); this.log = bind('log'); this.debug = bind('debug'); this.info = bind('info'); this.warn = bind('warn'); this.error = bind('error'); } /** * Creates a sub-logger with the given options. * * @param options - The options for the sub-logger, or a string to use as the * sub-logger's tag. * @returns The sub-logger. */ subLogger(options = {}) { return new Logger(mergeOptions(__classPrivateFieldGet(this, _Logger_options, "f"), typeof options === 'string' ? { tags: [options] } : options)); } /** * Injects a stream of log messages into the logger. * * @param stream - The stream of log messages to inject. * @param onError - The function to call if an error occurs while draining * the stream. If not provided, the error will be lost to the void. */ injectStream(stream, onError) { stream .drain(async ({ params }) => { const [, args] = params; const { level, tags, message, data } = lunser(args); const logArgs = message === undefined ? [] : [message, ...(data ?? [])]; __classPrivateFieldGet(this, _Logger_instances, "m", _Logger_dispatch).call(this, { level, tags }, ...logArgs); }) .catch((problem) => onError?.(problem)); } } _Logger_options = new WeakMap(), _Logger_instances = new WeakSet(), _Logger_dispatch = function _Logger_dispatch(options, ...args) { const { transports, level, tags } = mergeOptions(__classPrivateFieldGet(this, _Logger_options, "f"), options); const [message, ...data] = args; const entry = harden({ level, tags, message, data }); transports.forEach((transport) => transport(entry)); }; harden(Logger); //# sourceMappingURL=logger.mjs.map