Skip to main content
Runtime-agnostic logging · built on LogLayer

Stop rewriting your logger for every runtime.

One logging API for the browser, Node.js, and workers. Configure once, log everywhere.

This is the whole learning curve.

Import the singleton and log. No factory to wire up, no context provider to mount, no environment checks. When you are ready for Datadog, pretty output, or request tracing, you opt in — the call sites never change.

Read the intro
import { logger } from '@cues/sawdust/logger'

// Works the same in Node, the browser, and workers.
logger.info('checkout completed', { orderId, amountCents })
logger.error('payment failed', err, { orderId })

Everything a shared logging layer should be

Sawdust is the logging toolkit your monorepo keeps trying to build by hand — done once, correctly, and shared everywhere.

🌍

One API, every runtime

The same import and the same calls run in Node.js, the browser, and background workers. No per-environment logger, no #ifdefs, no drift.

🔌

Pluggable transports

Console, pretty terminal, Consola, Datadog logs, Datadog browser logs, and RUM — mix and match per environment. Built on LogLayer.

♻️

Configure once, upgrade in place

A singleton façade you can import before it is even configured. Bootstrap promotes it to a richer logger without breaking a single existing import.

🧵

Request-scoped context

AsyncLocalStorage on Node stamps every log inside a request with its requestId, userId, and route — automatically, with zero prop drilling.

🧪

Testing built in

Service-locator resets and a noop logger make suites deterministic. Swap in a mock, assert the calls, reset — no leaking global state.

🛡️

Structured & safe

Round-trippable error serialization and context sanitization mean clean, queryable logs instead of stringified stack-trace soup.

Runtime coverage

One package. The right build resolves automatically.

CapabilityNode.jsBrowserWorker
Singleton façade + scoring
Console / pretty / Consola
Datadog server logs + APM trace injection
Datadog browser logs + RUM
AsyncLocalStorage request scopestack emulation

Your future self is already using it.

Add one dependency, delete a folder of bespoke logger glue, and get consistent structured logs across every app you ship.