Skip to content
Zap Studio
logger
Esc
navigateopen⌘Jpreview
On this page

Output Formats

Pick a built-in output format for ConsoleLogger, or write your own.

ConsoleLogger accepts a format?: LogFormatter option, defaulting to classicFormat — today’s message + context output. Built-in formatters are all exported from logger (and the dedicated @zap-studio/logger/format subpath).

import { ConsoleLogger, jsonFormat } from "@zap-studio/logger";

const logger = new ConsoleLogger({ format: jsonFormat });

classicFormat (default)

The message, plus context as a second console argument when present. Leaves object inspection to the runtime console — collapsible in browser devtools, util.inspect in Node.

logger.info("server started", { port: 3000 });
// console.info("server started", { port: 3000 })

jsonFormat

Single-line JSON, pino-compatible field names (time as epoch milliseconds, level, msg):

logger.info("server started", { port: 3000 });
// {"port":3000,"time":1704067200000,"level":"info","msg":"server started"}

compactFormat

Single-line key=value pairs (logfmt) — grep-friendly and still machine-parseable. Values containing whitespace, ", or = are quoted:

logger.info("server started", { port: 3000 });
// port=3000 time=2024-01-01T00:00:00.000Z level=info msg="server started"

prettyFormat

Colorized, human-friendly single-line output: a dim local clock time, a color-coded level label, then the message. context, when present, is still passed as a second argument for native object inspection instead of being hand-formatted:

logger.info("server started", { port: 3000 });
// 12:34:56.789 INFO  server started   { port: 3000 }   (colored)

Color is applied automatically per runtime, with no configuration needed — see Runtime Compatibility for exactly how it adapts on Node, Bun, Deno, browsers, and Cloudflare Workers.

Field Merging (jsonFormat / compactFormat)

context fields are flattened to the top level rather than nested under a context key, matching the pino/bunyan convention:

logger.info("server started", { port: 3000 });
// jsonFormat: {"port":3000,"time":...,"level":"info","msg":"server started"}

A context field named time, level, or msg can never override the base field — the base fields are always applied last.

Error and bigint context values are handled specially, since neither survives JSON.stringify on its own (JSON.stringify(new Error("boom")) is "{}"):

logger.error("request failed", { error: new Error("boom") });
// jsonFormat:    ...,"error":{"name":"Error","message":"boom","stack":"..."}
// compactFormat: ... error="Error: boom"

Writing Your Own

Any function matching LogFormatter works — no registration required:

import type { LogFormatter, LogRecord } from "@zap-studio/logger";

const upperFormat: LogFormatter = (record: LogRecord) => [record.message.toUpperCase()];

const logger = new ConsoleLogger({ format: upperFormat });

A LogRecord has level, message, context (Record<string, unknown> | undefined), and timestamp (a Date, built fresh for each call that passes the minLevel filter).

A LogFormatter returns the argument list console[method](...) gets called with — return one string for a single line, or more arguments (like classicFormat and prettyFormat do) to hand context off for native inspection.

Last updated on September 21, 2026

Was this page helpful?