@venizia/ignis-docs 0.2.0 → 0.2.1-0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (142) hide show
  1. package/README.md +14 -14
  2. package/content/best-practices/api-usage-examples.md +39 -19
  3. package/content/best-practices/architectural-patterns.md +22 -11
  4. package/content/best-practices/architecture-decisions.md +29 -16
  5. package/content/best-practices/code-style-standards/advanced-patterns.md +43 -31
  6. package/content/best-practices/code-style-standards/constants-configuration.md +19 -4
  7. package/content/best-practices/code-style-standards/control-flow.md +33 -1
  8. package/content/best-practices/code-style-standards/documentation.md +28 -8
  9. package/content/best-practices/code-style-standards/function-patterns.md +15 -4
  10. package/content/best-practices/code-style-standards/index.md +7 -2
  11. package/content/best-practices/code-style-standards/naming-conventions.md +26 -2
  12. package/content/best-practices/code-style-standards/route-definitions.md +9 -5
  13. package/content/best-practices/code-style-standards/tooling.md +14 -1
  14. package/content/best-practices/code-style-standards/type-safety.md +39 -6
  15. package/content/best-practices/common-pitfalls.md +59 -35
  16. package/content/best-practices/contribution-workflow.md +6 -2
  17. package/content/best-practices/data-modeling.md +78 -62
  18. package/content/best-practices/deployment-strategies.md +56 -19
  19. package/content/best-practices/error-handling.md +182 -93
  20. package/content/best-practices/index.md +6 -0
  21. package/content/best-practices/performance-optimization.md +26 -13
  22. package/content/best-practices/security-guidelines.md +35 -9
  23. package/content/best-practices/testing-strategies.md +7 -2
  24. package/content/best-practices/troubleshooting-tips.md +27 -17
  25. package/content/extensions/components/api-reference.md +107 -322
  26. package/content/extensions/components/authentication/api.md +454 -603
  27. package/content/extensions/components/authentication/errors.md +121 -498
  28. package/content/extensions/components/authentication/index.md +88 -801
  29. package/content/extensions/components/authentication/usage.md +207 -956
  30. package/content/extensions/components/authorization/api.md +736 -656
  31. package/content/extensions/components/authorization/errors.md +168 -206
  32. package/content/extensions/components/authorization/index.md +82 -797
  33. package/content/extensions/components/authorization/usage.md +194 -527
  34. package/content/extensions/components/health-check.md +71 -243
  35. package/content/extensions/components/mail/api.md +504 -287
  36. package/content/extensions/components/mail/errors.md +73 -61
  37. package/content/extensions/components/mail/index.md +96 -467
  38. package/content/extensions/components/mail/usage.md +130 -172
  39. package/content/extensions/components/request-tracker.md +66 -173
  40. package/content/extensions/components/socket-io/api.md +195 -13
  41. package/content/extensions/components/socket-io/errors.md +3 -3
  42. package/content/extensions/components/socket-io/index.md +50 -337
  43. package/content/extensions/components/socket-io/usage.md +143 -26
  44. package/content/extensions/components/static-asset/api.md +410 -142
  45. package/content/extensions/components/static-asset/errors.md +110 -53
  46. package/content/extensions/components/static-asset/index.md +79 -608
  47. package/content/extensions/components/static-asset/usage.md +180 -300
  48. package/content/extensions/components/websocket/api.md +275 -399
  49. package/content/extensions/components/websocket/errors.md +47 -56
  50. package/content/extensions/components/websocket/index.md +74 -407
  51. package/content/extensions/components/websocket/usage.md +110 -341
  52. package/content/extensions/helpers/cron/index.md +51 -160
  53. package/content/extensions/helpers/crypto/index.md +62 -483
  54. package/content/extensions/helpers/crypto/reference.md +456 -0
  55. package/content/extensions/helpers/env/index.md +60 -178
  56. package/content/extensions/helpers/error/index.md +221 -207
  57. package/content/extensions/helpers/inversion/index.md +65 -556
  58. package/content/extensions/helpers/inversion/reference.md +522 -0
  59. package/content/extensions/helpers/kafka/admin.md +20 -1
  60. package/content/extensions/helpers/kafka/compile-binary.md +41 -35
  61. package/content/extensions/helpers/kafka/consumer.md +54 -20
  62. package/content/extensions/helpers/kafka/examples.md +21 -16
  63. package/content/extensions/helpers/kafka/index.md +80 -610
  64. package/content/extensions/helpers/kafka/producer.md +134 -5
  65. package/content/extensions/helpers/kafka/schema-registry.md +45 -70
  66. package/content/extensions/helpers/logger/hf-logger.md +193 -0
  67. package/content/extensions/helpers/logger/index.md +64 -563
  68. package/content/extensions/helpers/logger/pino.md +85 -0
  69. package/content/extensions/helpers/logger/reference.md +746 -0
  70. package/content/extensions/helpers/network/api.md +241 -195
  71. package/content/extensions/helpers/network/index.md +72 -530
  72. package/content/extensions/helpers/queue/index.md +72 -900
  73. package/content/extensions/helpers/queue/reference.md +467 -0
  74. package/content/extensions/helpers/redis/index.md +73 -645
  75. package/content/extensions/helpers/redis/reference.md +727 -0
  76. package/content/extensions/helpers/secrets/index.md +66 -0
  77. package/content/extensions/helpers/socket-io/api.md +305 -203
  78. package/content/extensions/helpers/socket-io/index.md +66 -432
  79. package/content/extensions/helpers/storage/api.md +564 -462
  80. package/content/extensions/helpers/storage/index.md +77 -573
  81. package/content/extensions/helpers/types/index.md +66 -499
  82. package/content/extensions/helpers/types/reference.md +650 -0
  83. package/content/extensions/helpers/uid/index.md +58 -227
  84. package/content/extensions/helpers/websocket/api.md +329 -216
  85. package/content/extensions/helpers/websocket/index.md +65 -503
  86. package/content/extensions/helpers/worker-thread/index.md +58 -396
  87. package/content/extensions/helpers/worker-thread/reference.md +428 -0
  88. package/content/guides/core-concepts/persistent/models.md +1 -1
  89. package/content/guides/core-concepts/persistent/search-typesense.md +3 -3
  90. package/content/guides/core-concepts/persistent/transactions.md +1 -1
  91. package/content/guides/core-concepts/secrets-vault.md +177 -0
  92. package/content/guides/core-concepts/services.md +1 -1
  93. package/content/guides/migrations/redis-helpers-migration.md +1 -1
  94. package/content/guides/migrations/unified-connectors-migration.md +2 -2
  95. package/content/guides/tutorials/ecommerce-api.md +3 -8
  96. package/content/references/base/application.md +1 -1
  97. package/content/references/base/connectors.md +79 -136
  98. package/content/references/base/datasources-reference.md +599 -0
  99. package/content/references/base/datasources.md +84 -444
  100. package/content/references/base/dependency-injection.md +17 -39
  101. package/content/references/base/filter-system/application-usage.md +69 -121
  102. package/content/references/base/filter-system/array-operators.md +12 -0
  103. package/content/references/base/filter-system/comparison-operators.md +12 -0
  104. package/content/references/base/filter-system/default-filter.md +136 -348
  105. package/content/references/base/filter-system/fields-order-pagination.md +38 -16
  106. package/content/references/base/filter-system/index.md +106 -257
  107. package/content/references/base/filter-system/json-filtering.md +12 -2
  108. package/content/references/base/filter-system/list-operators.md +16 -2
  109. package/content/references/base/filter-system/logical-operators.md +13 -0
  110. package/content/references/base/filter-system/null-operators.md +13 -0
  111. package/content/references/base/filter-system/pattern-matching.md +12 -0
  112. package/content/references/base/filter-system/quick-reference.md +11 -2
  113. package/content/references/base/filter-system/range-operators.md +12 -0
  114. package/content/references/base/filter-system/tips.md +70 -133
  115. package/content/references/base/filter-system/use-cases.md +156 -233
  116. package/content/references/base/middlewares.md +35 -21
  117. package/content/references/base/models-reference.md +886 -0
  118. package/content/references/base/models.md +80 -1452
  119. package/content/references/base/repositories/advanced.md +156 -192
  120. package/content/references/base/repositories/index.md +77 -650
  121. package/content/references/base/repositories/mixins.md +22 -18
  122. package/content/references/base/repositories/relations.md +123 -171
  123. package/content/references/base/repositories/soft-deletable.md +58 -56
  124. package/content/references/base/secrets.md +263 -0
  125. package/content/references/base/services.md +2 -2
  126. package/content/references/configuration/environment-variables.md +48 -4
  127. package/content/references/configuration/index.md +49 -31
  128. package/content/references/quick-reference.md +3 -16
  129. package/content/references/utilities/crypto.md +35 -76
  130. package/content/references/utilities/date.md +33 -73
  131. package/content/references/utilities/index.md +1 -1
  132. package/content/references/utilities/jsx-reference.md +298 -0
  133. package/content/references/utilities/jsx.md +82 -525
  134. package/content/references/utilities/module.md +29 -62
  135. package/content/references/utilities/parse.md +34 -64
  136. package/content/references/utilities/performance.md +33 -58
  137. package/content/references/utilities/promise.md +28 -62
  138. package/content/references/utilities/request.md +57 -218
  139. package/content/references/utilities/schema.md +43 -137
  140. package/content/references/utilities/statuses-reference.md +361 -0
  141. package/content/references/utilities/statuses.md +63 -667
  142. package/package.json +8 -8
