@venizia/ignis-docs 0.2.0 → 0.2.1-1

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 (174) 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 +24 -13
  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 +27 -3
  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 +8 -4
  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 +247 -153
  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 +109 -323
  26. package/content/extensions/components/authentication/api.md +489 -602
  27. package/content/extensions/components/authentication/errors.md +135 -498
  28. package/content/extensions/components/authentication/index.md +89 -801
  29. package/content/extensions/components/authentication/usage.md +231 -955
  30. package/content/extensions/components/authorization/api.md +991 -644
  31. package/content/extensions/components/authorization/errors.md +204 -208
  32. package/content/extensions/components/authorization/getting-started.md +227 -0
  33. package/content/extensions/components/authorization/index.md +88 -795
  34. package/content/extensions/components/authorization/usage.md +219 -528
  35. package/content/extensions/components/health-check.md +77 -243
  36. package/content/extensions/components/index.md +24 -90
  37. package/content/extensions/components/mail/api.md +553 -285
  38. package/content/extensions/components/mail/errors.md +76 -62
  39. package/content/extensions/components/mail/index.md +111 -463
  40. package/content/extensions/components/mail/usage.md +139 -173
  41. package/content/extensions/components/request-tracker.md +70 -173
  42. package/content/extensions/components/socket-io/api.md +462 -785
  43. package/content/extensions/components/socket-io/errors.md +49 -51
  44. package/content/extensions/components/socket-io/index.md +69 -372
  45. package/content/extensions/components/socket-io/usage.md +212 -105
  46. package/content/extensions/components/static-asset/api.md +461 -141
  47. package/content/extensions/components/static-asset/errors.md +121 -53
  48. package/content/extensions/components/static-asset/index.md +84 -606
  49. package/content/extensions/components/static-asset/usage.md +184 -299
  50. package/content/extensions/components/template/index.md +3 -3
  51. package/content/extensions/components/websocket/api.md +311 -404
  52. package/content/extensions/components/websocket/errors.md +47 -56
  53. package/content/extensions/components/websocket/index.md +75 -407
  54. package/content/extensions/components/websocket/usage.md +120 -338
  55. package/content/extensions/helpers/cron/index.md +52 -160
  56. package/content/extensions/helpers/crypto/index.md +67 -480
  57. package/content/extensions/helpers/crypto/reference.md +528 -0
  58. package/content/extensions/helpers/env/index.md +64 -178
  59. package/content/extensions/helpers/error/index.md +286 -196
  60. package/content/extensions/helpers/index.md +61 -47
  61. package/content/extensions/helpers/inversion/index.md +76 -550
  62. package/content/extensions/helpers/inversion/reference.md +530 -0
  63. package/content/extensions/helpers/kafka/admin.md +23 -3
  64. package/content/extensions/helpers/kafka/compile-binary.md +83 -52
  65. package/content/extensions/helpers/kafka/consumer.md +65 -28
  66. package/content/extensions/helpers/kafka/examples.md +46 -253
  67. package/content/extensions/helpers/kafka/index.md +55 -617
  68. package/content/extensions/helpers/kafka/producer.md +156 -22
  69. package/content/extensions/helpers/kafka/schema-registry.md +59 -79
  70. package/content/extensions/helpers/logger/hf-logger.md +220 -0
  71. package/content/extensions/helpers/logger/index.md +78 -552
  72. package/content/extensions/helpers/logger/pino.md +105 -0
  73. package/content/extensions/helpers/logger/reference.md +937 -0
  74. package/content/extensions/helpers/network/api.md +276 -195
  75. package/content/extensions/helpers/network/index.md +87 -524
  76. package/content/extensions/helpers/queue/index.md +80 -897
  77. package/content/extensions/helpers/queue/reference.md +494 -0
  78. package/content/extensions/helpers/redis/index.md +86 -640
  79. package/content/extensions/helpers/redis/reference.md +784 -0
  80. package/content/extensions/helpers/secrets/index.md +136 -0
  81. package/content/extensions/helpers/socket-io/api.md +325 -204
  82. package/content/extensions/helpers/socket-io/index.md +79 -429
  83. package/content/extensions/helpers/storage/api.md +584 -464
  84. package/content/extensions/helpers/storage/index.md +80 -573
  85. package/content/extensions/helpers/types/index.md +75 -495
  86. package/content/extensions/helpers/types/reference.md +689 -0
  87. package/content/extensions/helpers/uid/index.md +176 -189
  88. package/content/extensions/helpers/websocket/api.md +366 -214
  89. package/content/extensions/helpers/websocket/index.md +68 -503
  90. package/content/extensions/helpers/worker-thread/index.md +62 -396
  91. package/content/extensions/helpers/worker-thread/reference.md +428 -0
  92. package/content/extensions/index.md +38 -39
  93. package/content/extensions/src-details/mcp-server.md +96 -548
  94. package/content/guides/core-concepts/persistent/datasources.md +2 -2
  95. package/content/guides/core-concepts/persistent/index.md +5 -1
  96. package/content/guides/core-concepts/persistent/models.md +1 -1
  97. package/content/guides/core-concepts/persistent/pglite.md +218 -0
  98. package/content/guides/core-concepts/persistent/postgres-drivers.md +21 -15
  99. package/content/guides/core-concepts/persistent/search-meilisearch.md +22 -12
  100. package/content/guides/core-concepts/persistent/search-typesense.md +28 -16
  101. package/content/guides/core-concepts/persistent/sqlite.md +296 -0
  102. package/content/guides/core-concepts/persistent/transactions.md +12 -11
  103. package/content/guides/core-concepts/secrets-vault.md +177 -0
  104. package/content/guides/core-concepts/services.md +1 -1
  105. package/content/guides/get-started/5-minute-quickstart.md +59 -206
  106. package/content/guides/get-started/philosophy.md +135 -670
  107. package/content/guides/get-started/setup.md +53 -74
  108. package/content/guides/migrations/redis-helpers-migration.md +5 -4
  109. package/content/guides/migrations/scoped-rbac-migration.md +5 -5
  110. package/content/guides/migrations/unified-connectors-migration.md +8 -7
  111. package/content/guides/tutorials/ecommerce-api.md +3 -8
  112. package/content/guides/tutorials/realtime-chat.md +1 -1
  113. package/content/references/base/application.md +64 -22
  114. package/content/references/base/components.md +3 -3
  115. package/content/references/base/connectors.md +79 -136
  116. package/content/references/base/controllers.md +12 -12
  117. package/content/references/base/datasources-reference.md +600 -0
  118. package/content/references/base/datasources.md +84 -444
  119. package/content/references/base/dependency-injection.md +25 -46
  120. package/content/references/base/filter-system/application-usage.md +95 -123
  121. package/content/references/base/filter-system/array-operators.md +33 -43
  122. package/content/references/base/filter-system/comparison-operators.md +55 -63
  123. package/content/references/base/filter-system/default-filter.md +144 -350
  124. package/content/references/base/filter-system/fields-order-pagination.md +116 -148
  125. package/content/references/base/filter-system/index.md +114 -253
  126. package/content/references/base/filter-system/json-filtering.md +52 -181
  127. package/content/references/base/filter-system/list-operators.md +28 -44
  128. package/content/references/base/filter-system/logical-operators.md +69 -114
  129. package/content/references/base/filter-system/null-operators.md +41 -98
  130. package/content/references/base/filter-system/pattern-matching.md +48 -51
  131. package/content/references/base/filter-system/quick-reference.md +93 -196
  132. package/content/references/base/filter-system/range-operators.md +22 -38
  133. package/content/references/base/filter-system/tips.md +70 -133
  134. package/content/references/base/filter-system/use-cases.md +173 -232
  135. package/content/references/base/grpc-controllers.md +53 -17
  136. package/content/references/base/index.md +5 -3
  137. package/content/references/base/middlewares.md +43 -28
  138. package/content/references/base/models-reference.md +886 -0
  139. package/content/references/base/models.md +81 -1452
  140. package/content/references/base/providers.md +8 -8
  141. package/content/references/base/repositories/advanced.md +281 -419
  142. package/content/references/base/repositories/index.md +84 -644
  143. package/content/references/base/repositories/mixins.md +25 -21
  144. package/content/references/base/repositories/relations.md +194 -375
  145. package/content/references/base/repositories/soft-deletable.md +67 -55
  146. package/content/references/base/secrets.md +267 -0
  147. package/content/references/base/services.md +8 -6
  148. package/content/references/configuration/environment-variables.md +73 -21
  149. package/content/references/configuration/index.md +51 -31
  150. package/content/references/index.md +1 -1
  151. package/content/references/quick-reference.md +3 -16
  152. package/content/references/utilities/crypto.md +35 -76
  153. package/content/references/utilities/date.md +33 -73
  154. package/content/references/utilities/duration.md +85 -0
  155. package/content/references/utilities/index.md +6 -2
  156. package/content/references/utilities/jsx-reference.md +298 -0
  157. package/content/references/utilities/jsx.md +82 -525
  158. package/content/references/utilities/module.md +81 -61
  159. package/content/references/utilities/parse.md +34 -64
  160. package/content/references/utilities/performance.md +33 -58
  161. package/content/references/utilities/promise.md +28 -62
  162. package/content/references/utilities/request.md +58 -218
  163. package/content/references/utilities/retry.md +139 -0
  164. package/content/references/utilities/schema.md +43 -137
  165. package/content/references/utilities/statuses-reference.md +361 -0
  166. package/content/references/utilities/statuses.md +63 -667
  167. package/dist/mcp-server/index.js +0 -0
  168. package/dist/mcp-server/tools/github/list-project-files.tool.d.ts +1 -1
  169. package/dist/mcp-server/tools/github/list-project-files.tool.d.ts.map +1 -1
  170. package/dist/mcp-server/tools/github/list-project-files.tool.js +3 -3
  171. package/dist/mcp-server/tools/github/search-code.tool.js +1 -1
  172. package/dist/mcp-server/tools/github/verify-dependencies.tool.js +1 -1
  173. package/dist/mcp-server/tools/github/view-source-file.tool.js +1 -1
  174. package/package.json +24 -23
