Skip to main content
Welcome. This site supports keyboard navigation and screen readers. Press ? at any time for keyboard shortcuts. Press [ to focus the sidebar, ] to focus the content. High-contrast themes are available via the toolbar.
serard@dev00:~/cv

Structured Logging as a Port

A codebase with console.log scattered through it cannot be made observable retroactively — every log site is its own format, its own severity convention, its own missing field. @frenchexdev/ddd-log reifies logging as a port so the application calls logger.info(...) everywhere, the adapter decides what happens to those calls, and the same port works against a console for development and a structured-output collector for production.


What Log Reifies

The discipline a structured-logging port forces is typed fields. A log line is not a printf-style format string; it is a message plus a record of structured fields (request id, customer id, latency, error code) that an aggregator can index. The team that adopts structured logging gains the ability to query every error with customer_id=cu_abc across the entire system, which is the difference between an outage that resolves in twenty minutes and one that resolves in two hours.

The port surface — info, warn, error, debug — is the standard four-level shape. The discipline added by the corpus is that fields are typed records, not positional arguments or untyped objects. A logger called with logger.info('subscription started', { customerId: c.id, plan: 'pro' }) has a typed second argument; passing a string where an object is expected is a compile error rather than a runtime corruption of the log shape.


The Runtime: ddd-log and adapter

Two packages — ddd-log, ddd-log-console-adapter — both M4/M5 stubs pinned to TelemetryStructuredObservabilityRequirement. The console adapter writes JSON lines to stdout — the standard shape for log aggregators (Loki, Vector, Fluent Bit) that read container output.


The Analyzer: ddd-log-analyzer

Spec-first (spec.ts). Priority Medium. One info-severity rule, DDD-LOG-001, recommending the Logger suffix on the port class. The naming convention is enough for the analyzer to enforce because the real discipline (typed fields, no positional formatting) lives in the port's TypeScript signature, not in a separate lint pass.


  • One of the three telemetry ports together with @Metrics and @Tracing, all sharing the TelemetryStructuredObservabilityRequirement parent.
  • Consumed by every layer — domain services, application services, adapters. Logging is cross-cutting on purpose.
  • The console adapter is the development substrate; a structured-output adapter (JSON to a collector) is the operational substrate, scaffolded by the conformance suite.

Back to the series index.

⬇ Download