DeutschGitHub
prototypepackages/logger/src

Logger

@ralphschuler/logger

Formats messages with corrected severity filtering, bounded history and explicit output.

structured logsterminallevels

01 · Problem

What is it for?

Operational logs must remain visible at the right severity without leaking resources or terminating a process unexpectedly.

02 · Mental model

How should you think about it?

A logger selects an event, formats it and writes to an injected destination; terminal animations are a presentation concern.

In this repository

Formats messages with corrected severity filtering, bounded history and explicit output. The singleton is retained for compatibility; direct construction supports isolated tests. Fatal logs do not terminate the process.

03 · Control flow

What happens in which order?

  1. Construct a message with level and context.
  2. Apply the configured threshold.
  3. Format for the selected sink.
  4. Write once and retain only bounded diagnostic history.

04 · Building blocks

The important contracts

Logger / getInstanceConstruct an isolated logger or access the compatibility singleton.
trace / debug / info / warn / error / fatalApply severity filtering and write messages without process termination.
profile / profileSyncMeasure work and clean up its animation.

05 · Build it yourself

Implement a small core

Start with this small independent implementation, then use the steps below to make its contract explicit.

  1. Construct a message with level and context.
  2. Apply the configured threshold.
  3. Format for the selected sink.
  4. Write once and retain only bounded diagnostic history.
Concept sketch · may reference omitted helpers
type Level = 10 | 20 | 30 | 40 | 50;
type Record = { at: Date; level: Level; message: string; meta?: object };

class Logger {
  constructor(
    private threshold: Level,
    private write: (record: Record) => void,
    private now = () => new Date(),
  ) {}

  log(level: Level, message: string, meta?: object) {
    if (level < this.threshold) return;
    this.write({ at: this.now(), level, message, meta });
  }
}

06 · Verify

What should you test?

  • Verify every threshold boundary and fatal behavior.
  • Stop all animation timers after use.
  • Check color reset sequences and bounded history.

Try it yourself

Turn the first verification claim into a failing test, implement the smallest fix, then add a boundary case.

Verify every threshold boundary and fatal behavior.

Compare your approach

Your check should fail when the stated invariant is deliberately broken, and pass again after the fix. Keep setup deterministic and assert an observable result.

07 · Limits

Trade-offs and failure modes

  • Singleton configuration can create hidden dependencies.
  • Avoid terminal animation in unattended logs.
  • Process termination must be a caller decision.
Important

The singleton is retained for compatibility; direct construction supports isolated tests. Fatal logs do not terminate the process.

08 · Keep exploring

Source code and related ideas

yarn tsx packages/logger/examples/basic.ts