@@ -1,173 +1,69 @@
1
- # Logger
2
-
3
- Winston-based logging with scoped prefixes, multiple transports (console, daily-rotating files, UDP), and a zero-allocation high-frequency logger for performance-critical paths.
4
-
5
- ## Quick Reference
6
-
7
- | Class | Extends | Use Case |
8
- |-------|---------|----------|
9
- | `Logger` | -- | General-purpose scoped logger with caching |
10
- | `LoggerFactory` | -- | Factory that builds `Logger` instances from scope arrays |
11
- | `HfLogger` | -- | Zero-allocation ring-buffer logger for hot paths (~100-300ns) |
12
- | `HfLogFlusher` | -- | Background flusher for `HfLogger` entries |
13
- | `DgramTransport` | `winston-transport.Transport` | Custom Winston transport that sends logs over UDP |
14
-
15
- #### Import Paths
1
+ ---
2
+ title: Logger
3
+ description: Scoped, cached logging via LoggerFactory - Winston by default, with console, daily-rotating file, and UDP transports built in
4
+ difficulty: beginner
5
+ ---
16
6
 
17
- ```typescript
18
- // Core classes
19
- import { Logger, LoggerFactory, ApplicationLogger } from '@venizia/ignis-helpers';
20
-
21
- // High-frequency logger
22
- import { HfLogger, HfLogFlusher } from '@venizia/ignis-helpers';
23
-
24
- // Constants & types
25
- import { LogLevels, LoggerFormats } from '@venizia/ignis-helpers';
26
- import type { TLogLevel, TLoggerFormat } from '@venizia/ignis-helpers';
27
-
28
- // Custom logger utilities
29
- import {
30
- defineCustomLogger,
31
- defineLogFormatter,
32
- defineJsonLoggerFormatter,
33
- definePrettyLoggerFormatter,
34
- applicationLogFormatter,
35
- applicationLogger,
36
- } from '@venizia/ignis-helpers';
37
- import type { IFileTransportOptions, ICustomLoggerOptions } from '@venizia/ignis-helpers';
38
-
39
- // UDP transport
40
- import { DgramTransport } from '@venizia/ignis-helpers';
41
- import type { IDgramTransportOptions } from '@venizia/ignis-helpers';
42
- ```
7
+ # Logger
43
8
 
