Field guide · operations

Structured logging without runtime dependencies?

Short answer

JSON calls alone are insufficient. Define five contracts: a stable NDJSON envelope, context through child loggers, redaction before delivery, a bounded backpressure policy, and root logger closure after inbound traffic stops. swm-logs 0.1.1 implements formatting and lifecycle while leaving storage, retries, and network delivery to the application.

NDJSON
format
5
explicit contracts
64 KiB
buffer default

Scope

This guidance targets native ESM on Node.js 22/24. “Zero dependencies” describes the package runtime surface; an external log collection system is still required.

Minimum structured logging contract

ConcernContractVerification
EventOne JSON record per line; level, time, and msg keep stable types.A line reader parses the stream without multiline exceptions.
ContextA child logger inherits service and request bindings without mutating its parent.requestId appears on every request event and never leaks to another request.
SecretsExact and wildcard paths are redacted before the formatter and transport.Tests cover tokens, passwords, and dynamic headers or cookies.
BackpressureImmediate mode is valid only without a strict limit; otherwise use a bounded transport.max queue, overflow policy, and the loss counter are explicit.
ShutdownStop new requests, drain work, then await rootLogger.close().An integration test proves that the final event is delivered.
Crash pathfatal + flushSync(); durable guarantees require a file descriptor or a transport guarantee.A separate-process test exits abnormally and checks the final record.

Minimum production setup

  1. 01

    A platform agent collects stdout

    Start with immediate output

    But measure the Node.js stream queue and do not describe it as bounded.

  2. 02

    Loss must be bounded and measurable

    Implement a bounded transport

    Fix queue size, overflow policy, retries, and an independent loss metric.

  3. 03

    Durable local writes are required

    Use a file descriptor

    Verify flushSync() and own rotation and retention separately.

Solution boundaries

  • A logger does not replace a collector, storage, retention, or alerting.
  • Pretty output belongs in the development pipeline and must not change the production envelope.
  • A field list alone cannot protect secrets; schemas and redaction tests must evolve together.

Verifiable contract

The page is based on the published package and its fixed README snapshot.