@@ -0,0 +1,746 @@
1
+ ---
2
+ title: Logger - Full Reference
3
+ description: Complete reference for Logger, LoggerFactory, HfLogger, transports, formatters, and every APP_ENV_LOGGER_* environment variable
4
+ difficulty: intermediate
5
+ ---
6
+
7
+ # Logger - Full Reference
8
+
9
+ Exhaustive reference for `Logger`, `LoggerFactory`, `HfLogger`/`HfLogFlusher`, the Winston formatter and transport internals, and every environment variable. For a readable introduction and the common tasks, start with the [Logger overview](/extensions/helpers/logger/).
10
+
11
+ The default provider is **Winston** (with `winston-daily-rotate-file` for file rotation). All provider packages are OPTIONAL peers - an application loads exactly ONE provider (single-provider loading, below).
12
+
13
+ **Files:**
14
+
15
+ - [`packages/helpers/src/modules/logger/common/types.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/modules/logger/common/types.ts) - `ILogger`, `TLogLevel`, `TLoggerFormat`
16
+ - [`packages/helpers/src/modules/logger/common/constants.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/modules/logger/common/constants.ts) - `LogLevels`, `LoggerFormats`
17
+ - [`packages/helpers/src/modules/logger/base/abstract.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/modules/logger/base/abstract.ts) - `AbstractLogger`
18
+ - [`packages/helpers/src/modules/logger/base/base.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/modules/logger/base/base.ts) - `BaseLogger`
19
+ - [`packages/helpers/src/modules/logger/formatting/deep-splat.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/modules/logger/formatting/deep-splat.ts) - `formatLogMessage`, `%s` inspection widening
20
+ - [`packages/helpers/src/modules/logger/winston/logger.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/modules/logger/winston/logger.ts) - `WinstonLogger`, `Logger` alias
21
+ - [`packages/helpers/src/modules/logger/winston/define.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/modules/logger/winston/define.ts) - `defineCustomLogger`, formatters
22
+ - [`packages/helpers/src/modules/logger/winston/formatters/deep-splat.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/modules/logger/winston/formatters/deep-splat.ts) - `deepSplat`
23
+ - [`packages/helpers/src/modules/logger/winston/transports/dgram.transport.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/modules/logger/winston/transports/dgram.transport.ts) - `DgramTransport`
24
+ - [`packages/helpers/src/modules/logger/hf/logger.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/modules/logger/hf/logger.ts) - `HfLogger`
25
+ - [`packages/helpers/src/modules/logger/hf/flusher.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/modules/logger/hf/flusher.ts) - `HfLogFlusher`
26
+ - [`packages/helpers/src/modules/logger/factory.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/modules/logger/factory.ts) - `LoggerFactory`, `ApplicationLogger`
27
+
28
+ ## Architecture & ILogger
29
+
30
+ The module follows IGNIS's house format: `common/` (the contract), `base/` (provider-independent plumbing), `winston/` (the built-in provider), `hf/` (the separate high-frequency logger), and a top-level `factory.ts` as the single acquisition path.
31
+
32
+ ```
33
+ ILogger (interface) common/types.ts
34
+ └─ AbstractLogger (abstract) base/abstract.ts - the contract as a class, for `instanceof`
35
+ └─ BaseLogger (abstract) base/base.ts - scope, prefix, DEBUG gate, .for(), one write() sink
36
+ ├─ WinstonLogger winston/logger.ts - the built-in provider (default)
37
+ └─ PinoLogger pino/logger.ts - sub-path @venizia/ignis-helpers/pino
38
+ ```
39
+
40
+ - **Consumers type against `ILogger`, never a concrete class.** `LoggerFactory.getLogger()` and `BaseHelper.logger` both return `ILogger`. Which provider produced the instance stays invisible behind the interface.
41
+ - **Provider registration.** `LoggerFactory.use({ provider })` selects the application's provider (default: `WinstonLogger`). The factory hands out stable delegating wrappers and re-points ALL of them when `use()` is called - even module-level loggers captured at import time follow the registration; the per-call cost is one property read (measured ~0ns).
42
+ - **Single-provider loading.** Exactly ONE provider is ever loaded. Delegates resolve lazily at the first log call, so an app that registers pino at its entrypoint never loads winston. The winston default loads only when `use()` was never called by the first log line - it requires the winston peers installed (`bun add winston winston-transport winston-daily-rotate-file`). Compiled binaries (`bun build --compile`) must ALWAYS register a provider explicitly: only a class reference carries a provider into a bundle.
43
+ - **Both providers are sub-path only**: `WinstonLogger` at `@venizia/ignis-helpers/winston`, `PinoLogger` at `@venizia/ignis-helpers/pino` ([guide](/extensions/helpers/logger/pino)). The root barrel is provider-free; importing it loads neither.
44
+
45
+ **Which names follow `use()`:**
46
+
47
+ | Name | Is | Follows `use()`? |
48
+ |---|---|---|
49
+ | `LoggerFactory.getLogger()` / `BaseHelper.logger` | delegating wrapper | YES |
50
+ | `ApplicationLogger.get()` | facade over the factory; type = `ILogger` | YES |
51
+ | `Logger` / `Logger.get(scope, customWinston?)` | concrete `WinstonLogger` (instanceof, custom winston instances) | NO - names winston deliberately |
52
+ | `WinstonLogger` / `PinoLogger` | concrete providers | are the targets |
53
+
54
+ ## Quick Reference
55
+
56
+ | Class | Extends | Use Case |
57
+ |-------|---------|----------|
58
+ | `Logger` | `BaseLogger` -> `AbstractLogger` (`ILogger`) | General-purpose scoped logger with caching (permanent alias of `WinstonLogger`) |
59
+ | `LoggerFactory` | - | Provider registration (`use`) + `ILogger` acquisition from scope arrays |
60
+ | `PinoLogger` | `BaseLogger` (`ILogger`) | Throughput provider - NDJSON, sub-path only ([guide](/extensions/helpers/logger/pino)) |
61
+ | `HfLogger` | `AbstractLogger` (`ILogger`) | Ring-buffer logger for hot paths - bytes path ~59ns, string no-args path ~66ns |
62
+ | `HfLogFlusher` | - | Background flusher for `HfLogger` entries |
63
+ | `DgramTransport` | `winston-transport.Transport` | Custom Winston transport that sends logs over UDP |
64
+
65
+ ### Import paths
66
+
67
+ ```typescript
68
+ // Core classes - provider-neutral, root barrel
69
+ import { LoggerFactory, ApplicationLogger } from '@venizia/ignis-helpers';
70
+ import type { ILogger } from '@venizia/ignis-helpers';
71
+
72
+ // Abstract tiers - implementing ILogger yourself, or instanceof checks
73
+ import { AbstractLogger, BaseLogger } from '@venizia/ignis-helpers';
74
+
75
+ // High-frequency logger
76
+ import { HfLogger, HfLogFlusher } from '@venizia/ignis-helpers';
77
+
78
+ // Constants & types
79
+ import { LogLevels, LoggerFormats } from '@venizia/ignis-helpers';
80
+ import type { TLogLevel, TLoggerFormat } from '@venizia/ignis-helpers';
81
+
82
+ // Level resolution - provider-neutral
83
+ import { resolveLoggerLevel } from '@venizia/ignis-helpers';
84
+
85
+ // Winston provider + its utilities - SUB-PATH only (winston is an optional peer)
86
+ import {
87
+ Logger,
88
+ WinstonLogger,
89
+ defineCustomLogger,
90
+ defineLogFormatter,
91
+ defineJsonLoggerFormatter,
92
+ definePrettyLoggerFormatter,
93
+ applicationLogFormatter,
94
+ resolveDefaultTransportOptions,
95
+ } from '@venizia/ignis-helpers/winston';
96
+ import type { IFileTransportOptions, ICustomLoggerOptions } from '@venizia/ignis-helpers/winston';
97
+
98
+ // Pino provider - SUB-PATH only (optional peers: pino, pino-pretty, pino-roll)
99
+ import { PinoLogger, setPinoBackingLogger } from '@venizia/ignis-helpers/pino';
100
+ import type { ILoggerProvider } from '@venizia/ignis-helpers';
101
+
102
+ // UDP transport (winston)
103
+ import { DgramTransport } from '@venizia/ignis-helpers/winston';
104
+ import type { IDgramTransportOptions } from '@venizia/ignis-helpers/winston';
105
+ ```
106
+
107
+ The root barrel is provider-free: importing `@venizia/ignis-helpers` loads NO provider. Winston names resolve only through `@venizia/ignis-helpers/winston`, pino names only through `@venizia/ignis-helpers/pino`.
108
+
109
+ ## Creating an Instance
110
+
111
+ `Source ->` [`winston/logger.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/modules/logger/winston/logger.ts), [`factory.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/modules/logger/factory.ts)
112
+
113
+ ### Using LoggerFactory (recommended)
114
+
115
+ `LoggerFactory.getLogger` accepts an array of scope strings, joins them with `-`, and returns a cached provider-following wrapper (see the name/role table above).
116
+
117
+ ```typescript
118
+ import { LoggerFactory } from '@venizia/ignis-helpers';
119
+
120
+ const logger = LoggerFactory.getLogger(['MyService']);
121
+ logger.info('Service initialized');
122
+ // Output: [MyService] Service initialized
123
+
124
+ const scopedLogger = LoggerFactory.getLogger(['Payment', 'Stripe']);
125
+ scopedLogger.info('Charge created');
126
+ // Output: [Payment-Stripe] Charge created
127
+ ```
128
+
129
+ ### Using Logger.get() directly
130
+
131
+ ```typescript
132
+ import { Logger } from '@venizia/ignis-helpers/winston';
133
+
134
+ const logger = Logger.get('MyService');
135
+ logger.info('Direct logger access');
136
+ // Output: [MyService] Direct logger access
137
+ ```
138
+
139
+ Pass a custom Winston logger instance as the second parameter to use your own transport configuration:
140
+
141
+ ```typescript
142
+ import { Logger, defineCustomLogger, applicationLogFormatter } from '@venizia/ignis-helpers/winston';
143
+
144
+ const customWinstonLogger = defineCustomLogger({
145
+ formatter: applicationLogFormatter,
146
+ transports: {
147
+ info: { file: { prefix: 'custom', folder: './logs' } },
148
+ error: { file: { prefix: 'custom-error', folder: './logs' } },
149
+ },
150
+ });
151
+
152
+ const logger = Logger.get('MyService', customWinstonLogger);
153
+ ```
154
+
155
+ A custom-backed `Logger` is a fresh wrapper on every call - a scope-keyed cache cannot tell two different Winston instances apart, and the wrapper is cheap enough not to need one. `.for()` on a custom-backed logger keeps the same Winston instance.
156
+
157
+ ### Logger caching
158
+
159
+ Without a custom logger, both `Logger.get` and `LoggerFactory.getLogger` cache internally - the same scope always returns the same `Logger` instance:
160
+
161
+ ```typescript
162
+ const logger1 = Logger.get('MyService');
163
+ const logger2 = Logger.get('MyService');
164
+ // logger1 === logger2 (same instance)
165
+
166
+ const custom1 = Logger.get('MyService', customWinstonLogger);
167
+ const custom2 = Logger.get('MyService', customWinstonLogger);
168
+ // custom1 !== custom2 (fresh wrapper each call, same backing Winston instance)
169
+ ```
170
+
171
+ ### ApplicationLogger - the provider-following facade
172
+
173
+ `ApplicationLogger` is "the APPLICATION's logger": `ApplicationLogger.get(scope)` always returns the provider registered via `LoggerFactory.use()` (winston unless the app registered another). Its TYPE is `ILogger`. It is no longer a class alias of `WinstonLogger` - `instanceof ApplicationLogger` is now a compile error (use `instanceof AbstractLogger` to test any provider instance); the concrete alias remains available as `Logger`.
174
+
175
+ ```typescript
176
+ import { ApplicationLogger } from '@venizia/ignis-helpers';
177
+
178
+ const logger = ApplicationLogger.get('MyService'); // ILogger, follows LoggerFactory.use()
179
+ ```
180
+
181
+ The old scope-less `applicationLogger` instance was REMOVED - use `ApplicationLogger.get('YourScope')`; apps that need a raw winston instance build one with `defineCustomLogger` (sub-path `/winston`).
182
+
183
+ ## Log Levels
184
+
185
+ `Source ->` [`common/constants.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/modules/logger/common/constants.ts), [`base/base.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/modules/logger/base/base.ts), [`winston/define.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/modules/logger/winston/define.ts)
186
+
187
+ Five levels, each with a direct method on `ILogger`: `debug`, `info`, `warn`, `error`, `emerg`. The generic `log(level, ...)` remains for dynamic level selection.
188
+
189
+ ```typescript
190
+ logger.info('User created');
191
+ logger.warn('Rate limit approaching');
192
+ logger.error('Failed to process payment');
193
+ logger.emerg('System out of memory');
194
+ logger.debug('Query took 12ms'); // Requires DEBUG=true
195
+ logger.log('warn', 'Threshold exceeded'); // Generic method for any level
196
+ ```
197
+
198
+ ### What each level means
199
+
200
+ The level set follows the npm/winston convention. Lower priority number = more severe; the level floor (`APP_ENV_LOGGER_LEVEL`) admits everything at or above its severity.
201
+
202
+ | Level | Priority | Meaning | Use it for |
203
+ |-------|----------|---------|------------|
204
+ | `error` | 0 | An operation failed | Caught failures the line exists to diagnose - always pair an `Error` with `%s` |
205
+ | `emerg` | 0 | The process is in a fatal state | Out-of-memory, unrecoverable corruption, imminent shutdown |
206
+ | `warn` | 1 | Something is off but handled | Retries, fallbacks taken, deprecated usage |
207
+ | `info` | 2 | A business event happened | "Order created", lifecycle milestones, boot phases |
208
+ | `debug` | 3 | Developer diagnostics | Values and timings useful only while developing - ALSO gated by `DEBUG` env |
209
+
210
+ > [!NOTE]
211
+ > Two gates apply to `debug`, one to everything else. Every level passes the floor (`APP_ENV_LOGGER_LEVEL`, default `debug` - which admits ALL five levels); `debug()` additionally requires the `DEBUG` env gate. The vocabulary was deliberately trimmed to these five (2026-07-18): `alert`/`http`/`verbose`/`silly` had zero call sites and no consuming infrastructure - `http` returns as an access-line level if the request-correlation feature lands.
212
+
213
+ `LogLevels` defines all available levels and provides validation:
214
+
215
+ ```typescript
216
+ import { LogLevels } from '@venizia/ignis-helpers';
217
+ import type { TLogLevel } from '@venizia/ignis-helpers';
218
+
219
+ LogLevels.ERROR; // 'error'
220
+ LogLevels.EMERG; // 'emerg'
221
+ LogLevels.WARN; // 'warn'
222
+ LogLevels.INFO; // 'info'
223
+ LogLevels.DEBUG; // 'debug'
224
+
225
+ LogLevels.isValid('info'); // true
226
+ LogLevels.isValid('unknown'); // false
227
+
228
+ const level: TLogLevel = 'info';
229
+ ```
230
+
231
+ ### Winston level priority
232
+
233
+ `defineCustomLogger` configures Winston with these numeric priorities by default:
234
+
235
+ | Level | Priority | Color |
236
+ |-------|----------|-------|
237
+ | `error` | 0 | red |
238
+ | `emerg` | 0 | red |
239
+ | `warn` | 1 | yellow |
240
+ | `info` | 2 | green |
241
+ | `debug` | 3 | blue |
242
+
243
+ Lower numeric values have higher priority. `error` and `emerg` share priority `0`.
244
+
245
+ ## Method-Scoped Logging
246
+
247
+ `.for()` creates a sub-scoped logger for a specific method, appending the method name to the scope with a `-` separator, backed by the same provider instance as the parent. Default-backed results are cached.
248
+
249
+ ```typescript
250
+ class UserService {
251
+ private logger = LoggerFactory.getLogger(['UserService']);
252
+
253
+ async createUser(data: CreateUserDto) {
254
+ this.logger.for('createUser').info('Creating user: %j', data);
255
+ // Output: [UserService-createUser] Creating user: {...}
256
+
257
+ try {
258
+ const user = await this.userRepo.create({ data });
259
+ this.logger.for('createUser').info('User created: %s', user.id);
260
+ return user;
261
+ } catch (error) {
262
+ this.logger.for('createUser').error('Failed to create user: %s', error);
263
+ throw error;
264
+ }
265
+ }
266
+ }
267
+ ```
268
+
269
+ ## Message Formatting
270
+
271
+ `Source ->` [`winston/formatters/deep-splat.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/modules/logger/winston/formatters/deep-splat.ts), [`formatting/deep-splat.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/modules/logger/formatting/deep-splat.ts)
272
+
273
+ ### Logging errors: `%s`, never `%j`
274
+
275
+ - **`message` and `stack` are non-enumerable** on a native `Error`.
276
+ - **`%j` formats via `JSON.stringify`**, which only visits enumerable own properties, so `logger.error('Failed: %j', error)` silently drops both `message` and `stack` - the two fields the log line exists to capture.
277
+ - **Always pair an `Error` argument with `%s`**; reserve `%j`/`%o` for plain data objects.
278
+
279
+ ```typescript
280
+ // Good - %s prints message + stack
281
+ logger.error('Failed to create user: %s', error);
282
+
283
+ // Bad - %j drops message and stack (non-enumerable on Error)
284
+ logger.error('Failed to create user: %j', error);
285
+ ```
286
+
287
+ ### Object inspection depth for `%s`
288
+
289
+ - **Node hard-codes `depth: 0` for `%s`** in `util.format` - an object passed to `%s` collapses to `[Object]`, hiding the nested `extra` or `cause` a wrapped error carries.
290
+ - **`deepSplat` widens that depth.** The formatter (`formatLogMessage`) pre-inspects any object bound to a `%s` placeholder before handing the message to Winston, so nested fields print instead of collapsing.
291
+ - **Applies per-placeholder.** Only arguments matched to a `%s` token are affected, so `%j` still gets `JSON.stringify` semantics.
292
+
293
+ ```typescript
294
+ logger.error('Failed: %s', error); // nested `error.cause` is now visible, not `[Object]`
295
+ ```
296
+
297
+ The inspection depth defaults to `5` and is configurable via `APP_ENV_LOGGER_INSPECT_DEPTH`:
298
+
299
+ ```bash
300
+ APP_ENV_LOGGER_INSPECT_DEPTH=8
301
+ ```
302
+
303
+ The value must be a non-negative integer. An absent, empty, negative, or unparseable value falls back to the default of `5` - there is no "unlimited" setting.
304
+
305
+ ### Log formats
306
+
307
+ Output format is controlled by `APP_ENV_LOGGER_FORMAT` (default: `text`). `LoggerFormats` provides constants and validation:
308
+
309
+ ```typescript
310
+ import { LoggerFormats } from '@venizia/ignis-helpers';
311
+ import type { TLoggerFormat } from '@venizia/ignis-helpers';
312
+
313
+ LoggerFormats.JSON; // 'json'
314
+ LoggerFormats.TEXT; // 'text'
315
+ LoggerFormats.isValid('json'); // true
316
+
317
+ const fmt: TLoggerFormat = 'text';
318
+ ```
319
+
320
+ **JSON format** (`APP_ENV_LOGGER_FORMAT=json`):
321
+
322
+ ```json
323
+ {"level":"info","message":"[UserService] User created","timestamp":"2024-01-11T10:30:00.000Z","label":"APP"}
324
+ ```
325
+
326
+ **Pretty text format** (`APP_ENV_LOGGER_FORMAT=text`, default):
327
+
328
+ ```
329
+ 2024-01-11T10:30:00.000Z [APP] info: [UserService] User created
330
+ ```
331
+
332
+ > [!NOTE]
333
+ > The label shown in log output (e.g. `APP`) comes from `APP_ENV_APPLICATION_NAME` (defaults to `'APP'`). Set this env var to customize the label for your application.
334
+
335
+ ### Custom formatters
336
+
337
+ Build formatters directly using the exported helper functions:
338
+
339
+ ```typescript
340
+ import {
341
+ defineLogFormatter,
342
+ defineJsonLoggerFormatter,
343
+ definePrettyLoggerFormatter,
344
+ } from '@venizia/ignis-helpers';
345
+
346
+ // Auto-detect from APP_ENV_LOGGER_FORMAT (or override with format option)
347
+ const formatter = defineLogFormatter({ label: 'my-app' });
348
+ const jsonFmt = defineLogFormatter({ label: 'my-app', format: 'json' });
349
+
350
+ // Or use specific formatters directly
351
+ const jsonFormatter = defineJsonLoggerFormatter({ label: 'my-app' });
352
+ const prettyFormatter = definePrettyLoggerFormatter({ label: 'my-app' });
353
+ const plainFormatter = definePrettyLoggerFormatter({ label: 'my-app', colorize: false });
354
+ ```
355
+
356
+ `defineLogFormatter` throws an `ApplicationError` if `format` (or `APP_ENV_LOGGER_FORMAT`) is not `'json'` or `'text'`.
357
+
358
+ ## Transports
359
+
360
+ `Source ->` [`winston/define.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/modules/logger/winston/define.ts)
361
+
362
+ Every logger created by `defineCustomLogger` always includes a **Console** transport, which inherits the logger-level floor (`APP_ENV_LOGGER_LEVEL`, default `debug`). File and UDP transports are optional and are registered per transport group (`info`, `error`).
363
+
364
+ Formatting is split in two stages: a shared preparation format on the logger (label, timestamp, error normalization, deep splat) and a per-transport assembly format. In `text` mode the console assembly colorizes while the file assembly does not - log FILES never contain ANSI color codes. In `json` mode every transport assembles with plain `format.json()`. Passing `formatter` disables the split: that one format produces the final line for every transport.
365
+
366
+ ### File rotation (DailyRotateFile)
367
+
368
+ Configure file rotation through environment variables or programmatically via `IFileTransportOptions`.
369
+
370
+ **Environment variables:**
371
+
372
+ | Variable | Default | Description |
373
+ |----------|---------|-------------|
374
+ | `APP_ENV_LOGGER_FOLDER_PATH` | _(unset)_ | Log files directory; file logging is OFF when unset |
375
+ | `APP_ENV_LOGGER_FILE_FREQUENCY` | `1h` | Rotation frequency |
376
+ | `APP_ENV_LOGGER_FILE_MAX_SIZE` | `100m` | Max file size before rotation |
377
+ | `APP_ENV_LOGGER_FILE_MAX_FILES` | `5d` | Retention period |
378
+ | `APP_ENV_LOGGER_FILE_DATE_PATTERN` | `YYYYMMDD_HH` | Date pattern in filename |
379
+
380
+ **Programmatic configuration:**
381
+
382
+ ```typescript
383
+ import { defineCustomLogger, applicationLogFormatter } from '@venizia/ignis-helpers/winston';
384
+
385
+ const customLogger = defineCustomLogger({
386
+ formatter: applicationLogFormatter,
387
+ transports: {
388
+ info: {
389
+ file: {
390
+ prefix: 'my-app',
391
+ folder: './logs',
392
+ frequency: '24h',
393
+ maxSize: '500m',
394
+ maxFiles: '30d',
395
+ datePattern: 'YYYYMMDD',
396
+ },
397
+ },
398
+ error: {
399
+ file: {
400
+ prefix: 'my-app-error',
401
+ folder: './logs',
402
+ maxFiles: '90d',
403
+ },
404
+ },
405
+ },
406
+ });
407
+ ```
408
+
409
+ Generated filename pattern: `{folder}/{prefix}-info-{DATE}.log` or `{folder}/{prefix}-error-{DATE}.log`. An `error`-level file transport is also registered as a Winston exception handler.
410
+
411
+ #### IFileTransportOptions
412
+
413
+ ```typescript
414
+ interface IFileTransportOptions {
415
+ prefix: string; // Filename prefix (required)
416
+ folder: string; // Output directory (required)
417
+ frequency?: string; // Rotation frequency (default: '1h')
418
+ maxSize?: string; // Max file size (default: '100m')
419
+ maxFiles?: string; // Retention period (default: '5d')
420
+ datePattern?: string; // Date pattern in filename (default: 'YYYYMMDD_HH')
421
+ }
422
+ ```
423
+
424
+ ### UDP transport (DgramTransport)
425
+
426
+ `Source ->` [`winston/transports/dgram.transport.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/modules/logger/winston/transports/dgram.transport.ts)
427
+
428
+ `DgramTransport` is a custom Winston transport that sends log entries over UDP. It filters by level - only messages whose level is in the configured `levels` set are forwarded.
429
+
430
+ ```typescript
431
+ import { DgramTransport } from '@venizia/ignis-helpers/winston';
432
+
433
+ const transport = new DgramTransport({
434
+ label: 'my-app',
435
+ host: '127.0.0.1',
436
+ port: 5000,
437
+ levels: ['error', 'warn', 'info'],
438
+ socketOptions: { type: 'udp4' },
439
+ });
440
+ ```
441
+
442
+ **Static factory with validation** - `fromPartial` returns `null` if any required field is missing, rather than throwing:
443
+
444
+ ```typescript
445
+ const transport = DgramTransport.fromPartial({
446
+ label: 'my-app',
447
+ host: '127.0.0.1',
448
+ port: 5000,
449
+ levels: ['error', 'warn'],
450
+ socketOptions: { type: 'udp4' },
451
+ });
452
+ // Returns null if label, host, port, levels (non-empty), or socketOptions is missing
453
+ ```
454
+
455
+ On a socket error the transport closes and nulls its client; the next `log()` call re-establishes the socket before sending. A failed `send` is logged to the console and the socket is dropped for reconnection - it is never re-emitted as an `'error'` event, so one lost UDP log line can never crash the process.
456
+
457
+ **Environment variables for the default application logger:**
458
+
459
+ | Variable | Description |
460
+ |----------|-------------|
461
+ | `APP_ENV_LOGGER_DGRAM_HOST` | UDP log aggregator host |
462
+ | `APP_ENV_LOGGER_DGRAM_PORT` | UDP log aggregator port |
463
+ | `APP_ENV_LOGGER_DGRAM_LABEL` | Label to identify log source |
464
+ | `APP_ENV_LOGGER_DGRAM_LEVELS` | Comma-separated levels to send via UDP |
465
+
466
+ #### IDgramTransportOptions
467
+
468
+ ```typescript
469
+ interface IDgramTransportOptions extends Transport.TransportStreamOptions {
470
+ label: string; // Label to identify log source
471
+ host: string; // UDP host
472
+ port: number; // UDP port
473
+ levels: Array<string>; // Levels to forward over UDP
474
+ socketOptions: dgram.SocketOptions; // Node.js dgram socket options
475
+ }
476
+ ```
477
+
478
+ ### ICustomLoggerOptions
479
+
480
+ ```typescript
481
+ interface ICustomLoggerOptions {
482
+ levels?: { [name: string | symbol]: number };
483
+ colors?: { [name: string | symbol]: string };
484
+ // Full override: applied once for every transport, exactly as it produces the line
485
+ formatter?: ReturnType<typeof winston.format.combine>;
486
+ format?: TLoggerFormat; // 'json' | 'text'; defaults to APP_ENV_LOGGER_FORMAT
487
+ level?: TLogLevel; // logger-level floor; defaults to APP_ENV_LOGGER_LEVEL, then 'debug'
488
+ transports: {
489
+ info: {
490
+ file?: IFileTransportOptions;
491
+ dgram?: Partial<IDgramTransportOptions>;
492
+ };
493
+ error: {
494
+ file?: IFileTransportOptions;
495
+ dgram?: Partial<IDgramTransportOptions>;
496
+ };
497
+ };
498
+ }
499
+ ```
500
+
501
+ - **Both `info` and `error` transport groups support optional `file` (DailyRotateFile) and `dgram` (UDP) transports.**
502
+ - **A console transport is always included**, regardless of what is configured.
503
+ - **Error file transports double as Winston exception handlers.**
504
+
505
+ ## Debug Logging Behavior
506
+
507
+ `Source ->` [`base/base.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/modules/logger/base/base.ts)
508
+
509
+ Debug logs require **both** conditions to be met:
510
+
511
+ 1. `DEBUG=true` environment variable is set (parsed via `toBoolean`)
512
+ 2. `NODE_ENV` is either unset **or** is present in the `Environment.COMMON_ENVS` set
513
+
514
+ `COMMON_ENVS` includes: `local`, `debug`, `development`, `dev`, `sit`, `uat`, `alpha`, `beta`, `staging`, `production`. Extend this set with `APP_ENV_EXTRA_LOG_ENVS`:
515
+
516
+ ```bash
517
+ DEBUG=true
518
+ NODE_ENV=development
519
+ APP_ENV_EXTRA_LOG_ENVS=qa,preview # Comma-separated additional environments
520
+ ```
521
+
522
+ > [!IMPORTANT]
523
+ > The debug flag check is pre-computed at module load time. Changing `DEBUG` or `NODE_ENV` at runtime has no effect - the values are captured once when the module is first imported.
524
+
525
+ ## High-Frequency Logger (HfLogger)
526
+
527
+ `Source ->` [`hf/logger.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/modules/logger/hf/logger.ts), [`hf/flusher.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/modules/logger/hf/flusher.ts)
528
+
529
+ For performance-critical applications (e.g. HFT systems, game servers), `HfLogger` provides ring-buffer logging with a 59.4ns bytes-path enqueue and a 66.0ns string no-args enqueue (Bun 1.3.14, 1M-iteration median). It extends `AbstractLogger` and implements `ILogger`, so it can be used anywhere an `ILogger` is expected - but it is still entirely separate from the Winston-backed `Logger` pipeline: no formatters, transports, or `APP_ENV_LOGGER_*` env vars apply to it. Read the [HfLogger guide](/extensions/helpers/logger/hf-logger) before using it - it carries hard usage rules (pre-encoded fixed message vocabulary, single-thread only, flush-interval sizing) and documented limitations.
530
+
531
+ ```typescript
532
+ import { HfLogger, HfLogFlusher } from '@venizia/ignis-helpers';
533
+
534
+ // At initialization time (once):
535
+ const logger = HfLogger.get('OrderEngine');
536
+ const MSG_ORDER_SENT = HfLogger.encodeMessage('Order sent');
537
+ const MSG_ORDER_FILLED = HfLogger.encodeMessage('Order filled');
538
+
539
+ // Start background flusher
540
+ const flusher = new HfLogFlusher();
541
+ flusher.start(100); // Flush every 100ms
542
+
543
+ // In hot path (bytes path, ~59ns, no allocation):
544
+ logger.log('info', MSG_ORDER_SENT);
545
+ logger.log('info', MSG_ORDER_FILLED);
546
+
547
+ // ILogger surface also works (string no-args path, ~66ns on a cache hit):
548
+ logger.info('Order sent');
549
+
550
+ // Shutdown:
551
+ await flusher.flush();
552
+ flusher.stop();
553
+ ```
554
+
555
+ ### HfLogger API
556
+
557
+ `HfLogger` implements the full `ILogger` contract plus its own static/bytes surface:
558
+
559
+ | Method | Signature | Description |
560
+ |--------|-----------|--------------|
561
+ | `HfLogger.get` | `(scope: string) => HfLogger` | Get or create a cached logger instance (allocates the ring lazily on first call) |
562
+ | `HfLogger.encodeMessage` | `(msg: string) => Uint8Array` | Pre-encode a message string to bytes; FIFO-bounded cache, cap `MESSAGE_CACHE_CAP = 4096` |
563
+ | `logger.debug/info/warn/error/emerg` | `(message: string, ...args: AnyType[]) => void` | `ILogger` methods. No args: cache-lookup encode + bytes-path write. With args: `formatLogMessage` (deep inspection + redaction) then an uncached encode - the slow path |
564
+ | `logger.log` | `(level: TLogLevel, message: string, ...args: AnyType[]) => void`<br>`(level: TLogLevel, messageBytes: Uint8Array) => void` | Overloaded: string form follows the `debug`/`info`/... cost model above; `Uint8Array` form is the legacy bytes hot path, unchanged signature |
565
+ | `logger.for` | `(methodName: string) => ILogger` | Returns `HfLogger.get(`${scope}-${methodName}`)`, same dash composition as `BaseLogger` |
566
+
567
+ Supported levels (`TLogLevel`, full set): `debug` (0), `info` (1), `warn` (2), `error` (3), `emerg` (4).
568
+
569
+ ### HfLogFlusher API
570
+
571
+ | Method | Signature | Description |
572
+ |--------|-----------|--------------|
573
+ | `new HfLogFlusher` | `(options?: IHfLogFlusherOptions) => HfLogFlusher` | `sink?: THfSink` (full custom delivery), `filePath?: string` (default sink appends here instead of stdout), `batchSize?: number` (entries rendered per batch before yielding, default `1024`; invalid values fall back with a `console.warn`) |
574
+ | `flusher.flush` | `() => Promise<void>` | Drain the full backlog in bounded batches, yielding (`setImmediate`) between batches; re-entrant calls return the in-progress promise |
575
+ | `flusher.start` | `(intervalMs?: number) => void` | Start a background `setInterval` flush loop (default `100`ms), unref'd so it never blocks process exit; idempotent - calling again restarts cleanly |
576
+ | `flusher.stop` | `() => void` | Clear the interval started by `start()` |
577
+
578
+ `THfSinkBatch` passed to a custom `sink`: `{ lines: Array<string>; dropped: number }` - `dropped` is the exact count of entries overwritten by the ring before the flusher could read them since the previous batch (see "Lap accounting" in the guide). The default sink (no `filePath`) writes `process.stdout.write(...)` once per batch; with `filePath`, it appends via `fs.appendFileSync` once per batch. A sink that throws is logged via `console.error` and does not abort the drain.
579
+
580
+ ### Line format
581
+
582
+ The default sink renders each entry as:
583
+
584
+ ```
585
+ <ISO timestamp> [<level name>] <scope> <message>
586
+ ```
587
+
588
+ For example: `2026-07-18T09:41:03.128Z [info] OrderEngine Order sent`. When a batch has `dropped > 0`, the default sink emits a `warn` marker line ahead of it: `<ISO timestamp> [warn] HfLogFlusher ring lapped - <N> entries overwritten before they could be read`.
589
+
590
+ ### Ring buffer entry format
591
+
592
+ Each entry occupies exactly 256 bytes in a 64K-entry (16MB) `ArrayBuffer`, allocated lazily on the first `HfLogger.get()` call (not at module import) and shared module-wide (not per-`HfLogger` instance):
593
+
594
+ | Offset | Size | Field |
595
+ |--------|------|-------|
596
+ | 0-7 | 8 bytes | Timestamp (`float64` epoch milliseconds, sub-millisecond precision) |
597
+ | 8 | 1 byte | Level (`0`=debug, `1`=info, `2`=warn, `3`=error, `4`=emerg) |
598
+ | 9 | 1 byte | Scope length (0-32) |
599
+ | 10-41 | 32 bytes | Scope bytes |
600
+ | 42 | 1 byte | Message length (0-213) |
601
+ | 43-255 | 213 bytes | Message bytes |
602
+
603
+ The explicit length bytes are what make reads exact: the flusher decodes only the bytes a field actually holds, so there is no NUL padding and no stale tail from a previous, longer entry in a reused slot. The buffer wraps around at 65,536 entries using bitwise AND masking (`writeIndex & (BUFFER_SIZE - 1)`); when the producer writes faster than the flusher drains, unflushed entries are overwritten, and the overwritten count is reported via `dropped` on the next sink batch rather than silently emitted.
604
+
605
+ > [!WARNING]
606
+ > Pre-encode messages at initialization time using `HfLogger.encodeMessage()` or by calling a no-args `ILogger` method once per distinct message. Calling either with dynamic, per-event strings puts UTF-8 encoding on the hot path and can evict other cached messages once the FIFO-bounded cache (4096 entries) fills.
607
+
608
+ ## Environment Variables
609
+
610
+ ### Core configuration
611
+
612
+ | Variable | Default | Description |
613
+ |----------|---------|-------------|
614
+ | `APP_ENV_APPLICATION_NAME` | `APP` | Label prefix shown in all log output |
615
+ | `DEBUG` | `false` | Enable debug-level logging |
616
+ | `NODE_ENV` | _(unset)_ | Must be in `COMMON_ENVS` or unset for debug to activate |
617
+ | `APP_ENV_EXTRA_LOG_ENVS` | _(empty)_ | Comma-separated additional environments to allow debug |
618
+ | `APP_ENV_LOGGER_FORMAT` | `text` | Output format (`json` or `text`) |
619
+ | `APP_ENV_LOGGER_LEVEL` | `debug` | Logger-level floor; transports without their own level inherit it. Invalid values fall back to `debug` with a console warning |
620
+ | `APP_ENV_LOGGER_FOLDER_PATH` | _(unset)_ | Log files directory; file logging is OFF when unset |
621
+ | `APP_ENV_LOGGER_INSPECT_DEPTH` | `5` | Object inspection depth for `%s` placeholders. Non-negative integer only; invalid or absent falls back to `5` |
622
+ | `APP_ENV_LOGGER_DO_REDACT` | `true` | Secret redaction in log arguments. ONLY the literal `false` disables it - raw values (passwords, tokens, connection URLs) then reach the sinks. Any other value, unset included, keeps redaction ON. Never disable in production |
623
+
624
+ ### File rotation
625
+
626
+ | Variable | Default | Description |
627
+ |----------|---------|-------------|
628
+ | `APP_ENV_LOGGER_FILE_FREQUENCY` | `1h` | Rotation frequency |
629
+ | `APP_ENV_LOGGER_FILE_MAX_SIZE` | `100m` | Max file size before rotation |
630
+ | `APP_ENV_LOGGER_FILE_MAX_FILES` | `5d` | Retention period |
631
+ | `APP_ENV_LOGGER_FILE_DATE_PATTERN` | `YYYYMMDD_HH` | Date pattern in filename |
632
+
633
+ ### UDP transport
634
+
635
+ | Variable | Description |
636
+ |----------|-------------|
637
+ | `APP_ENV_LOGGER_DGRAM_HOST` | UDP log aggregator host |
638
+ | `APP_ENV_LOGGER_DGRAM_PORT` | UDP log aggregator port |
639
+ | `APP_ENV_LOGGER_DGRAM_LABEL` | Label to identify log source |
640
+ | `APP_ENV_LOGGER_DGRAM_LEVELS` | Comma-separated levels to send via UDP |
641
+
642
+ ### Example `.env`
643
+
644
+ ```bash
645
+ # Application
646
+ APP_ENV_APPLICATION_NAME=my-service
647
+
648
+ # Core
649
+ DEBUG=true
650
+ APP_ENV_LOGGER_FORMAT=json
651
+ APP_ENV_LOGGER_FOLDER_PATH=./app_data/logs
652
+ APP_ENV_LOGGER_INSPECT_DEPTH=5
653
+
654
+ # File rotation
655
+ APP_ENV_LOGGER_FILE_FREQUENCY=24h
656
+ APP_ENV_LOGGER_FILE_MAX_SIZE=500m
657
+ APP_ENV_LOGGER_FILE_MAX_FILES=30d
658
+
659
+ # UDP transport
660
+ APP_ENV_LOGGER_DGRAM_HOST=127.0.0.1
661
+ APP_ENV_LOGGER_DGRAM_PORT=5000
662
+ APP_ENV_LOGGER_DGRAM_LABEL=my-app
663
+ APP_ENV_LOGGER_DGRAM_LEVELS=error,warn,info
664
+ ```
665
+
666
+ ## API Summary
667
+
668
+ | Export | Kind | Description |
669
+ |--------|------|-------------|
670
+ | `ILogger` | interface | The logging contract every consumer types against - one direct method per level (`debug`, `info`, `warn`, `error`, `emerg`), plus `log` and `for` |
671
+ | `AbstractLogger` | abstract class | `ILogger` as a class - the `instanceof` check that works for EVERY provider |
672
+ | `BaseLogger` | abstract class | Provider-independent plumbing shared by every implementation: scope, prefix, the `DEBUG` gate, `.for()`, one abstract `write()` sink |
673
+ | `WinstonLogger` | class | The Winston-backed provider (the default); `Logger` is its permanent concrete alias |
674
+ | `Logger` | class | Concrete winston alias - `Logger.get(scope, customWinstonLogger?)`, `instanceof Logger`; deliberately does NOT follow `use()` |
675
+ | `PinoLogger` | class (sub-path `/pino`) | The throughput provider - register with `LoggerFactory.use` ([guide](/extensions/helpers/logger/pino)) |
676
+ | `ApplicationLogger` | const facade + type (`ILogger`) | `ApplicationLogger.get(scope)` always returns the REGISTERED provider's logger |
677
+ | `LoggerFactory` | class | Provider registration (`use({ provider })`) + `ILogger` acquisition from scope arrays |
678
+ | `ILoggerProvider` | interface | Static-side contract a provider class satisfies (`get(scope): ILogger`) |
679
+ | `HfLogger` | class | `ILogger`-conformant ring-buffer logger for hot paths |
680
+ | `HfLogFlusher` | class | Background flusher for `HfLogger` |
681
+ | `LogLevels` | class (constants) | Log level constants (`ERROR`, `EMERG`, `WARN`, `INFO`, `DEBUG`) with `isValid()` |
682
+ | `LoggerFormats` | class (constants) | Format constants (`JSON`, `TEXT`) with `isValid()` |
683
+ | `defineCustomLogger` | `(opts: ICustomLoggerOptions) => winston.Logger` | Create a fully configured Winston logger |
684
+ | `defineLogFormatter` | `(opts: { label: string; format?: TLoggerFormat }) => winston.Logform.Format` | Create a formatter (auto-detects format from env) |
685
+ | `defineJsonLoggerFormatter` | `(opts: { label: string }) => winston.Logform.Format` | Create a JSON formatter |
686
+ | `definePrettyLoggerFormatter` | `(opts: { label: string; colorize?: boolean }) => winston.Logform.Format` | Create a pretty text formatter; `colorize: false` for files/aggregators |
687
+ | `applicationLogFormatter` | `winston.Logform.Format` | Pre-built formatter using `APP_ENV_APPLICATION_NAME` label |
688
+ | `resolveLoggerLevel` | `(opts: { configured?: string }) => TLogLevel` | Validate a level string; invalid or absent falls back to `debug` |
689
+ | `resolveDefaultTransportOptions` | `() => ICustomLoggerOptions['transports']` | Default transports from `APP_ENV_LOGGER_*`, resolved at call time |
690
+ | `DgramTransport` | class | Custom Winston transport for UDP logging |
691
+ | `TLogLevel` | type | Union of all log level string literals |
692
+ | `TLoggerFormat` | type | Union of `'json' \| 'text'` |
693
+ | `IFileTransportOptions` | interface | Options for daily-rotating file transport |
694
+ | `ICustomLoggerOptions` | interface | Options for `defineCustomLogger` |
695
+ | `IDgramTransportOptions` | interface | Options for `DgramTransport` |
696
+
697
+ ## Troubleshooting
698
+
699
+ ### Debug logs not appearing
700
+
701
+ **Cause:** Debug logging requires both `DEBUG=true` AND a `NODE_ENV` that is either unset or present in the `COMMON_ENVS` set. These values are pre-computed at module load time.
702
+
703
+ **Fix:**
704
+ 1. Verify `DEBUG=true` is set in your environment.
705
+ 2. Verify `NODE_ENV` is set to one of: `local`, `debug`, `development`, `dev`, `sit`, `uat`, `alpha`, `beta`, `staging`, `production` - or is unset entirely.
706
+ 3. If you use a custom environment name (e.g. `qa`), add it to `APP_ENV_EXTRA_LOG_ENVS=qa`.
707
+
708
+ ```bash
709
+ DEBUG=true NODE_ENV=development bun run server:dev
710
+ ```
711
+
712
+ ### "[defineLogger] Invalid logger format | format: {format} | valids: json,text"
713
+
714
+ **Cause:** The `format` option passed to `defineLogFormatter` (or the `APP_ENV_LOGGER_FORMAT` environment variable) is not `json` or `text`.
715
+
716
+ **Fix:** Set `APP_ENV_LOGGER_FORMAT` to either `json` or `text`:
717
+
718
+ ```bash
719
+ APP_ENV_LOGGER_FORMAT=text
720
+ ```
721
+
722
+ ### UDP transport not sending logs
723
+
724
+ **Cause:** `DgramTransport.fromPartial()` returns `null` if any required option is missing (`label`, `host`, `port`, `levels` with at least one entry, or `socketOptions`). The transport is silently not registered.
725
+
726
+ **Fix:**
727
+ 1. Ensure **all four** dgram env vars are set: `APP_ENV_LOGGER_DGRAM_HOST`, `APP_ENV_LOGGER_DGRAM_PORT`, `APP_ENV_LOGGER_DGRAM_LABEL`, and `APP_ENV_LOGGER_DGRAM_LEVELS`.
728
+ 2. `APP_ENV_LOGGER_DGRAM_LEVELS` must contain at least one level (e.g. `error,warn,info`). An empty value results in no transport.
729
+ 3. Verify the UDP aggregator is reachable from your host (firewall, port binding).
730
+
731
+ ### Log label shows "APP" instead of application name
732
+
733
+ **Cause:** The default label comes from `Defaults.APPLICATION_NAME`, which reads `APP_ENV_APPLICATION_NAME`. If the env var is not set, it falls back to `'APP'`.
734
+
735
+ **Fix:** Set `APP_ENV_APPLICATION_NAME` in your environment:
736
+
737
+ ```bash
738
+ APP_ENV_APPLICATION_NAME=my-service
739
+ ```
740
+
741
+ ## See also
742
+
743
+ - [Logger overview](/extensions/helpers/logger/) - introduction and the most common tasks
744
+ - [Request Tracker Component](/extensions/components/request-tracker) - request logging
745
+ - [Winston documentation](https://github.com/winstonjs/winston) - underlying logging library
746
+ - [winston-daily-rotate-file](https://github.com/winstonjs/winston-daily-rotate-file) - file rotation transport