44
- ## Creating an Instance
9
+ IGNIS gives every helper a scoped `ILogger`. `LoggerFactory` builds it from one registered provider - Winston by default, with console, daily-rotating file, and UDP transports built in.
45
10
 
46
- ### Using LoggerFactory (Recommended)
11
+ ## In one example
47
12
 
48
- `LoggerFactory.getLogger` accepts an array of scope strings, joins them with `-`, and returns a cached `Logger` instance.
13
+ The smallest real use: get a scoped logger and log with it.
49
14
 
50
15
  ```typescript
51
16
  import { LoggerFactory } from '@venizia/ignis-helpers';
52
17
 
53
- const logger = LoggerFactory.getLogger(['MyService']);
54
- logger.info('Service initialized');
55
- // Output: [MyService] Service initialized
56
-
57
- const scopedLogger = LoggerFactory.getLogger(['Payment', 'Stripe']);
58
- scopedLogger.info('Charge created');
59
- // Output: [Payment-Stripe] Charge created
60
- ```
61
-
62
- > [!TIP]
63
- > `LoggerFactory` is how `BaseHelper` creates its internal logger. Every helper in the framework gets a scoped logger automatically through this path.
64
-
65
- ### Using Logger.get() Directly
66
-
67
- ```typescript
68
- import { Logger } from '@venizia/ignis-helpers';
69
-
70
- const logger = Logger.get('MyService');
71
- logger.info('Direct logger access');
72
- // Output: [MyService] Direct logger access
18
+ const logger = LoggerFactory.getLogger(['UserService']);
19
+ logger.info('User created');
20
+ // Output: [UserService] User created
73
21
  ```
74
22
 
75
- Pass a custom Winston logger instance as the second parameter to use your own transport configuration:
76
-
77
- ```typescript
78
- import { Logger, defineCustomLogger, applicationLogFormatter } from '@venizia/ignis-helpers';
79
-
80
- const customWinstonLogger = defineCustomLogger({
81
- loggerFormatter: applicationLogFormatter,
82
- transports: {
83
- info: { file: { prefix: 'custom', folder: './logs' } },
84
- error: { file: { prefix: 'custom-error', folder: './logs' } },
85
- },
86
- });
23
+ `LoggerFactory` is how `BaseHelper` creates its internal logger, so every helper in the framework gets a scoped logger the same way, for free.
87
24
 
88
- const logger = Logger.get('MyService', customWinstonLogger);
89
- ```
25
+ ## How it works
90
26
 
91
- Custom loggers are cached under a separate key (`scope:custom`), so a default and custom logger for the same scope can coexist.
27
+ - **Typed against `ILogger`.** Every consumer - including `BaseHelper.logger` - gets the `ILogger` interface, never a concrete class. Winston is the default provider behind it, selected in `factory.ts`.
28
+ - **Provider-based.** `LoggerFactory.use({ provider })` selects the app's logger engine once, at the entrypoint. Winston is the default; [pino](/extensions/helpers/logger/pino) is the throughput option. Every factory-issued logger follows the registration, even one captured at import time.
29
+ - **Scoped and cached.** `LoggerFactory.getLogger(scopes)` joins the scopes with `-` and caches the result per scope. The same scope always returns the same instance. `BaseHelper` calls this in its constructor, so every helper's `this.logger` comes pre-scoped.
30
+ - **Custom-backed loggers are the exception.** `Logger.get(scope, customWinstonLogger)` (from the `/winston` sub-path) is NOT cached. Each call returns a fresh wrapper over the instance you passed in.
31
+ - **Method scoping.** `.for(methodName)` returns a child logger scoped to `<scope>-<methodName>` (also cached), so each line shows where it came from.
32
+ - **Level floor.** `APP_ENV_LOGGER_LEVEL` (default `debug`) sets the logger-level floor. Transports without their own level inherit it.
33
+ - **`debug()` is gated.** It emits only when `DEBUG=true` and `NODE_ENV` is unset or listed in `Environment.COMMON_ENVS`. Extend that set via `APP_ENV_EXTRA_LOG_ENVS`. The check runs once at module load - runtime env changes need a restart.
92
34
 
93
- ### Logger Caching
35
+ **Log levels**
94
36
 
