UNPKG

@libp2p/logger

Version:

A logging component for use in js-libp2p modules

237 lines • 6.79 kB
/** * @packageDocumentation * * A logger for libp2p based on [weald](https://www.npmjs.com/package/weald), a TypeScript port of the venerable [debug](https://www.npmjs.com/package/debug) module. * * @example * * ```TypeScript * import { logger } from '@libp2p/logger' * * const log = logger('libp2p:my:component:name') * * try { * // an operation * log('something happened: %s', 'it was ok') * } catch (err) { * log.error('something bad happened: %e', err) * } * * log('with this peer: %p', {}) * log('and this base58btc: %b', Uint8Array.from([0, 1, 2, 3])) * log('and this base32: %t', Uint8Array.from([4, 5, 6, 7])) * ``` * * ```console * $ DEBUG=libp2p:* node index.js * something happened: it was ok * something bad happened: <stack trace> * with this peer: 12D3Foo * with this base58btc: Qmfoo * with this base32: bafyfoo * ``` */ import { base32 } from 'multiformats/bases/base32'; import { base58btc } from 'multiformats/bases/base58'; import { base64 } from 'multiformats/bases/base64'; import debug from 'weald'; import { truncatePeerId } from "./utils.js"; // Add a formatter for converting to a base58 string debug.formatters.b = (v) => { return v == null ? 'undefined' : base58btc.baseEncode(v); }; // Add a formatter for converting to a base32 string debug.formatters.t = (v) => { return v == null ? 'undefined' : base32.baseEncode(v); }; // Add a formatter for converting to a base64 string debug.formatters.m = (v) => { return v == null ? 'undefined' : base64.baseEncode(v); }; // Add a formatter for stringifying peer ids debug.formatters.p = (v) => { return v == null ? 'undefined' : v.toString(); }; // Add a formatter for stringifying CIDs debug.formatters.c = (v) => { return v == null ? 'undefined' : v.toString(); }; // Add a formatter for stringifying Datastore keys debug.formatters.k = (v) => { return v == null ? 'undefined' : v.toString(); }; // Add a formatter for stringifying Multiaddrs debug.formatters.a = (v) => { return v == null ? 'undefined' : v.toString(); }; function formatError(v, indent = '') { const message = notEmpty(v.message); const stack = notEmpty(v.stack); // some browser errors (mostly from Firefox) have no message or no stack, // sometimes both, sometimes neither. Sometimes the message is in the stack, // sometimes is isn't so try to do *something* useful if (message != null && stack != null) { if (stack.includes(message)) { return `${stack.split('\n').join(`\n${indent}`)}`; } return `${message}\n${indent}${stack.split('\n').join(`\n${indent}`)}`; } if (stack != null) { return `${stack.split('\n').join(`\n${indent}`)}`; } if (message != null) { return `${message}`; } return `${v.toString()}`; } function isAggregateError(err) { return err instanceof AggregateError || (err?.name === 'AggregateError' && Array.isArray(err.errors)); } function printError(err, indent = '') { if (isAggregateError(err)) { let output = formatError(err, indent); if (err.errors.length > 0) { indent = `${indent} `; output += `\n${indent}${err.errors .map(err => `${printError(err, `${indent}`)}`) .join(`\n${indent}`)}`; } else { output += `\n${indent}[Error list was empty]`; } return output.trim(); } return formatError(err, indent); } // Add a formatter for stringifying Errors debug.formatters.e = (v) => { if (v == null) { return 'undefined'; } return printError(v); }; function createDisabledLogger(namespace) { const logger = () => { }; logger.enabled = false; logger.color = ''; logger.diff = 0; logger.log = () => { }; logger.namespace = namespace; logger.destroy = () => true; logger.extend = () => logger; logger.useColors = () => false; return logger; } /** * Create a component logger that will prefix any log messages with a truncated * peer id. * * @example * * ```TypeScript * import { peerLogger } from '@libp2p/logger' * import { peerIdFromString } from '@libp2p/peer-id' * * const peerId = peerIdFromString('12D3FooBar') * const logger = peerLogger(peerId) * * const log = logger.forComponent('my-component') * log.info('hello world') * // logs "12…oBar:my-component hello world" * ``` */ export function peerLogger(peerId, options = {}) { return prefixLogger(truncatePeerId(peerId, options), options); } /** * Create a component logger that will prefix any log messages with the passed * string. * * @example * * ```TypeScript * import { prefixLogger } from '@libp2p/logger' * * const logger = prefixLogger('my-node') * * const log = logger.forComponent('my-component') * log.info('hello world') * // logs "my-node:my-component hello world" * ``` */ export function prefixLogger(prefix, options) { return { forComponent(name) { return logger(`${prefix}:${name}`, options); } }; } /** * Create a component logger * * @example * * ```TypeScript * import { defaultLogger } from '@libp2p/logger' * import { peerIdFromString } from '@libp2p/peer-id' * * const logger = defaultLogger() * * const log = logger.forComponent('my-component') * log.info('hello world') * // logs "my-component hello world" * ``` */ export function defaultLogger(options) { return { forComponent(name) { return logger(name, options); } }; } /** * Creates a logger for the passed component name. * * @example * * ```TypeScript * import { logger } from '@libp2p/logger' * * const log = logger('my-component') * log.info('hello world') * // logs "my-component hello world" * ``` */ export function logger(name, options) { // trace logging is a no-op by default let trace = createDisabledLogger(`${name}:trace`); // look at all the debug names and see if trace logging has explicitly been enabled if (debug.enabled(`${name}:trace`) && debug.names.map((r) => r.toString()).find((n) => n.includes(':trace')) != null) { trace = debug(`${name}:trace`, options); } return Object.assign(debug(name, options), { error: debug(`${name}:error`, options), trace, newScope: (scope) => logger(`${name}:${scope}`, options) }); } export function disable() { debug.disable(); } export function enable(namespaces) { debug.enable(namespaces); } export function enabled(namespaces) { return debug.enabled(namespaces); } function notEmpty(str) { if (str == null) { return; } str = str.trim(); if (str.length === 0) { return; } return str; } //# sourceMappingURL=index.js.map