Changelog - 2026-07-17
Logger Correctness Pass
Bug Fix Enhancement Behavior ChangeIn one line. The Winston pipeline now formats per transport (color on console only, valid JSON everywhere), honors a configurable level floor, writes files only when asked to, and can no longer crash the process over a lost UDP log line.
What changed
- Log files no longer contain ANSI color codes. Formatting is split into a shared preparation stage (label, timestamp, error normalization, deep splat) on the logger and a per-transport assembly stage - the console colorizes, files and UDP get the same line plain.
- JSON mode emits valid JSON. The dead
colorize()sitting afterjson()is gone, anderrors({ stack: true })now runs before assembly instead of afterprintfwhere it was a no-op. APP_ENV_LOGGER_LEVELsets the logger-level floor (defaultdebug, preserving current behavior). Transports without their own level inherit it - this also un-caps the UDP transport, which was silently pinned toinfoby Winston's default logger level.- File logging is opt-in. Without
APP_ENV_LOGGER_FOLDER_PATH, no rotating file transports are created. Previously the folder defaulted to./and every process scattered*-info-*.logfiles into its working directory. - Custom-logger caching is fixed.
Logger.get(scope, customLogger)used to cache underscope:custom, so a second, different Winston instance for the same scope silently got the first one's wrapper - and.for(method)on a custom-backed logger silently fell back to the defaultapplicationLogger. A custom-backed logger is now a fresh wrapper per call, and.for()keeps its backing instance. DgramTransportcannot crash the process. A failed UDPsendused toemit('error')with no listener attached - a process-killing unhandled error. It now logs the failure and drops the socket so the next line reconnects.
Who is affected
- Apps using
LoggerFactory.getLogger/this.logger.for(...). No action needed - the API surface is unchanged. - Deployments relying on default
./file logs WITHOUTAPP_ENV_LOGGER_FOLDER_PATH. File logs stop appearing until the variable is set. Console output is unchanged, so stdout-based collection (Docker/Kubernetes) is unaffected. SetAPP_ENV_LOGGER_FOLDER_PATHto keep rotating files. - Log aggregators parsing text-format files. Lines no longer carry ANSI escapes - strip-ANSI workarounds can be removed.
Details
- The
textconsole line shape is unchanged:<timestamp> [<label>] <level>: <message>. - New
ICustomLoggerOptionsfields:format?: 'json' | 'text'andlevel?: TLogLevel, both defaulting to the corresponding env vars. PassingloggerFormatterstill overrides everything, applied identically to every transport as before. - New exports:
resolveLoggerLevel({ configured })(validates againstLogLevels, falls back todebugwith a console warning) andresolveDefaultTransportOptions()(the env-driven default transport set, resolved at call time). definePrettyLoggerFormattergainedcolorize?: boolean(defaulttrue) for building plain text formatters.
| File | Package |
|---|---|
src/modules/logger/default-logger.ts | helpers |
src/modules/logger/application-logger.ts | helpers |
src/modules/logger/transports/dgram.transport.ts | helpers |