Skip to content

Logger API

Standalone logger, imported via the subpath @fullhaus/rivet/logger. Independent of the component runtime.

import {
createLogger,
logger,
consoleTransport,
memoryTransport,
} from "@fullhaus/rivet/logger";
function createLogger(config?: LoggerConfig): Logger;

Creates a logger. Without an argument the defaults apply.

const log = createLogger({ scope: "checkout", level: "debug", format: "json" });
const logger: Logger;

Ready-to-use default instance without scope.

import { logger } from "@fullhaus/rivet/logger";
logger.info("ready");
type Logger = {
debug(message: string, ...args: unknown[]): void;
info(message: string, ...args: unknown[]): void;
warn(message: string, ...args: unknown[]): void;
error(message: string, ...args: unknown[]): void;
/** Child logger with a nested scope; shares the parent's config. */
child(scope: string): Logger;
/** Update the shared config at runtime. `scope` is ignored. */
configure(config: Omit<Partial<LoggerConfig>, "scope">): void;
/** Snapshot of the effective config (shared fields + own scope). */
getConfig(): Required<LoggerConfig>;
};
type LoggerConfig = {
level?: LogLevel; // default "info"
scope?: string; // default ""
transports?: LogTransport[]; // default [consoleTransport]
format?: "pretty" | "json" | "plain"; // default "pretty"
now?: () => Date; // default () => new Date() (test injection)
};
type LogLevel = "debug" | "info" | "warn" | "error" | "silent";

Weighting: debug (10) < info (20) < warn (30) < error (40) < silent (100). Entries below the configured level are dropped.

type LogEntry = {
level: "debug" | "info" | "warn" | "error"; // never "silent"
scope: string;
message: string; // raw message, never formatted
args: unknown[];
timestamp: Date;
};
type LogTransport = (formatted: string, entry: LogEntry) => void;

A transport receives the formatted string and the raw entry.

const consoleTransport: LogTransport;

Default transport: writes with the console method matching the level (console.debug/info/warn/error) and appends entry.args.

function memoryTransport(): {
transport: LogTransport;
entries: Array<{ formatted: string; entry: LogEntry }>;
clear(): void;
};

Collects entries in memory — for tests and snapshot assertions.

const mem = memoryTransport();
const log = createLogger({ transports: [mem.transport] });
log.info("hello");
mem.entries[0].entry.message; // "hello"
mem.entries[0].formatted; // "… INFO hello"
mem.clear();
FormatExample output
pretty2025-01-01T00:00:00.000Z INFO [scope] message
plain[scope] message
json{"time":"…","level":"info","scope":"…","message":"…","args":[…]}

json is safe against circular references ([Circular]) and serializes Error objects with name, message and stack.

child(scope) shares the parent’s config. configure(...) on any logger in the tree updates level, transports and format everywhere — only scope is per-logger. For an independent tree, call createLogger() again.