UNPKG

loglevelnext

Version:

A modern logging library for Node.js and modern browsers that provides log level mapping to the console

255 lines (251 loc) 7.12 kB
// src/MethodFactory.ts var defaultLevels = { TRACE: 0, DEBUG: 1, INFO: 2, WARN: 3, ERROR: 4, SILENT: 5 }; var levels = Symbol("log-levels"); var instance = Symbol("log-instance"); var noop = () => { }; var MethodFactory = class { constructor(logger) { this[instance] = logger; this[levels] = defaultLevels; } // @ts-ignore get levels() { return this[levels]; } get logger() { return this[instance]; } get methods() { return Object.keys(this.levels).map((key) => key.toLowerCase()).filter((key) => key !== "silent"); } set logger(logger) { this[instance] = logger; } // eslint-disable-next-line class-methods-use-this bindMethod(obj, methodName) { const method = obj[methodName]; if (typeof method.bind === "function") { return method.bind(obj); } try { return Function.prototype.bind.call(method, obj); } catch (e) { return function result() { return Function.prototype.apply.apply(method, [obj, arguments]); }; } } distillLevel(level) { let value; if (typeof level === "string") { const levels2 = this.levels; value = levels2[level.toUpperCase()]; } else { value = level; } if (this.levelValid(value)) return value; return null; } levelValid(level) { const max = Math.max(...Object.values(this.levels)); if (typeof level === "number" && level >= 0 && level <= max) { return true; } return false; } /** * Build the best logging method possible for this env * Wherever possible we want to bind, not wrap, to preserve stack traces. * Since we're targeting modern browsers, there's no need to wait for the * console to become available. */ // eslint-disable-next-line class-methods-use-this make(methodName) { const target = console; if (typeof target[methodName] !== "undefined") { return this.bindMethod(target, methodName); } else if (typeof console.log !== "undefined") { return this.bindMethod(target, "log"); } return noop; } replaceMethods(logLevel) { const level = this.distillLevel(logLevel); if (level === null) { throw new Error(`loglevelnext: replaceMethods() called with invalid level: ${logLevel}`); } if (!this.logger || this.logger.type !== "LogLevel") { throw new TypeError( "loglevelnext: Logger is undefined or invalid. Please specify a valid Logger instance." ); } this.methods.forEach((methodName) => { const { [methodName.toUpperCase()]: methodLevel } = this.levels; this.logger[methodName] = methodLevel < level ? noop : this.make(methodName); }); this.logger.log = this.logger.debug; } }; instance, levels; // src/PrefixFactory.ts var defaults = { level: (opts) => `[${opts.level}]`, name: (opts) => opts.logger.name, template: "{{time}} {{level}} ", time: () => (/* @__PURE__ */ new Date()).toTimeString().split(" ")[0] }; var PrefixFactory = class extends MethodFactory { constructor(logger, options) { super(logger); this.options = Object.assign({}, defaults, options); } interpolate(level) { return this.options.template.replace(/{{([^{}]*)}}/g, (stache, prop) => { const fn = this.options[prop]; if (typeof fn === "function") { return fn({ level, logger: this.logger }); } return stache; }); } make(methodName) { const og = super.make(methodName); return (...args) => { const output = this.interpolate(methodName); const [first] = args; if (typeof first === "string") { args[0] = output + first; } else { args.unshift(output); } og(...args); }; } }; // src/LogLevel.ts var defaults2 = { factory: void 0, level: "warn", name: (+/* @__PURE__ */ new Date()).toString(), prefix: void 0 }; var LogLevel = class { constructor(options) { this.type = "LogLevel"; this.options = Object.assign({}, defaults2, options); this.methodFactory = options.factory; if (!this.methodFactory) { const factory = options.prefix ? new PrefixFactory(this, options.prefix) : new MethodFactory(this); this.methodFactory = factory; } if (!this.methodFactory.logger) { this.methodFactory.logger = this; } this.name = options.name || "<unknown>"; this.level = this.options.level ?? "trace"; } get level() { return this.currentLevel; } get levels() { return this.methodFactory.levels; } get factory() { return this.methodFactory; } set factory(factory) { factory.logger = this; this.methodFactory = factory; this.methodFactory.replaceMethods(this.level); } set level(logLevel) { const level = this.methodFactory.distillLevel(logLevel); if (level === false || level == null) { throw new RangeError(`loglevelnext: setLevel() called with invalid level: ${logLevel}`); } this.currentLevel = level; this.methodFactory.replaceMethods(level); const max = Math.max(...Object.values(this.levels)); if (typeof console === "undefined") { process.stdout.write("loglevelnext: console is undefined. The log will produce no output.\n"); } else if (level > max) { console.warn( `The log level has been set to a value greater than 'silent'. The log will produce no output.` ); } } disable() { const levels2 = this.levels; if (levels2.SILENT) { this.level = levels2.SILENT; } else { console.warn( `loglevelnext: no 'silent' level defined. The log cannot be disabled. You may want to override the 'disable' method.` ); } } enable() { const levels2 = this.levels; if (typeof levels2.TRACE !== "undefined") { this.level = levels2.TRACE; } else { console.warn( `loglevelnext: no 'trace' level defined. The log cannot be enabled. You may want to override the 'trace' method.` ); } } }; // src/index.ts var factories = Symbol("log-factories"); var DefaultLogger = class extends LogLevel { constructor() { super({ name: "default" }); this.cache = { default: this }; this[factories] = { MethodFactory, PrefixFactory }; } get factories() { return this[factories]; } get loggers() { return this.cache; } create(opts) { let options; if (typeof opts === "string") { options = { name: opts }; } else { options = Object.assign({}, opts); } if (!options.id) { options.id = options.name.toString(); } const { name, id } = options; const defaults3 = { level: this.level }; if (typeof name !== "string" || !name || !name.length) { throw new TypeError("You must supply a name when creating a logger."); } let logger = this.cache[id]; if (!logger) { logger = new LogLevel(Object.assign({}, defaults3, options)); this.cache[id] = logger; } return logger; } }; var src_default = new DefaultLogger(); export { LogLevel, MethodFactory, PrefixFactory, src_default as default, defaultLevels };