95
- Both methods use internal caching -- the same scope always returns the same `Logger` instance:
37
+ Five levels, each with a direct method: `debug`, `info`, `warn`, `error`, `emerg`. The generic `.log(level, ...)` remains for picking the level dynamically. What each level means, and when to use it, is in the [level guide](/extensions/helpers/logger/reference#what-each-level-means).
96
38
 
97
- ```typescript
98
- const logger1 = Logger.get('MyService');
99
- const logger2 = Logger.get('MyService');
100
- // logger1 === logger2 (same instance)
101
- ```
39
+ **Transports**
102
40
 
103
- ### ApplicationLogger Alias
41
+ | Transport | Turns on when |
42
+ |-----------|---------------|
43
+ | Console | Always |
44
+ | Daily-rotating file | `APP_ENV_LOGGER_FOLDER_PATH` is set |
45
+ | UDP (`DgramTransport`) | All four UDP `APP_ENV_LOGGER_DGRAM_*` variables are set |
104
46
 
105
- `ApplicationLogger` is exported as both a value and a type alias for `Logger`, providing backward compatibility:
106
-
107
- ```typescript
108
- import { ApplicationLogger } from '@venizia/ignis-helpers';
47
+ Output shape (plain text or JSON) follows `APP_ENV_LOGGER_FORMAT`. Color codes appear only on the console, and only in a development `NODE_ENV` - file and UDP output never carries ANSI escapes. See [Color](./reference#color) to override.
109
48
 
110
- const logger = ApplicationLogger.get('MyService');
111
- ```
49
+ For extreme hot paths, `HfLogger` is a separate ring-buffer logger outside this pipeline, with its own [usage guide](/extensions/helpers/logger/hf-logger). The [Full reference](/extensions/helpers/logger/reference) covers everything else, including the `ApplicationLogger` facade.
112
50
 
113
- ## Usage
51
+ ## Common tasks
114
52
 
115
- ### Log Levels
53
+ ### Get a scoped logger
116
54
 
117
- The `Logger` class exposes direct methods for `info`, `warn`, `error`, `emerg`, and `debug`. Other levels (`alert`, `http`, `verbose`, `silly`) are accessible through the generic `log()` method.
55
+ Use `LoggerFactory.getLogger` with an array of scope segments, or `ApplicationLogger.get` with a single string. Both cache by scope and follow the registered provider.
118
56
 
119
57
  ```typescript
120
- logger.info('User created');
121
- logger.warn('Rate limit approaching');
122
- logger.error('Failed to process payment');
123
- logger.emerg('System out of memory');
124
- logger.debug('Query took 12ms'); // Requires DEBUG=true
125
- logger.log('alert', 'Threshold exceeded'); // Generic method for any level
126
- ```
58
+ import { ApplicationLogger, LoggerFactory } from '@venizia/ignis-helpers';
127
59
 
128
- The `LogLevels` class defines all available levels and provides validation:
129
-
130
- ```typescript
131
- import { LogLevels } from '@venizia/ignis-helpers';
132
- import type { TLogLevel } from '@venizia/ignis-helpers';
133
-
134
- LogLevels.ERROR; // 'error'
135
- LogLevels.ALERT; // 'alert'
136
- LogLevels.EMERG; // 'emerg'
137
- LogLevels.WARN; // 'warn'
138
- LogLevels.INFO; // 'info'
139
- LogLevels.HTTP; // 'http'
140
- LogLevels.VERBOSE; // 'verbose'
141
- LogLevels.DEBUG; // 'debug'
142
- LogLevels.SILLY; // 'silly'
143
-
144
- LogLevels.isValid('info'); // true
145
- LogLevels.isValid('unknown'); // false
146
-
147
- const level: TLogLevel = 'info';
60
+ const scoped = LoggerFactory.getLogger(['Payment', 'Stripe']); // [Payment-Stripe]
61
+ const direct = ApplicationLogger.get('MyService'); // [MyService]
148
62
  ```
149
63
 
150
- #### Winston Level Priority
64
+ ### Scope logs to a method
151
65
 
152
- The `defineCustomLogger` function configures Winston with these numeric priorities by default:
153
-
154
- | Level | Priority | Color |
155
- |-------|----------|-------|
156
- | `error` | 0 | red |
157
- | `alert` | 0 | red |
158
- | `emerg` | 0 | red |
159
- | `warn` | 1 | yellow |
160
- | `info` | 2 | green |
161
- | `http` | 3 | magenta |
162
- | `verbose` | 4 | gray |
163
- | `debug` | 5 | blue |
164
- | `silly` | 6 | gray |
165
-
166
- Lower numeric values have higher priority. `error`, `alert`, and `emerg` share priority `0`.
167
-
168
- ### Method-Scoped Logging
169
-
170
- The `.for()` method creates a sub-scoped logger for specific methods, appending the method name to the scope with a `-` separator. The resulting logger is also cached.
66
+ `.for()` appends a method name to the current scope so every line in that method self-identifies.
171
67
 
172
68
  ```typescript
173
69
  class UserService {
@@ -176,455 +72,85 @@ class UserService {
176
72
  async createUser(data: CreateUserDto) {
177
73
  this.logger.for('createUser').info('Creating user: %j', data);
178
74
  // Output: [UserService-createUser] Creating user: {...}
179
-
180
- try {
181
- const user = await this.userRepo.create({ data });
182
- this.logger.for('createUser').info('User created: %s', user.id);
183
- return user;
184
- } catch (error) {
185
- this.logger.for('createUser').error('Failed to create user: %s', error);
186
- throw error;
187
- }
188
75
  }
189
76
  }
190
77
  ```
191
78
 
192
- ### Logging Errors: `%s`, Never `%j`
79
+ ### Log an Error with `%s`, never `%j`
193
80
 
194
- `message` and `stack` are non-enumerable properties on a native `Error`. `%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. Always pair an `Error` argument with `%s`; reserve `%j`/`%o` for plain data objects.
81
+ `%s` routes the error through `ErrorPrettier`, which projects it down to identity, cause and frames. `%j` keeps every enumerable own property instead, so a driver error takes its whole query along and a `jose` error its whole payload. Always pair an `Error` argument with `%s`.
195
82
 
196
83
  ```typescript
197
- // Good - %s prints message + stack
198
- logger.error('Failed to create user: %s', error);
199
-
200
- // ❌ Bad - %j drops message and stack (non-enumerable on Error)
201
- logger.error('Failed to create user: %j', error);
84
+ logger.error('Failed to create user: %s', error); // prints message + stack
202
85
  ```
203
86
 
204
- ### Object Inspection Depth for `%s`
205
-
206
- 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. IGNIS's formatter (`formatLogMessage`/`deepSplat`) pre-inspects any object bound to a `%s` placeholder before handing the message to Winston, widening that depth so nested fields print instead of collapsing.
87
+ A mistaken `%j` is no longer a silent loss: the formatter projects `message` and `stack` in before `JSON.stringify` runs, which on its own would drop both (they are non-enumerable). It is still the wrong placeholder for an error.
207
88
 
208
- ```typescript
209
- logger.error('Failed: %s', error); // nested `error.cause` is now visible, not `[Object]`
210
- ```
89
+ ### Keep a driver error readable with `ErrorPrettier`
211
90
 
212
- The inspection depth defaults to `5` and is configurable via `APP_ENV_LOGGER_INSPECT_DEPTH`:
213
-
214
- ```bash
215
- APP_ENV_LOGGER_INSPECT_DEPTH=8
216
- ```
217
-
218
- 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.
219
-
220
- ### Log Formats
221
-
222
- The logger supports two output formats, controlled by the `APP_ENV_LOGGER_FORMAT` environment variable (default: `text`).
223
-
224
- The `LoggerFormats` class provides constants and validation:
91
+ `%s` prints the whole object. A `pg` or `drizzle` failure carries the statement in `message`, again in `stack`, and again in `query` - one failure floods the log with the same SQL several times. Wrap it:
225
92
 
226
93
  ```typescript
227
- import { LoggerFormats } from '@venizia/ignis-helpers';
228
- import type { TLoggerFormat } from '@venizia/ignis-helpers';
229
-
230
- LoggerFormats.JSON; // 'json'
231
- LoggerFormats.TEXT; // 'text'
232
- LoggerFormats.isValid('json'); // true
94
+ import { ErrorPrettier } from '@venizia/ignis-helpers';
233
95
 
234
- const fmt: TLoggerFormat = 'text';
96
+ logger.error('Failed to create user | %s', ErrorPrettier.format({ error }));
235
97
  ```
236
98
 
237
- #### JSON Format
99
+ You get the identity, the root `cause` with its code, the driver's `hint`, the full message and the top stack frames - each on its own line, with the message's real newlines intact. The duplicated statement and the noisy driver internals are gone.
238
100
 
239
- ```bash
240
- APP_ENV_LOGGER_FORMAT=json
241
- ```
101
+ Pass `includeStack: false` when the error is one you raised yourself and the frames add nothing. For a JSON sink, `ErrorPrettier.summarize({ error })` returns the same projection as a typed object instead of a string.
242
102
 
243
- Output:
103
+ ### Switch the output format
244
104
 
245
- ```json
246
- {"level":"info","message":"[UserService] User created","timestamp":"2024-01-11T10:30:00.000Z","label":"APP"}
247
- ```
248
-
249
- #### Pretty Text Format (Default)
105
+ `APP_ENV_LOGGER_FORMAT` controls plain text (default) vs. JSON output.
250
106
 
251
107
  ```bash
252
- APP_ENV_LOGGER_FORMAT=text
253
- ```
254
-
255
- Output:
256
-
257
- ```
258
- 2024-01-11T10:30:00.000Z [APP] info: [UserService] User created
259
- ```
260
-
261
- > [!NOTE]
262
- > 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.
263
-
264
- #### Custom Formatters
265
-
266
- Build formatters directly using the exported helper functions:
267
-
268
- ```typescript
269
- import {
270
- defineLogFormatter,
271
- defineJsonLoggerFormatter,
272
- definePrettyLoggerFormatter,
273
- } from '@venizia/ignis-helpers';
274
-
275
- // Auto-detect from APP_ENV_LOGGER_FORMAT (or override with format option)
276
- const formatter = defineLogFormatter({ label: 'my-app' });
277
- const jsonFmt = defineLogFormatter({ label: 'my-app', format: 'json' });
278
-
279
- // Or use specific formatters directly
280
- const jsonFormatter = defineJsonLoggerFormatter({ label: 'my-app' });
281
- const prettyFormatter = definePrettyLoggerFormatter({ label: 'my-app' });
282
- ```
283
-
284
- ### Transports
285
-
286
- Every logger created by `defineCustomLogger` always includes a **Console** transport at the `debug` level. File and UDP transports are optional.
287
-
288
- #### File Rotation (DailyRotateFile)
289
-
290
- Configure file rotation through environment variables or programmatically via `IFileTransportOptions`.
291
-
292
- **Environment variables:**
293
-
294
- | Variable | Default | Description |
295
- |----------|---------|-------------|
296
- | `APP_ENV_LOGGER_FOLDER_PATH` | `./` | Log files directory |
297
- | `APP_ENV_LOGGER_FILE_FREQUENCY` | `1h` | Rotation frequency |
298
- | `APP_ENV_LOGGER_FILE_MAX_SIZE` | `100m` | Max file size before rotation |
299
- | `APP_ENV_LOGGER_FILE_MAX_FILES` | `5d` | Retention period |
300
- | `APP_ENV_LOGGER_FILE_DATE_PATTERN` | `YYYYMMDD_HH` | Date pattern in filename |
301
-
302
- **Programmatic configuration:**
303
-
304
- ```typescript
305
- import { defineCustomLogger, applicationLogFormatter } from '@venizia/ignis-helpers';
306
-
307
- const customLogger = defineCustomLogger({
308
- loggerFormatter: applicationLogFormatter,
309
- transports: {
310
- info: {
311
- file: {
312
- prefix: 'my-app',
313
- folder: './logs',
314
- frequency: '24h',
315
- maxSize: '500m',
316
- maxFiles: '30d',
317
- datePattern: 'YYYYMMDD',
318
- },
319
- },
320
- error: {
321
- file: {
322
- prefix: 'my-app-error',
323
- folder: './logs',
324
- maxFiles: '90d',
325
- },
326
- },
327
- },
328
- });
329
- ```
330
-
331
- Generated filename pattern: `{folder}/{prefix}-info-{DATE}.log` or `{folder}/{prefix}-error-{DATE}.log`.
332
-
333
- #### IFileTransportOptions
334
-
335
- ```typescript
336
- interface IFileTransportOptions {
337
- prefix: string; // Filename prefix (required)
338
- folder: string; // Output directory (required)
339
- frequency?: string; // Rotation frequency (default: '1h')
340
- maxSize?: string; // Max file size (default: '100m')
341
- maxFiles?: string; // Retention period (default: '5d')
342
- datePattern?: string; // Date pattern in filename (default: 'YYYYMMDD_HH')
343
- }
344
- ```
345
-
346
- #### UDP Transport (DgramTransport)
347
-
348
- The `DgramTransport` is a custom Winston transport that sends log entries over UDP. It supports level-based filtering -- only messages matching the configured `levels` set are forwarded.
349
-
350
- ```typescript
351
- import { DgramTransport } from '@venizia/ignis-helpers';
352
-
353
- const transport = new DgramTransport({
354
- label: 'my-app',
355
- host: '127.0.0.1',
356
- port: 5000,
357
- levels: ['error', 'warn', 'info'],
358
- socketOptions: { type: 'udp4' },
359
- });
360
- ```
361
-
362
- **Static factory with validation** -- returns `null` if any required field is missing:
363
-
364
- ```typescript
365
- const transport = DgramTransport.fromPartial({
366
- label: 'my-app',
367
- host: '127.0.0.1',
368
- port: 5000,
369
- levels: ['error', 'warn'],
370
- socketOptions: { type: 'udp4' },
371
- });
372
- // Returns null if label, host, port, levels (non-empty), or socketOptions is missing
373
- ```
374
-
375
- The transport automatically re-establishes the UDP socket if it encounters an error.
376
-
377
- **Environment variables for the default application logger:**
378
-
379
- | Variable | Description |
380
- |----------|-------------|
381
- | `APP_ENV_LOGGER_DGRAM_HOST` | UDP log aggregator host |
382
- | `APP_ENV_LOGGER_DGRAM_PORT` | UDP log aggregator port |
383
- | `APP_ENV_LOGGER_DGRAM_LABEL` | Label to identify log source |
384
- | `APP_ENV_LOGGER_DGRAM_LEVELS` | Comma-separated levels to send via UDP |
385
-
386
- #### IDgramTransportOptions
387
-
388
- ```typescript
389
- interface IDgramTransportOptions extends Transport.TransportStreamOptions {
390
- label: string; // Label to identify log source
391
- host: string; // UDP host
392
- port: number; // UDP port
393
- levels: Array<string>; // Levels to forward over UDP
394
- socketOptions: dgram.SocketOptions; // Node.js dgram socket options
395
- }
396
- ```
397
-
398
- #### ICustomLoggerOptions
399
-
400
- ```typescript
401
- interface ICustomLoggerOptions {
402
- logLevels?: { [name: string | symbol]: number };
403
- logColors?: { [name: string | symbol]: string };
404
- loggerFormatter?: ReturnType<typeof winston.format.combine>;
405
- transports: {
406
- info: {
407
- file?: IFileTransportOptions;
408
- dgram?: Partial<IDgramTransportOptions>;
409
- };
410
- error: {
411
- file?: IFileTransportOptions;
412
- dgram?: Partial<IDgramTransportOptions>;
413
- };
414
- };
415
- }
108
+ APP_ENV_LOGGER_FORMAT=text # 2024-01-11T10:30:00.000Z [APP] info: [UserService] User created
109
+ APP_ENV_LOGGER_FORMAT=json # {"level":"info","message":"[UserService] User created", ...}
416
110
  ```
417
111
 
418
- Both `info` and `error` transport groups support optional `file` (DailyRotateFile) and `dgram` (UDP) transports. A console transport is always included. Error file transports are also registered as exception handlers.
419
-
420
- ### Debug Logging Behavior
112
+ The `[APP]` label comes from `APP_ENV_APPLICATION_NAME` (defaults to `'APP'`).
421
113
 
422
- Debug logs require **both** conditions to be met:
114
+ ### Enable daily file rotation
423
115
 
424
- 1. `DEBUG=true` environment variable is set (parsed via `toBoolean`)
425
- 2. `NODE_ENV` is either unset **or** is present in the `Environment.COMMON_ENVS` set
426
-
427
- The `COMMON_ENVS` set includes: `local`, `debug`, `development`, `dev`, `sit`, `uat`, `alpha`, `beta`, `staging`, `production`. You can extend this set with `APP_ENV_EXTRA_LOG_ENVS`:
116
+ Point `APP_ENV_LOGGER_FOLDER_PATH` at a directory. Rotation frequency, size cap, and retention are also env-driven. Without this variable, no log files are written - console (and UDP, if configured) remain the only outputs.
428
117
 
429
118
  ```bash
430
- DEBUG=true
431
- NODE_ENV=development
432
- APP_ENV_EXTRA_LOG_ENVS=qa,preview # Comma-separated additional environments
433
- ```
434
-
435
- > [!IMPORTANT]
436
- > 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.
437
-
438
- ### High-Frequency Logger (HfLogger)
439
-
440
- For performance-critical applications (e.g., HFT systems, game servers), `HfLogger` provides zero-allocation logging via a lock-free ring buffer backed by `SharedArrayBuffer`.
441
-
442
- ```typescript
443
- import { HfLogger, HfLogFlusher } from '@venizia/ignis-helpers';
444
-
445
- // At initialization time (once):
446
- const logger = HfLogger.get('OrderEngine');
447
- const MSG_ORDER_SENT = HfLogger.encodeMessage('Order sent');
448
- const MSG_ORDER_FILLED = HfLogger.encodeMessage('Order filled');
449
-
450
- // Start background flusher
451
- const flusher = new HfLogFlusher();
452
- flusher.start(100); // Flush every 100ms
453
-
454
- // In hot path (~100-300ns, zero allocation):
455
- logger.log('info', MSG_ORDER_SENT);
456
- logger.log('info', MSG_ORDER_FILLED);
119
+ APP_ENV_LOGGER_FOLDER_PATH=./app_data/logs
120
+ APP_ENV_LOGGER_FILE_MAX_FILES=30d
457
121
  ```
458
122
 
459
- #### HfLogger API
460
-
461
- | Method | Signature | Description |
462
- |--------|-----------|-------------|
463
- | `HfLogger.get` | `(scope: string) => HfLogger` | Get or create a cached logger instance |
464
- | `HfLogger.encodeMessage` | `(msg: string) => Uint8Array` | Pre-encode a message string to bytes (cached) |
465
- | `logger.log` | `(level: THfLogLevel, messageBytes: Uint8Array) => void` | Write entry to ring buffer |
466
-
467
- Supported levels: `debug` (0), `info` (1), `warn` (2), `error` (3), `emerg` (4).
123
+ | Setting | Default |
124
+ |---|---|
125
+ | Rotation frequency | `1h` |
126
+ | Max file size | `100m` |
127
+ | Retention | `5d` |
468
128
 
469
- #### HfLogFlusher API
129
+ Full programmatic configuration - custom prefixes, custom retention - is in the [Full reference](/extensions/helpers/logger/reference).
470
130
 
471
- | Method | Signature | Description |
472
- |--------|-----------|-------------|
473
- | `flusher.flush` | `() => Promise<void>` | Flush all buffered entries to output |
474
- | `flusher.start` | `(intervalMs?: number) => void` | Start background flush loop (default: `100`ms) |
131
+ ### Forward logs over UDP
475
132
 
476
- #### Ring Buffer Entry Format
477
-
478
- Each entry occupies exactly 256 bytes in a 64K-entry (16MB) `SharedArrayBuffer`:
479
-
480
- | Offset | Size | Field |
481
- |--------|------|-------|
482
- | 0-7 | 8 bytes | Timestamp (`BigInt64`, nanosecond precision) |
483
- | 8 | 1 byte | Level (`0`=debug, `1`=info, `2`=warn, `3`=error, `4`=emerg) |
484
- | 9-40 | 32 bytes | Scope (fixed-width, padded) |
485
- | 41-255 | 215 bytes | Message (fixed-width, truncated if longer) |
486
-
487
- The buffer wraps around at 65,536 entries using bitwise AND masking (`writeIndex & (BUFFER_SIZE - 1)`).
488
-
489
- > [!WARNING]
490
- > Pre-encode messages at initialization time using `HfLogger.encodeMessage()`. Calling it in the hot path defeats the zero-allocation purpose because it triggers string encoding on every log call.
491
-
492
- ### Environment Variables
493
-
494
- #### Core Configuration
495
-
496
- | Variable | Default | Description |
497
- |----------|---------|-------------|
498
- | `APP_ENV_APPLICATION_NAME` | `APP` | Label prefix shown in all log output |
499
- | `DEBUG` | `false` | Enable debug-level logging |
500
- | `NODE_ENV` | _(unset)_ | Must be in `COMMON_ENVS` or unset for debug to activate |
501
- | `APP_ENV_EXTRA_LOG_ENVS` | _(empty)_ | Comma-separated additional environments to allow debug |
502
- | `APP_ENV_LOGGER_FORMAT` | `text` | Output format (`json` or `text`) |
503
- | `APP_ENV_LOGGER_FOLDER_PATH` | `./` | Log files directory |
504
- | `APP_ENV_LOGGER_INSPECT_DEPTH` | `5` | Object inspection depth for `%s` placeholders. Non-negative integer only; invalid or absent falls back to `5` |
505
-
506
- #### File Rotation
507
-
508
- | Variable | Default | Description |
509
- |----------|---------|-------------|
510
- | `APP_ENV_LOGGER_FILE_FREQUENCY` | `1h` | Rotation frequency |
511
- | `APP_ENV_LOGGER_FILE_MAX_SIZE` | `100m` | Max file size before rotation |
512
- | `APP_ENV_LOGGER_FILE_MAX_FILES` | `5d` | Retention period |
513
- | `APP_ENV_LOGGER_FILE_DATE_PATTERN` | `YYYYMMDD_HH` | Date pattern in filename |
514
-
515
- #### UDP Transport
516
-
517
- | Variable | Description |
518
- |----------|-------------|
519
- | `APP_ENV_LOGGER_DGRAM_HOST` | UDP log aggregator host |
520
- | `APP_ENV_LOGGER_DGRAM_PORT` | UDP log aggregator port |
521
- | `APP_ENV_LOGGER_DGRAM_LABEL` | Label to identify log source |
522
- | `APP_ENV_LOGGER_DGRAM_LEVELS` | Comma-separated levels to send via UDP |
523
-
524
- #### Example `.env`
133
+ Set all four `APP_ENV_LOGGER_DGRAM_*` variables - the transport is silently skipped if any one is missing.
525
134
 
526
135
  ```bash
527
- # Application
528
- APP_ENV_APPLICATION_NAME=my-service
529
-
530
- # Core
531
- DEBUG=true
532
- APP_ENV_LOGGER_FORMAT=json
533
- APP_ENV_LOGGER_FOLDER_PATH=./app_data/logs
534
- APP_ENV_LOGGER_INSPECT_DEPTH=5
535
-
536
- # File rotation
537
- APP_ENV_LOGGER_FILE_FREQUENCY=24h
538
- APP_ENV_LOGGER_FILE_MAX_SIZE=500m
539
- APP_ENV_LOGGER_FILE_MAX_FILES=30d
540
-
541
- # UDP transport
542
136
  APP_ENV_LOGGER_DGRAM_HOST=127.0.0.1
543
137
  APP_ENV_LOGGER_DGRAM_PORT=5000
544
138
  APP_ENV_LOGGER_DGRAM_LABEL=my-app
545
139
  APP_ENV_LOGGER_DGRAM_LEVELS=error,warn,info
546
140
  ```
547
141
 
548
- ## API Summary
549
-
550
- | Export | Kind | Description |
551
- |--------|------|-------------|
552
- | `Logger` | class | Scoped logger with caching, wraps a Winston logger instance |
553
- | `ApplicationLogger` | value + type alias | Backward-compatible alias for `Logger` |
554
- | `LoggerFactory` | class | Factory that creates `Logger` from scope arrays |
555
- | `HfLogger` | class | Zero-allocation ring-buffer logger |
556
- | `HfLogFlusher` | class | Background flusher for `HfLogger` |
557
- | `LogLevels` | class (constants) | Log level constants (`ERROR`, `ALERT`, `EMERG`, `WARN`, `INFO`, `HTTP`, `VERBOSE`, `DEBUG`, `SILLY`) with `isValid()` |
558
- | `LoggerFormats` | class (constants) | Format constants (`JSON`, `TEXT`) with `isValid()` |
559
- | `defineCustomLogger` | `(opts: ICustomLoggerOptions) => winston.Logger` | Create a fully configured Winston logger |
560
- | `defineLogFormatter` | `(opts: { label: string; format?: TLoggerFormat }) => winston.Logform.Format` | Create a formatter (auto-detects format from env) |
561
- | `defineJsonLoggerFormatter` | `(opts: { label: string }) => winston.Logform.Format` | Create a JSON formatter |
562
- | `definePrettyLoggerFormatter` | `(opts: { label: string }) => winston.Logform.Format` | Create a pretty text formatter |
563
- | `applicationLogFormatter` | `winston.Logform.Format` | Pre-built formatter using `APP_ENV_APPLICATION_NAME` label |
564
- | `applicationLogger` | `winston.Logger` | Pre-built default Winston logger instance |
565
- | `DgramTransport` | class | Custom Winston transport for UDP logging |
566
- | `TLogLevel` | type | Union of all log level string literals |
567
- | `TLoggerFormat` | type | Union of `'json' \| 'text'` |
568
- | `IFileTransportOptions` | interface | Options for daily-rotating file transport |
569
- | `ICustomLoggerOptions` | interface | Options for `defineCustomLogger` |
570
- | `IDgramTransportOptions` | interface | Options for `DgramTransport` |
571
-
572
- ## Troubleshooting
573
-
574
- ### Debug logs not appearing
575
-
576
- **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.
577
-
578
- **Fix:**
579
- 1. Verify `DEBUG=true` is set in your environment.
580
- 2. Verify `NODE_ENV` is set to one of: `local`, `debug`, `development`, `dev`, `sit`, `uat`, `alpha`, `beta`, `staging`, `production` -- or is unset entirely.
581
- 3. If you use a custom environment name (e.g. `qa`), add it to `APP_ENV_EXTRA_LOG_ENVS=qa`.
582
-
583
- ```bash
584
- DEBUG=true NODE_ENV=development bun run server:dev
585
- ```
586
-
587
- ### "[defineLogger] Invalid logger format | format: {format} | valids: json,text"
588
-
589
- **Cause:** The `format` option passed to `defineLogFormatter` (or the `APP_ENV_LOGGER_FORMAT` environment variable) is not `json` or `text`.
590
-
591
- **Fix:** Set `APP_ENV_LOGGER_FORMAT` to either `json` or `text`:
592
-
593
- ```bash
594
- APP_ENV_LOGGER_FORMAT=text
595
- ```
596
-
597
- ### UDP transport not sending logs
598
-
599
- **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.
600
-
601
- **Fix:**
602
- 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`.
603
- 2. `APP_ENV_LOGGER_DGRAM_LEVELS` must contain at least one level (e.g. `error,warn,info`). An empty value results in no transport.
604
- 3. Verify the UDP aggregator is reachable from your host (firewall, port binding).
605
-
606
- ### Log label shows "APP" instead of application name
607
-
608
- **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'`.
609
-
610
- **Fix:** Set `APP_ENV_APPLICATION_NAME` in your environment:
611
-
612
- ```bash
613
- APP_ENV_APPLICATION_NAME=my-service
614
- ```
615
-
616
- ## See Also
617
-
618
- - **Related Concepts:**
619
- - [Services](/guides/core-concepts/services) -- Logging in services
620
- - [Controllers](/guides/core-concepts/rest-controllers) -- Logging in controllers
142
+ ## See also
621
143
 
622
- - **Other Helpers:**
623
- - [Helpers Index](../index) -- All available helpers
144
+ - [Full reference](/extensions/helpers/logger/reference) - every export, transport option, log level, and edge case
145
+ - [Services](/guides/core-concepts/services) - logging in services
146
+ - [Controllers](/guides/core-concepts/rest-controllers) - logging in controllers
147
+ - [Helpers Overview](/extensions/helpers/) - all available helpers
148
+ - [Request Tracker Component](/extensions/components/request-tracker) - request logging
149
+ - [Winston documentation](https://github.com/winstonjs/winston) - underlying logging library
624
150
 
625
- - **References:**
626
- - [Request Tracker Component](/extensions/components/request-tracker) -- Request logging
151
+ **Files:**
627
152
 
628
- - **External Resources:**
629
- - [Winston Documentation](https://github.com/winstonjs/winston) -- Winston logging library
630
- - [winston-daily-rotate-file](https://github.com/winstonjs/winston-daily-rotate-file) -- File rotation transport
153
+ - [`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`, the contract every consumer types against
154
+ - [`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
155
+ - [`packages/helpers/src/modules/logger/factory.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/modules/logger/factory.ts) - `LoggerFactory`, `ApplicationLogger`
156
+ - [`packages/helpers/src/modules/logger/winston/define.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/modules/logger/winston/define.ts) - Winston setup, transports, env configuration