Skip to content

Logger

Rivet ships a small, configurable logger as a separate subpath. It is independent of the component runtime — usable anywhere, even without createRivet().

import { createLogger, logger } from "@fullhaus/rivet/logger";
import { createLogger } from "@fullhaus/rivet/logger";
const log = createLogger({
level: "debug", // "debug" | "info" | "warn" | "error" | "silent"
scope: "checkout", // prefix prepended to every message
format: "pretty", // "pretty" | "plain" | "json"
});
log.info("user added item", { sku: "abc" });
log.warn("retrying request");
log.error("payment failed");

For a quick start there is a ready-to-use instance without scope:

import { logger } from "@fullhaus/rivet/logger";
logger.info("works out of the box");
logger.configure({ level: "debug" });

Messages below the configured level are dropped. Order:

debug (10) < info (20) < warn (30) < error (40) < silent (100)

Default is info. silent suppresses everything.

A scope is a prefix. child(scope) creates a nested scope and shares the configuration of the parent.

const app = createLogger({ scope: "checkout", level: "info" });
const cart = app.child("cart"); // scope becomes "checkout:cart"
cart.debug("ignored"); // below info → dropped
app.configure({ level: "debug" });
cart.debug("kept"); // child sees the change immediately
FormatOutput
pretty2025-01-01T… INFO [scope] message — default, readable
plain[scope] message — minimal
jsonStructured JSON — safe against circular refs, serializes errors

format: "json" is robust against circular references and serializes Error objects with name, message and stack.

A transport receives both: the formatted string and the raw entry. So the default console transport can print the line while a custom transport sends structured data e.g. to a backend.

import { createLogger, type LogTransport } from "@fullhaus/rivet/logger";
const httpTransport: LogTransport = (_formatted, entry) => {
fetch("/log", {
method: "POST",
body: JSON.stringify({
level: entry.level,
scope: entry.scope,
message: entry.message,
args: entry.args,
time: entry.timestamp.toISOString(),
}),
});
};
const log = createLogger({
transports: [
(entry) => console.log(entry), // formatted string
httpTransport,
],
});
log.configure({ level: "warn" });
log.configure({ format: "json", transports: [httpTransport] });