Skip to content
LogoLogo

@portable/log

Functions

Log.format

Returns a record's arguments as one line of text, replacing format specifiers as Node's util.format does, except that objects are written with JSON.stringify instead of util.inspect. %s, %d, %i, %f, %j, %o and %O in the first argument are replaced with the next arguments, %c and its argument are dropped, and the remaining arguments are appended after spaces. Errors are written as their stack. A format string with no arguments after it is returned unchanged.

function format(record: Record): string;
Log.subscribe((record) => lines.push(Log.format(record)));

Log.create

Returns a logger for namespace. debug and info calls are off until a pattern enables the namespace, and warn and error calls are on until a pattern turns it off.

function create(namespace: string): Logger;
const log = Log.create('app:db');
log.debug('connected to %s', url);
log.warn('slow query', { ms: 812 });

Log.disable

Turns off every namespace at every level, warnings and errors included, and returns the patterns that were in effect, so enable can restore them.

function disable(): string;
const previous = Log.disable();
Log.enable(previous);

Log.enable

Sets which namespaces log, with debug's pattern syntax plus an optional minimum level: app:*,-app:noisy,lib:*=warn. Pass undefined to keep the current patterns and change only options. Throws a RangeError for an unknown level.

function enable(
  patterns: string | undefined,
  options: enable.Options = {},
): void;
OptionTypeDefaultDescription
persistbooleanfalseAlso writes the patterns to localStorage.debug, so they apply after a reload.
consolebooleantrueWrites enabled calls to console. Set to false to log only through subscribe.
timebooleanfalsePrefixes console output with an ISO 8601 timestamp.
contextContextStorageStorage for withContext, such as new AsyncLocalStorage() from node:async_hooks.
Log.enable('app:*', { time: true });

Log.subscribe

Calls subscriber with every enabled log call, after the console output.

function subscribe(
  subscriber: (record: Record) => void,
  options: subscribe.Options = {},
): void;
OptionTypeDefaultDescription
signalAbortSignalRemoves the subscriber when the signal aborts.
Log.subscribe((record) => lines.push(Log.format(record)), { signal });

Log.withContext

Runs fn with properties added to every record logged during the call, including records from loggers created elsewhere. Needs a context storage passed to enable. Without one it just calls fn.

function withContext<result>(
  properties: Properties,
  fn: () => result,
): result;
Log.withContext({ requestId }, () => handle(request));

Log.write

Writes a record to console as the default output does: the namespace in a color picked from its name, then the arguments, then the properties. debug records go to console.log, because Chrome hides console.debug unless its Verbose level is on.

function write(record: Record): void;
Log.enable(undefined, { console: false });
Log.subscribe((record) =>
  Log.console({ ...record, properties: redact(record.properties) }),
);

Types

Log.ContextStorage

Storage for withContext. Node's AsyncLocalStorage has this shape, and so does AsyncLocalStorage in Bun, Deno and Cloudflare Workers with nodejs_compat.

type ContextStorage = {
  run: <result>(store: Properties, fn: () => result) => result;
  getStore: () => Properties | undefined;
};

Log.Level

A log level, from most to least verbose.

type Level =  |  |  | ;

Log.Logger

A logger made by create. Its methods don't use this, so they can be passed around alone.

type Logger = {
  debug: (...args: readonly unknown[]) => void;
  info: (...args: readonly unknown[]) => void;
  warn: (...args: readonly unknown[]) => void;
  error: (...args: readonly unknown[]) => void;
  extend: (suffix: string) => Logger;
  with: (properties: Properties) => Logger;
  isEnabled: (level?: Level) => boolean;
  readonly namespace: string;
};

Log.Properties

Properties attached to a record by with and withContext.

type Properties = Readonly<{
  [key: string]: unknown;
}>;

Log.Record

One enabled log call, as subscribe receives it.

type Record = {
  time: Date;
  level: Level;
  namespace: string;
  args: readonly unknown[];
  properties: Properties;
};