@eqxjs/nest-logger 3.1.0-beta.9 → 3.1.1-beta.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 (122) hide show
  1. package/CHANGELOG +57 -1
  2. package/MIGRATION.md +234 -0
  3. package/PERFORMANCE_IMPROVEMENTS.md +158 -0
  4. package/README.md +2008 -16
  5. package/RESTRUCTURING_SUMMARY.md +272 -0
  6. package/STRUCTURE.md +110 -0
  7. package/dist/constants/action-message.constant.d.ts +187 -0
  8. package/dist/constants/action-message.constant.js +220 -0
  9. package/dist/constants/action-message.constant.js.map +1 -0
  10. package/dist/constants/index.d.ts +2 -0
  11. package/dist/constants/index.js +9 -0
  12. package/dist/constants/index.js.map +1 -0
  13. package/dist/constants/logger.constants.d.ts +17 -0
  14. package/dist/constants/logger.constants.js +20 -0
  15. package/dist/constants/logger.constants.js.map +1 -0
  16. package/dist/core/formatters/index.d.ts +1 -0
  17. package/dist/core/formatters/index.js +6 -0
  18. package/dist/core/formatters/index.js.map +1 -0
  19. package/dist/core/formatters/logger.formatter.d.ts +141 -0
  20. package/dist/core/formatters/logger.formatter.js +268 -0
  21. package/dist/core/formatters/logger.formatter.js.map +1 -0
  22. package/dist/core/loggers/app.logger.d.ts +46 -0
  23. package/dist/core/loggers/app.logger.js +92 -0
  24. package/dist/core/loggers/app.logger.js.map +1 -0
  25. package/dist/core/loggers/base-app.logger.d.ts +299 -0
  26. package/dist/core/loggers/base-app.logger.js +517 -0
  27. package/dist/core/loggers/base-app.logger.js.map +1 -0
  28. package/dist/core/loggers/custom.logger.d.ts +127 -0
  29. package/dist/core/loggers/custom.logger.js +260 -0
  30. package/dist/core/loggers/custom.logger.js.map +1 -0
  31. package/dist/core/loggers/index.d.ts +3 -0
  32. package/dist/core/loggers/index.js +10 -0
  33. package/dist/core/loggers/index.js.map +1 -0
  34. package/dist/helpers/datetime.helper.d.ts +24 -0
  35. package/dist/helpers/datetime.helper.js +36 -0
  36. package/dist/helpers/datetime.helper.js.map +1 -0
  37. package/dist/helpers/index.d.ts +5 -0
  38. package/dist/helpers/index.js +17 -0
  39. package/dist/helpers/index.js.map +1 -0
  40. package/dist/helpers/log.helper.d.ts +84 -0
  41. package/dist/helpers/log.helper.js +109 -0
  42. package/dist/helpers/log.helper.js.map +1 -0
  43. package/dist/helpers/logger-builder.helper.d.ts +242 -0
  44. package/dist/helpers/logger-builder.helper.js +345 -0
  45. package/dist/helpers/logger-builder.helper.js.map +1 -0
  46. package/dist/helpers/message-formatter.helper.d.ts +88 -0
  47. package/dist/helpers/message-formatter.helper.js +159 -0
  48. package/dist/helpers/message-formatter.helper.js.map +1 -0
  49. package/dist/helpers/time-performance.helper.d.ts +68 -0
  50. package/dist/helpers/time-performance.helper.js +82 -0
  51. package/dist/helpers/time-performance.helper.js.map +1 -0
  52. package/dist/index.d.ts +13 -5
  53. package/dist/index.js +24 -9
  54. package/dist/index.js.map +1 -1
  55. package/dist/interfaces/data-header.interface.d.ts +21 -0
  56. package/dist/{dto/m2.dto.js → interfaces/data-header.interface.js} +1 -1
  57. package/dist/interfaces/data-header.interface.js.map +1 -0
  58. package/dist/interfaces/data-protocol.interface.d.ts +14 -0
  59. package/dist/interfaces/data-protocol.interface.js +3 -0
  60. package/dist/interfaces/data-protocol.interface.js.map +1 -0
  61. package/dist/interfaces/data-service.interface.d.ts +21 -0
  62. package/dist/{dto/m3.dto.js → interfaces/data-service.interface.js} +1 -1
  63. package/dist/interfaces/data-service.interface.js.map +1 -0
  64. package/dist/{types.d.ts → interfaces/data.interface.d.ts} +4 -4
  65. package/dist/{dto/m1.dto.js → interfaces/data.interface.js} +1 -1
  66. package/dist/interfaces/data.interface.js.map +1 -0
  67. package/dist/interfaces/index.d.ts +5 -0
  68. package/dist/{types.js → interfaces/index.js} +1 -1
  69. package/dist/interfaces/index.js.map +1 -0
  70. package/dist/{dto/header.dto.js → interfaces/logger-opt.interface.js} +1 -1
  71. package/dist/interfaces/logger-opt.interface.js.map +1 -0
  72. package/dist/logger.module.js +4 -4
  73. package/dist/logger.module.js.map +1 -1
  74. package/dist/models/index.d.ts +1 -0
  75. package/dist/models/index.js +6 -0
  76. package/dist/models/index.js.map +1 -0
  77. package/dist/models/logger.dto.d.ts +71 -0
  78. package/dist/models/logger.dto.js +76 -0
  79. package/dist/models/logger.dto.js.map +1 -0
  80. package/package.json +30 -33
  81. package/dist/dto/header.dto.d.ts +0 -21
  82. package/dist/dto/header.dto.js.map +0 -1
  83. package/dist/dto/logger.dto.d.ts +0 -28
  84. package/dist/dto/logger.dto.js +0 -33
  85. package/dist/dto/logger.dto.js.map +0 -1
  86. package/dist/dto/m1.dto.d.ts +0 -7
  87. package/dist/dto/m1.dto.js.map +0 -1
  88. package/dist/dto/m2.dto.d.ts +0 -5
  89. package/dist/dto/m2.dto.js.map +0 -1
  90. package/dist/dto/m3.dto.d.ts +0 -5
  91. package/dist/dto/m3.dto.js.map +0 -1
  92. package/dist/dto/protocol.dto.d.ts +0 -14
  93. package/dist/dto/protocol.dto.js +0 -3
  94. package/dist/dto/protocol.dto.js.map +0 -1
  95. package/dist/dto/service.dto.d.ts +0 -25
  96. package/dist/dto/service.dto.js +0 -3
  97. package/dist/dto/service.dto.js.map +0 -1
  98. package/dist/logger.app.d.ts +0 -62
  99. package/dist/logger.app.js +0 -504
  100. package/dist/logger.app.js.map +0 -1
  101. package/dist/logger.service.d.ts +0 -15
  102. package/dist/logger.service.js +0 -158
  103. package/dist/logger.service.js.map +0 -1
  104. package/dist/logger.util.d.ts +0 -3
  105. package/dist/logger.util.js +0 -28
  106. package/dist/logger.util.js.map +0 -1
  107. package/dist/types.js.map +0 -1
  108. package/dist/utils/action.common.d.ts +0 -14
  109. package/dist/utils/action.common.js +0 -43
  110. package/dist/utils/action.common.js.map +0 -1
  111. package/dist/utils/datetime.util.d.ts +0 -1
  112. package/dist/utils/datetime.util.js +0 -13
  113. package/dist/utils/datetime.util.js.map +0 -1
  114. package/dist/utils/logger.opt.js +0 -3
  115. package/dist/utils/logger.opt.js.map +0 -1
  116. package/dist/utils/m1.utils.d.ts +0 -3
  117. package/dist/utils/m1.utils.js +0 -79
  118. package/dist/utils/m1.utils.js.map +0 -1
  119. package/dist/utils/time.performance.d.ts +0 -6
  120. package/dist/utils/time.performance.js +0 -18
  121. package/dist/utils/time.performance.js.map +0 -1
  122. /package/dist/{utils/logger.opt.d.ts → interfaces/logger-opt.interface.d.ts} +0 -0
package/README.md CHANGED
@@ -1,36 +1,2028 @@
1
- # {PROJECT_TITLE}
1
+ # @eqxjs/nest-logger
2
2
 
3
- {PROJECT_SHORT_DESCRIPTION}
3
+ A comprehensive, production-ready logging module for NestJS applications with built-in OpenTelemetry integration (metrics, traces, and logs API), structured logging, and support for multiple message formats.
4
4
 
5
- Status: {PROJECT_CURRENT_STATUS}
5
+ [![Version](https://img.shields.io/npm/v/@eqxjs/nest-logger)](https://www.npmjs.com/package/@eqxjs/nest-logger)
6
+ [![Test Coverage](https://img.shields.io/badge/coverage-100%25%20lines-brightgreen)](./coverage)
7
+ [![Node Version](https://img.shields.io/badge/node-%3E%3D22-brightgreen)](https://nodejs.org)
6
8
 
7
- Node: `>=22`
9
+ ## Features
8
10
 
9
- ## guideline (delete this section after finish initializing project)
11
+ **Key Features:**
10
12
 
11
- > [!IMPORTANT]
12
- > Do not forget to edit/update within these checklist
13
- >
14
- > - update `name` is package.json and reset version to `0.1.0`
15
- > - replace any value in this format `{EXAMPLE_VALUE_TO_REPLACE}`
16
- > - remove this section in README.md file
13
+ - 🚀 **NestJS Integration** - Seamless integration with NestJS framework (v11+)
14
+ - 📊 **OpenTelemetry Support** - Built-in metrics, traces, spans, and logs API with distributed tracing
15
+ - 🏷️ **Structured Logging** - Consistent log format with rich metadata (27+ fields)
16
+ - 🔒 **Sensitive Data Masking** - Automatic masking of sensitive fields (password, token, apiKey, etc.)
17
+ - 📝 **Multiple Log Levels** - Debug, Info, Log, Warn, Error, Verbose support with environment filtering
18
+ - 🎯 **Message Formats** - Support for M1 (broker/queue), M2 (HTTP/protocol), and M3 (service) message protocols
19
+ - ⚡ **Performance Optimized** - Efficient logging with caching, fast paths, and minimal overhead
20
+ - 🧪 **Well Tested** - 100% line coverage, 98%+ statement coverage with 297 test cases
21
+ - 🔍 **Telemetry Metrics** - Counter and histogram metrics for observability with configurable filtering
22
+ - 📦 **TypeScript** - Full TypeScript support with comprehensive type definitions and JSDoc
23
+ - ⏱️ **High-Resolution Timing** - Built-in TimeDiff class for precise performance measurements
24
+ - 🎨 **Builder Pattern** - Fluent LoggerDtoBuilder for complex log construction
25
+ - 🌍 **UTC+7 Timezone** - Standardized timestamps with configurable timezone support
26
+ - 🔧 **Message Truncation** - Automatic message truncation (4096 chars) to prevent log overflow
27
+ - 📋 **14 Action Tags** - Predefined action constants for consistent categorization
17
28
 
18
29
  ## Installation
19
30
 
20
31
  ```bash
21
- yarn add @eqxjs/{PROJECT_PACKAGE_NAME}
32
+ # Using yarn
33
+ yarn add @eqxjs/nest-logger
34
+
35
+ # Using npm
36
+ npm install @eqxjs/nest-logger
37
+ ```
38
+
39
+ **Requirements:**
40
+ - Node.js >= 22
41
+ - NestJS >= 11
42
+
43
+ **OpenTelemetry Setup (Optional):**
44
+
45
+ For OpenTelemetry Logs API support, ensure you have the OpenTelemetry SDK configured in your application:
46
+
47
+ ```bash
48
+ # Install OpenTelemetry SDK packages (if not already installed)
49
+ yarn add @opentelemetry/sdk-logs @opentelemetry/sdk-node
50
+ ```
51
+
52
+ Configure the SDK in your application bootstrap:
53
+
54
+ ```typescript
55
+ import { NodeSDK } from '@opentelemetry/sdk-node';
56
+ import { OTLPLogExporter } from '@opentelemetry/exporter-logs-otlp-http';
57
+
58
+ const sdk = new NodeSDK({
59
+ logRecordProcessor: new BatchLogRecordProcessor(
60
+ new OTLPLogExporter({
61
+ url: 'http://your-collector:4318/v1/logs',
62
+ })
63
+ ),
64
+ });
65
+
66
+ sdk.start();
67
+ ```
68
+
69
+ ## Feature Overview
70
+
71
+ ### Logger Types Comparison
72
+
73
+ | Feature | CustomLogger | BaseAppLogger | AppLogger | LoggerFormat (M1/M2/M3) |
74
+ |---------|--------------|---------------|-----------|-------------------------|
75
+ | **Basic Logging** | ✅ | ✅ | ✅ | ✅ |
76
+ | **Structured Metadata** | ❌ | ✅ | ✅ | ✅ |
77
+ | **OpenTelemetry** | ❌ | ✅ | ✅ | ✅ |
78
+ | **Message Formats** | ❌ | ❌ | ✅ | ✅ |
79
+ | **Summary Logs** | ❌ | ✅ | ✅ | ✅ |
80
+ | **Sensitive Masking** | ✅ | ✅ | ✅ | ✅ |
81
+ | **Use Case** | Simple apps | Advanced apps | Multi-format | Specific protocols |
82
+
83
+ ### Supported Log Levels
84
+
85
+ All loggers support these levels (controlled by `LOG_LEVEL` environment variable):
86
+
87
+ - **debug** - Detailed diagnostic information
88
+ - **info** - General informational messages
89
+ - **log** - Alias for info level
90
+ - **warn** - Warning messages for potentially harmful situations
91
+ - **error** - Error events that might still allow the app to continue
92
+ - **verbose** - Most detailed information for deep debugging
93
+
94
+
95
+ ### Metadata Fields
96
+
97
+ LoggerDto includes 27+ fields for comprehensive logging:
98
+
99
+ | Category | Fields |
100
+ |----------|--------|
101
+ | **Core** | level, timestamp, message, action |
102
+ | **Application** | appName, componentName, componentVersion |
103
+ | **Tracking** | sessionId, transactionId, recordName, guid |
104
+ | **Context** | channel, broker, device, user, public |
105
+ | **Use Case** | useCase, useCaseStep |
106
+ | **Result** | appResult, appResultCode, serviceTime, stack |
107
+ | **Infrastructure** | instance, originateServiceName, recordType |
108
+
109
+ ## Quick Start
110
+
111
+ ### 1. Import the Module
112
+
113
+ ```typescript
114
+ import { Module } from '@nestjs/common';
115
+ import { CustomLoggerModule } from '@eqxjs/nest-logger';
116
+
117
+ @Module({
118
+ imports: [CustomLoggerModule],
119
+ })
120
+ export class AppModule {}
121
+ ```
122
+
123
+ ### 2. Use the Logger
124
+
125
+ ```typescript
126
+ import { Injectable } from '@nestjs/common';
127
+ import { CustomLogger, AppLogger } from '@eqxjs/nest-logger';
128
+
129
+ @Injectable()
130
+ export class MyService {
131
+ constructor(
132
+ private readonly logger: CustomLogger,
133
+ private readonly appLogger: AppLogger,
134
+ ) {}
135
+
136
+ doSomething() {
137
+ this.logger.log('Simple log message', 'MyService');
138
+ this.logger.error('Error occurred', 'MyService');
139
+ }
140
+ }
141
+ ```
142
+
143
+ ## Message Protocol Data Structures
144
+
145
+ The logger supports three message protocols (M1, M2, M3), each with specific required properties:
146
+
147
+ ### DataM1I - Broker/Queue Messages
148
+
149
+ **Required Properties:**
150
+ - `header`: DataHeaderI - Message header with identity
151
+ - `protocol`: DataProtocolI - Protocol-specific information
152
+ - `body`: Record<string, unknown> - Message payload
153
+
154
+ ```typescript
155
+ import { DataM1I } from '@eqxjs/nest-logger';
156
+
157
+ const data: DataM1I = {
158
+ header: {
159
+ sessionId: 'session-123',
160
+ transactionId: 'txn-456',
161
+ broker: 'kafka',
162
+ channel: 'order-queue',
163
+ useCase: 'ProcessOrder',
164
+ identity: {
165
+ device: 'mobile-app',
166
+ user: 'user-123',
167
+ public: 'public-id'
168
+ }
169
+ },
170
+ protocol: {
171
+ topic: 'order.created',
172
+ command: 'PROCESS',
173
+ qos: '1'
174
+ },
175
+ body: {
176
+ orderId: '12345',
177
+ amount: 100.00
178
+ }
179
+ };
180
+ ```
181
+
182
+ ### DataM2I - HTTP/Protocol Messages
183
+
184
+ **Required Properties:**
185
+ - `header`: DataHeaderI - Message header with identity
186
+ - `body`: Record<string, unknown> - Message payload
187
+
188
+ **Optional Properties:**
189
+ - `protocol`: DataProtocolI - HTTP/protocol information
190
+
191
+ ```typescript
192
+ import { DataM2I } from '@eqxjs/nest-logger';
193
+
194
+ const data: DataM2I = {
195
+ header: {
196
+ sessionId: 'session-123',
197
+ transactionId: 'txn-456',
198
+ channel: 'web',
199
+ useCase: 'CreatePayment',
200
+ identity: {
201
+ user: 'user-123',
202
+ public: 'public-id'
203
+ }
204
+ },
205
+ body: {
206
+ paymentId: 'pay-123',
207
+ status: 'completed'
208
+ }
209
+ };
210
+ ```
211
+
212
+ ### DataM3I - Service/Database Messages
213
+
214
+ **Required Properties:**
215
+ - `service`: DataServiceI - Service-specific information with identity
216
+ - `body`: Record<string, unknown> - Message payload
217
+
218
+ **Optional Properties:**
219
+ - `header`: DataHeaderI - Message header with identity
220
+
221
+ ```typescript
222
+ import { DataM3I } from '@eqxjs/nest-logger';
223
+
224
+ const data: DataM3I = {
225
+ service: {
226
+ serviceName: 'PostgreSQL',
227
+ name: 'users-db',
228
+ invoke: 'SELECT',
229
+ identity: {
230
+ device: 'db-server-1',
231
+ user: 'db-user'
232
+ }
233
+ },
234
+ body: {
235
+ query: 'SELECT * FROM users WHERE id = $1',
236
+ resultCount: 1
237
+ }
238
+ };
239
+ ```
240
+
241
+ ### Identity Structure
242
+
243
+ All message types include an `identity` object with optional fields:
244
+
245
+ ```typescript
246
+ identity: {
247
+ device?: string | string[]; // Device identifier(s)
248
+ public?: string; // Public identifier
249
+ user?: string; // User identifier
250
+ }
251
+ ```
252
+
253
+ ## Usage Examples
254
+
255
+ ### Basic Logging
256
+
257
+ #### CustomLogger - Simple Logging
258
+
259
+ ```typescript
260
+ import { CustomLogger } from '@eqxjs/nest-logger';
261
+
262
+ export class UserService {
263
+ private readonly logger = new CustomLogger('UserService');
264
+
265
+ createUser(userData: any) {
266
+ this.logger.log('Creating new user');
267
+ this.logger.debug('User data received', 'UserService');
268
+ this.logger.warn('Deprecated API used', 'UserService');
269
+ this.logger.error('Failed to create user', 'UserService');
270
+ this.logger.verbose('Detailed processing info', 'UserService');
271
+ }
272
+ }
273
+ ```
274
+
275
+ ### Real-World Examples
276
+
277
+ #### Example 1: HTTP Request/Response Logging
278
+
279
+ ```typescript
280
+ import { Injectable } from '@nestjs/common';
281
+ import { AppLogger, ActionMessage, TimeDiff, DataM2I } from '@eqxjs/nest-logger';
282
+
283
+ @Injectable()
284
+ export class PaymentController {
285
+ private readonly logger = new AppLogger('PaymentAPI', 'PaymentController');
286
+
287
+ async processPayment(request: any) {
288
+ const timer = new TimeDiff();
289
+ const sessionId = request.headers['x-session-id'];
290
+ const transactionId = request.headers['x-transaction-id'];
291
+
292
+ const data: DataM2I = {
293
+ header: {
294
+ sessionId,
295
+ transactionId,
296
+ channel: 'web',
297
+ useCase: 'ProcessPayment',
298
+ identity: {},
299
+ },
300
+ body: {
301
+ amount: request.body.amount,
302
+ currency: request.body.currency,
303
+ },
304
+ };
305
+
306
+ // Log incoming request
307
+ this.logger.loggerM2.info(
308
+ 'api.payment',
309
+ ActionMessage.httpRequest(),
310
+ data,
311
+ `Payment request received: ${request.body.amount}`
312
+ );
313
+
314
+ try {
315
+ // Process payment logic...
316
+ const result = await this.executePayment(request.body);
317
+
318
+ // Log successful response
319
+ this.logger.loggerM2.summarySuccess(
320
+ 'api.payment',
321
+ 'Payment processed successfully',
322
+ '200',
323
+ timer.diff(),
324
+ data
325
+ );
326
+
327
+ return result;
328
+ } catch (error) {
329
+ // Log error response
330
+ this.logger.loggerM2.summaryError(
331
+ 'api.payment',
332
+ 'Payment processing failed',
333
+ '500',
334
+ timer.diff(),
335
+ data,
336
+ [error.stack]
337
+ );
338
+
339
+ throw error;
340
+ }
341
+ }
342
+ }
343
+ ```
344
+
345
+ #### Example 2: Kafka Message Consumer
346
+
347
+ ```typescript
348
+ import { Injectable } from '@nestjs/common';
349
+ import { AppLogger, ActionMessage, TimeDiff, DataM1I } from '@eqxjs/nest-logger';
350
+
351
+ @Injectable()
352
+ export class OrderConsumer {
353
+ private readonly logger = new AppLogger('OrderService', 'KafkaConsumer');
354
+
355
+ async consumeOrderMessage(message: any) {
356
+ const timer = new TimeDiff();
357
+
358
+ const data: DataM1I = {
359
+ header: {
360
+ sessionId: message.sessionId,
361
+ transactionId: message.transactionId,
362
+ broker: 'kafka',
363
+ channel: 'order-topic',
364
+ useCase: 'ProcessOrder',
365
+ useCaseStep: 'Consume',
366
+ identity: {},
367
+ },
368
+ protocol: {
369
+ topic: 'order.created',
370
+ command: 'CONSUME',
371
+ },
372
+ body: {
373
+ orderId: message.orderId,
374
+ customerId: message.customerId,
375
+ },
376
+ };
377
+
378
+ // Log message consumption start
379
+ this.logger.loggerM1.info(
380
+ 'order.created',
381
+ ActionMessage.consume(),
382
+ data,
383
+ `Consuming order message: ${message.orderId}`
384
+ );
385
+
386
+ try {
387
+ // Process the message
388
+ await this.processOrder(message);
389
+
390
+ // Log successful consumption
391
+ this.logger.loggerM1.info(
392
+ 'order.created',
393
+ ActionMessage.consumed(),
394
+ data,
395
+ `Order message consumed successfully`
396
+ );
397
+
398
+ this.logger.loggerM1.summarySuccess(
399
+ 'order.created',
400
+ 'Order processed',
401
+ '200',
402
+ timer.diff(),
403
+ data
404
+ );
405
+ } catch (error) {
406
+ // Log consumption failure
407
+ this.logger.loggerM1.error(
408
+ 'order.created',
409
+ ActionMessage.exception(),
410
+ data,
411
+ `Failed to consume order message: ${error.message}`
412
+ );
413
+
414
+ this.logger.loggerM1.summaryError(
415
+ 'order.created',
416
+ 'Order processing failed',
417
+ '500',
418
+ timer.diff(),
419
+ data,
420
+ [error.stack]
421
+ );
422
+
423
+ throw error;
424
+ }
425
+ }
426
+ }
427
+ ```
428
+
429
+ #### Example 3: Database Operations
430
+
431
+ ```typescript
432
+ import { Injectable } from '@nestjs/common';
433
+ import { AppLogger, ActionMessage, TimeDiff, DataM3I } from '@eqxjs/nest-logger';
434
+
435
+ @Injectable()
436
+ export class UserRepository {
437
+ private readonly logger = new AppLogger('UserService', 'UserRepository');
438
+
439
+ async findUserById(userId: string, sessionId: string, transactionId: string) {
440
+ const timer = new TimeDiff();
441
+
442
+ const data: DataM3I = {
443
+
444
+ service: {
445
+ serviceName: 'PostgreSQL',
446
+ invoke: 'SELECT',
447
+ name: 'users',
448
+ identity: {},
449
+ },
450
+ body: {
451
+ userId: userId,
452
+ operation: 'findById',
453
+ },
454
+ };
455
+
456
+ // Log database request
457
+ this.logger.loggerM3.debug(
458
+ 'db.users',
459
+ ActionMessage.dbRequest(),
460
+ data,
461
+ `Querying user by ID: ${userId}`
462
+ );
463
+
464
+ try {
465
+ const user = await this.executeQuery(`SELECT * FROM users WHERE id = $1`, [userId]);
466
+
467
+ // Log database response
468
+ this.logger.loggerM3.debug(
469
+ 'db.users',
470
+ ActionMessage.dbResponse(),
471
+ data,
472
+ `User found: ${user.email}`
473
+ );
474
+
475
+ this.logger.loggerM3.summarySuccess(
476
+ 'db.users',
477
+ 'User retrieved',
478
+ '200',
479
+ timer.diff(),
480
+ data
481
+ );
482
+
483
+ return user;
484
+ } catch (error) {
485
+ this.logger.loggerM3.summaryError(
486
+ 'db.users',
487
+ 'Database query failed',
488
+ '500',
489
+ timer.diff(),
490
+ data,
491
+ [error.stack]
492
+ );
493
+
494
+ throw error;
495
+ }
496
+ }
497
+ }
498
+ ```
499
+
500
+ #### Example 4: Microservice Communication
501
+
502
+ ```typescript
503
+ import { Injectable } from '@nestjs/common';
504
+ import { AppLogger, ActionMessage, TimeDiff, DataM3I } from '@eqxjs/nest-logger';
505
+
506
+ @Injectable()
507
+ export class NotificationService {
508
+ private readonly logger = new AppLogger('NotificationService', 'EmailClient');
509
+
510
+ async sendEmail(emailData: any, sessionId: string, transactionId: string) {
511
+ const timer = new TimeDiff();
512
+
513
+ const data: DataM3I = {
514
+ service: {
515
+ serviceName: 'EmailService',
516
+ operation: 'SEND',
517
+ endpoint: '/api/v1/email/send',
518
+ },
519
+ };
520
+
521
+ // Log outbound call
522
+ this.logger.loggerM3.info(
523
+ 'notification.email',
524
+ ActionMessage.outbound(),
525
+ data,
526
+ `Sending email to: ${emailData.recipient}`
527
+ );
528
+
529
+ try {
530
+ const response = await this.emailClient.send(emailData);
531
+
532
+ // Log successful response
533
+ this.logger.loggerM3.info(
534
+ 'notification.email',
535
+ ActionMessage.inbound(),
536
+ data,
537
+ `Email sent successfully`
538
+ );
539
+
540
+ this.logger.loggerM3.summarySuccess(
541
+ 'notification.email',
542
+ 'Email delivered',
543
+ '200',
544
+ timer.diff(),
545
+ data
546
+ );
547
+
548
+ return response;
549
+ } catch (error) {
550
+ this.logger.loggerM3.summaryError(
551
+ 'notification.email',
552
+ 'Email delivery failed',
553
+ '500',
554
+ timer.diff(),
555
+ data,
556
+ [error.stack]
557
+ );
558
+
559
+ throw error;
560
+ }
561
+ }
562
+ }
563
+ ```
564
+
565
+ #### Example 5: Business Logic with Comprehensive Logging
566
+
567
+ ```typescript
568
+ import { Injectable } from '@nestjs/common';
569
+ import {
570
+ AppLogger,
571
+ ActionMessage,
572
+ TimeDiff,
573
+ logStringify
574
+ } from '@eqxjs/nest-logger';
575
+
576
+ @Injectable()
577
+ export class OrderProcessingService {
578
+ private readonly logger = new AppLogger('OrderService', 'OrderProcessor');
579
+
580
+ async processOrder(orderData: any, sessionId: string, transactionId: string) {
581
+ const overallTimer = new TimeDiff();
582
+
583
+ // Log start of business logic
584
+ this.logger.app.info(
585
+ 'Starting order processing',
586
+ ActionMessage.appLogic(),
587
+ 'OrderProcessingService',
588
+ orderData.orderId,
589
+ sessionId,
590
+ transactionId,
591
+ orderData.channel,
592
+ '1.0.0',
593
+ 'ProcessOrder',
594
+ 'Start',
595
+ orderData.userId,
596
+ orderData.device
597
+ );
598
+
599
+ try {
600
+ // Step 1: Validate order
601
+ const validationTimer = new TimeDiff();
602
+ this.logger.app.debug(
603
+ 'Validating order data',
604
+ '[VALIDATION]',
605
+ 'OrderProcessingService',
606
+ orderData.orderId,
607
+ sessionId,
608
+ transactionId
609
+ );
610
+
611
+ await this.validateOrder(orderData);
612
+
613
+ this.logger.app.verbose(
614
+ `Order validation completed in ${validationTimer.diff()}ms`,
615
+ '[VALIDATION]'
616
+ );
617
+
618
+ // Step 2: Check inventory
619
+ const inventoryTimer = new TimeDiff();
620
+ this.logger.app.debug(
621
+ 'Checking inventory availability',
622
+ '[INVENTORY_CHECK]',
623
+ 'OrderProcessingService',
624
+ orderData.orderId,
625
+ sessionId,
626
+ transactionId
627
+ );
628
+
629
+ const inventory = await this.checkInventory(orderData.items);
630
+
631
+ this.logger.app.info(
632
+ `Inventory checked: ${logStringify(inventory)}`,
633
+ '[INVENTORY_CHECK]',
634
+ 'OrderProcessingService',
635
+ orderData.orderId
636
+ );
637
+
638
+ // Step 3: Process payment
639
+ const paymentTimer = new TimeDiff();
640
+ this.logger.app.info(
641
+ 'Processing payment',
642
+ '[PAYMENT]',
643
+ 'OrderProcessingService',
644
+ orderData.orderId,
645
+ sessionId,
646
+ transactionId
647
+ );
648
+
649
+ const payment = await this.processPayment(orderData.payment);
650
+
651
+ this.logger.app.info(
652
+ 'Payment processed successfully',
653
+ '[PAYMENT]',
654
+ 'OrderProcessingService',
655
+ orderData.orderId
656
+ );
657
+
658
+ // Step 4: Create order
659
+ this.logger.app.info(
660
+ 'Creating order record',
661
+ '[ORDER_CREATE]',
662
+ 'OrderProcessingService',
663
+ orderData.orderId,
664
+ sessionId,
665
+ transactionId
666
+ );
667
+
668
+ const order = await this.createOrder(orderData, payment);
669
+
670
+ // Log final success summary with telemetry
671
+ this.logger.app.summarySuccess(
672
+ 'Order processed successfully',
673
+ '200',
674
+ overallTimer.diff(),
675
+ 'OrderProcessingService',
676
+ orderData.orderId,
677
+ sessionId,
678
+ transactionId,
679
+ orderData.channel,
680
+ '1.0.0',
681
+ 'ProcessOrder',
682
+ 'Complete',
683
+ orderData.userId,
684
+ orderData.device,
685
+ order.publicId
686
+ );
687
+
688
+ return order;
689
+
690
+ } catch (error) {
691
+ // Log detailed error with context
692
+ this.logger.app.error(
693
+ `Order processing failed: ${error.message}`,
694
+ ActionMessage.exception(),
695
+ 'OrderProcessingService',
696
+ orderData.orderId,
697
+ sessionId,
698
+ transactionId
699
+ );
700
+
701
+ // Log error summary with telemetry
702
+ this.logger.app.summaryError(
703
+ 'Order processing failed',
704
+ error.code || '500',
705
+ overallTimer.diff(),
706
+ 'OrderProcessingService',
707
+ orderData.orderId,
708
+ sessionId,
709
+ transactionId,
710
+ orderData.channel,
711
+ '1.0.0',
712
+ 'ProcessOrder',
713
+ 'Failed',
714
+ orderData.userId,
715
+ orderData.device,
716
+ undefined,
717
+ [error.stack]
718
+ );
719
+
720
+ throw error;
721
+ }
722
+ }
723
+ }
724
+ ```
725
+
726
+ ### Advanced Logging with AppLogger
727
+
728
+ #### BaseAppLogger - Structured Logging
729
+
730
+ ```typescript
731
+ import { AppLogger } from '@eqxjs/nest-logger';
732
+
733
+ export class PaymentService {
734
+ private readonly logger = new AppLogger('PaymentService', 'PaymentContext');
735
+
736
+ processPayment(paymentData: any) {
737
+ // Detailed structured log
738
+ this.logger.app.info(
739
+ 'Processing payment',
740
+ '[PAYMENT_PROCESSING]',
741
+ 'PaymentService',
742
+ 'payment-record-123',
743
+ 'session-456',
744
+ 'txn-789',
745
+ 'mobile-app',
746
+ '1.0.0',
747
+ 'ProcessPayment',
748
+ 'Validation',
749
+ 'user@example.com',
750
+ ['mobile', 'ios'],
751
+ 'public-id-123'
752
+ );
753
+ }
754
+ }
755
+ ```
756
+
757
+ #### Summary Logging with Telemetry
758
+
759
+ ```typescript
760
+ import { AppLogger, TimeDiff } from '@eqxjs/nest-logger';
761
+
762
+ export class OrderService {
763
+ private readonly logger = new AppLogger('OrderService');
764
+
765
+ async createOrder(orderData: any) {
766
+ const timer = new TimeDiff();
767
+
768
+ try {
769
+ // Process order...
770
+ const result = await this.processOrder(orderData);
771
+
772
+ // Log success with metrics
773
+ this.logger.app.summarySuccess(
774
+ 'Order created successfully',
775
+ '200',
776
+ timer.diff(),
777
+ 'OrderService',
778
+ 'order-123',
779
+ 'session-456',
780
+ 'txn-789',
781
+ 'web',
782
+ '2.0.0',
783
+ 'CreateOrder',
784
+ 'Complete'
785
+ );
786
+
787
+ return result;
788
+ } catch (error) {
789
+ // Log error with stack trace
790
+ this.logger.app.summaryError(
791
+ 'Order creation failed',
792
+ '500',
793
+ timer.diff(),
794
+ 'OrderService',
795
+ 'order-123',
796
+ 'session-456',
797
+ 'txn-789',
798
+ 'web',
799
+ '2.0.0',
800
+ 'CreateOrder',
801
+ 'Failed',
802
+ undefined,
803
+ undefined,
804
+ [error.stack]
805
+ );
806
+
807
+ throw error;
808
+ }
809
+ }
810
+ }
811
+ ```
812
+
813
+ ### Message Format Loggers (M1, M2, M3)
814
+
815
+ #### M1 Message Format
816
+
817
+ ```typescript
818
+ import { AppLogger } from '@eqxjs/nest-logger';
819
+ import { DataM1I } from '@eqxjs/nest-logger';
820
+
821
+ export class KafkaConsumerService {
822
+ private readonly logger = new AppLogger('KafkaConsumer');
823
+
824
+ consumeMessage(message: any) {
825
+ const data: DataM1I = {
826
+ header: {
827
+ sessionId: 'session-123',
828
+ transactionId: 'txn-456',
829
+ broker: 'kafka',
830
+ channel: 'queue',
831
+ useCase: 'MessageProcessing',
832
+ identity: {},
833
+ },
834
+ protocol: {
835
+ topic: 'payment.topic',
836
+ command: 'PROCESS',
837
+ },
838
+ body: {
839
+ messageId: message.id,
840
+ payload: message.data,
841
+ },
842
+ };
843
+
844
+ // Log with M1 format
845
+ this.logger.loggerM1.info(
846
+ 'payment.topic',
847
+ '[CONSUMING]',
848
+ data,
849
+ 'Processing payment message'
850
+ );
851
+
852
+ // Summary for M1
853
+ this.logger.loggerM1.summarySuccess(
854
+ 'payment.topic',
855
+ 'Message processed',
856
+ '200',
857
+ 150,
858
+ data
859
+ );
860
+ }
861
+ }
862
+ ```
863
+
864
+ #### M2 Message Format
865
+
866
+ ```typescript
867
+ import { AppLogger } from '@eqxjs/nest-logger';
868
+ import { DataM2I } from '@eqxjs/nest-logger';
869
+
870
+ export class HttpService {
871
+ private readonly logger = new AppLogger('HttpService');
872
+
873
+ handleRequest(req: any) {
874
+ const data: DataM2I = {
875
+ header: {
876
+ sessionId: req.sessionId,
877
+ transactionId: req.transactionId,
878
+ identity: {},
879
+ },
880
+ protocol: {
881
+ requestId: req.id,
882
+ method: req.method,
883
+ path: req.path,
884
+ },
885
+ body: {
886
+ endpoint: req.path,
887
+ params: req.params,
888
+ },
889
+ };
890
+
891
+ this.logger.loggerM2.info(
892
+ 'api.endpoint',
893
+ '[HTTP_REQUEST]',
894
+ data,
895
+ 'Incoming HTTP request'
896
+ );
897
+ }
898
+ }
899
+ ```
900
+
901
+ #### M3 Message Format
902
+
903
+ ```typescript
904
+ import { AppLogger } from '@eqxjs/nest-logger';
905
+ import { DataM3I } from '@eqxjs/nest-logger';
906
+
907
+ export class DatabaseService {
908
+ private readonly logger = new AppLogger('DatabaseService');
909
+
910
+ queryDatabase(query: string) {
911
+ const data: DataM3I = {
912
+ header: {
913
+ sessionId: 'session-123',
914
+ transactionId: 'txn-456',
915
+ identity: {},
916
+ },
917
+ service: {
918
+ serviceName: 'PostgreSQL',
919
+ invoke: 'SELECT',
920
+ name: 'users',
921
+ identity: {},
922
+ },
923
+ body: {
924
+ query: query,
925
+ database: 'users_db',
926
+ },
927
+ };
928
+
929
+ this.logger.loggerM3.debug(
930
+ 'db.query',
931
+ '[DB_REQUEST]',
932
+ data,
933
+ `Executing query: ${query}`
934
+ );
935
+ }
936
+ }
937
+ ```
938
+
939
+ ### Utility Functions
940
+
941
+ #### Time Performance Measurement
942
+
943
+ ```typescript
944
+ import { TimeDiff } from '@eqxjs/nest-logger';
945
+
946
+ export class PerformanceService {
947
+ async trackOperation() {
948
+ const timer = new TimeDiff();
949
+
950
+ // Perform operation
951
+ await this.heavyOperation();
952
+
953
+ const duration = timer.diff(); // Returns time in milliseconds
954
+ console.log(`Operation took ${duration}ms`);
955
+ }
956
+ }
957
+ ```
958
+
959
+ #### Date Formatting
960
+
961
+ ```typescript
962
+ import { dateFormat } from '@eqxjs/nest-logger';
963
+
964
+ const timestamp = dateFormat(); // Returns: "2026-01-12T10:30:00.000Z"
965
+ ```
966
+
967
+ #### Action Message Constants
968
+
969
+ ```typescript
970
+ import { ActionMessage } from '@eqxjs/nest-logger';
971
+
972
+ // Use predefined action tags
973
+ console.log(ActionMessage.consume()); // [CONSUMING]
974
+ console.log(ActionMessage.consumed()); // [CONSUMED]
975
+ console.log(ActionMessage.produce()); // [PRODUCING]
976
+ console.log(ActionMessage.produced()); // [PRODUCED]
977
+ console.log(ActionMessage.httpRequest()); // [HTTP_REQUEST]
978
+ console.log(ActionMessage.httpResponse()); // [HTTP_RESPONSE]
979
+ console.log(ActionMessage.wsRecv()); // [WS_RECEIVED]
980
+ console.log(ActionMessage.wsSent()); // [WS_SENT]
981
+ console.log(ActionMessage.dbRequest()); // [DB_REQUEST]
982
+ console.log(ActionMessage.dbResponse()); // [DB_RESPONSE]
983
+ console.log(ActionMessage.appLogic()); // [APP_LOGIC]
984
+ console.log(ActionMessage.inbound()); // [INBOUND]
985
+ console.log(ActionMessage.outbound()); // [OUTBOUND]
986
+ console.log(ActionMessage.exception()); // [EXCEPTION]
987
+ ```
988
+
989
+ #### Additional Helper Functions
990
+
991
+ **Log Level Checking**
992
+
993
+ ```typescript
994
+ import { isLevelEnable } from '@eqxjs/nest-logger';
995
+
996
+ process.env.LOG_LEVEL = 'info,error';
997
+
998
+ if (isLevelEnable('debug')) {
999
+ // This won't execute
1000
+ console.log('Debug is enabled');
1001
+ }
1002
+
1003
+ if (isLevelEnable('info')) {
1004
+ // This will execute
1005
+ console.log('Info is enabled');
1006
+ }
1007
+ ```
1008
+
1009
+ **Message Masking**
1010
+
1011
+ ```typescript
1012
+ import { maskMessageReplacer, logStringify } from '@eqxjs/nest-logger';
1013
+
1014
+ process.env.LOG_MASK_KEYS = 'password,apiKey,token';
1015
+
1016
+ const sensitiveData = {
1017
+ username: 'john',
1018
+ password: 'secret123',
1019
+ apiKey: 'abc-def-ghi',
1020
+ email: 'john@example.com'
1021
+ };
1022
+
1023
+ // Stringify with automatic masking
1024
+ const masked = logStringify(sensitiveData);
1025
+ console.log(masked);
1026
+ // Output: {"username":"john","password":"*****","apiKey":"*****","email":"john@example.com"}
1027
+
1028
+ // Use replacer function directly with JSON.stringify
1029
+ const manualMask = JSON.stringify(sensitiveData, maskMessageReplacer);
1030
+ ```
1031
+
1032
+ ## Configuration
1033
+
1034
+ ### Environment Variables
1035
+
1036
+ Configure the logger behavior using these environment variables:
1037
+
1038
+ | Variable | Type | Default | Description |
1039
+ |----------|------|---------|-------------|
1040
+ | `LOG_LEVEL` | string | - | Comma-separated list of enabled log levels: `debug,info,log,warn,error,verbose` |
1041
+ | `LOG_MASK_KEYS` | string | - | Comma-separated list of field names to mask (e.g., `password,token,apiKey,secret`) |
1042
+ | `APP_VERSION` | string | - | Application version included in telemetry and logs |
1043
+ | `DESTINATION` | string | - | Deployment destination/environment name |
1044
+ | `TELEMETRY_IGNORE_CODE` | string | - | Comma-separated list of result codes to exclude from telemetry metrics |
1045
+
1046
+ **Example Configuration:**
1047
+
1048
+ ```bash
1049
+ # .env file
1050
+ LOG_LEVEL=debug,info,warn,error,verbose
1051
+ LOG_MASK_KEYS=password,secret,token,apiKey,creditCard,ssn
1052
+ APP_VERSION=1.0.0
1053
+ DESTINATION=production
1054
+ TELEMETRY_IGNORE_CODE=404,401,403
1055
+ ```
1056
+
1057
+ ### Log Level Filtering
1058
+
1059
+ Control which log levels are output by configuring the `LOG_LEVEL` environment variable:
1060
+
1061
+ ```typescript
1062
+ // Only logs matching the LOG_LEVEL env var will be output
1063
+ process.env.LOG_LEVEL = 'info,error';
1064
+
1065
+ logger.debug('This will NOT be logged');
1066
+ logger.info('This WILL be logged');
1067
+ logger.error('This WILL be logged');
1068
+ logger.verbose('This will NOT be logged');
1069
+ ```
1070
+
1071
+ ### Sensitive Data Masking
1072
+
1073
+ Protect sensitive information by automatically masking specified fields:
1074
+
1075
+ ```typescript
1076
+ // Set masked fields via environment
1077
+ process.env.LOG_MASK_KEYS = 'password,creditCard,ssn,token';
1078
+
1079
+ const userData = {
1080
+ username: 'john',
1081
+ password: 'secret123',
1082
+ creditCard: '4111-1111-1111-1111',
1083
+ email: 'john@example.com',
1084
+ token: 'abc-def-123'
1085
+ };
1086
+
1087
+ logger.log(userData);
1088
+ // Output: { username: 'john', password: '*****', creditCard: '*****', email: 'john@example.com', token: '*****' }
1089
+ ```
1090
+
1091
+ ### Telemetry Filtering
1092
+
1093
+ Exclude specific result codes from telemetry metrics to reduce noise:
1094
+
1095
+ ```typescript
1096
+ // Don't track 404 and 401 errors in telemetry
1097
+ process.env.TELEMETRY_IGNORE_CODE = '404,401';
1098
+
1099
+ // These won't be recorded in OpenTelemetry metrics
1100
+ logger.app.summaryError('Not found', '404', 100);
1101
+ logger.app.summaryError('Unauthorized', '401', 50);
1102
+
1103
+ // This will be recorded
1104
+ logger.app.summaryError('Server error', '500', 200);
1105
+ ```
1106
+
1107
+ ### Message Truncation
1108
+
1109
+ Long messages are automatically truncated to prevent log overflow:
1110
+
1111
+ ```typescript
1112
+ // Messages longer than 4096 characters are truncated
1113
+ const longMessage = 'a'.repeat(5000);
1114
+ logger.info(longMessage);
1115
+ // Logged message will be truncated to 4096 chars + '...'
1116
+
1117
+ // The limit is defined in DEFAULT_VALUES.MAX_MESSAGE_LENGTH
1118
+ import { DEFAULT_VALUES } from '@eqxjs/nest-logger';
1119
+ console.log(DEFAULT_VALUES.MAX_MESSAGE_LENGTH); // 4096
1120
+ ```
1121
+
1122
+ ## OpenTelemetry Integration
1123
+
1124
+ The logger automatically integrates with OpenTelemetry for metrics, tracing, and logs:
1125
+
1126
+ ### Metrics Collected
1127
+
1128
+ - **Counter**: `total_request` - Total number of operations
1129
+ - **Histogram**: `latency` - Operation duration in milliseconds
1130
+
1131
+ ### Span Attributes
1132
+
1133
+ - `application.code` - Result code
1134
+ - `application.success` - Operation success status
1135
+ - `application.duration` - Processing time
1136
+ - `application.time` - Timestamp
1137
+ - `application.source` - Originating service
1138
+ - `application.stack` - Error stack trace (if applicable)
1139
+
1140
+ ### Logs API Integration
1141
+
1142
+ Starting from v3.1.0, summary logs are automatically pushed to OpenTelemetry Logs API with structured attributes:
1143
+
1144
+ **Log Record Attributes:**
1145
+ - `log.type` - Type of log (summary)
1146
+ - `app.result` - Result description
1147
+ - `app.result.code` - Result code
1148
+ - `service.time` - Service processing time (ms)
1149
+ - `originate.service.name` - Source service name
1150
+ - `record.name` - Record identifier
1151
+ - `session.id` - Session identifier
1152
+ - `transaction.id` - Transaction identifier
1153
+ - `channel` - Communication channel
1154
+ - `use.case` - Use case name
1155
+ - `use.case.step` - Use case step
1156
+ - `user` - User identifier
1157
+ - `device` - Device identifier(s)
1158
+ - `instance` - Instance/hostname
1159
+ - `component.name` - Component name
1160
+ - `component.version` - Component version
1161
+ - `stack` - Error stack trace (included only for summaryError calls)
1162
+
1163
+ **Severity Levels:**
1164
+ - `SeverityNumber.INFO` - For summarySuccess calls
1165
+ - `SeverityNumber.ERROR` - For summaryError calls
1166
+
1167
+ ### Example with Telemetry
1168
+
1169
+ ```typescript
1170
+ // Summary methods automatically record telemetry
1171
+ this.logger.app.summarySuccess(
1172
+ 'Operation completed',
1173
+ '200',
1174
+ 150, // Service time in ms
1175
+ 'UserService',
1176
+ 'record-123'
1177
+ );
1178
+
1179
+ // This will:
1180
+ // 1. Log the summary to Winston
1181
+ // 2. Push log to OpenTelemetry Logs API
1182
+ // 3. Increment the counter metric
1183
+ // 4. Record histogram metric
1184
+ // 5. Create a span with attributes
1185
+ ```
1186
+
1187
+ ## API Reference
1188
+
1189
+ ### CustomLogger
1190
+
1191
+ Basic logger with standard log levels. Extends Winston logger functionality.
1192
+
1193
+ **Constructor:**
1194
+ ```typescript
1195
+ new CustomLogger(context?: string)
1196
+ ```
1197
+
1198
+ **Methods:**
1199
+ - `log(message: any, context?: string): void` - Info level logging
1200
+ - `error(message: any, trace?: string, context?: string): void` - Error level logging
1201
+ - `warn(message: any, context?: string): void` - Warning level logging
1202
+ - `debug(message: any, context?: string): void` - Debug level logging
1203
+ - `verbose(message: any, context?: string): void` - Verbose level logging
1204
+
1205
+ **Example:**
1206
+ ```typescript
1207
+ const logger = new CustomLogger('MyService');
1208
+ logger.log('Application started');
1209
+ logger.debug('Debug information');
1210
+ logger.warn('Warning message');
1211
+ logger.error('Error occurred', 'stack trace');
1212
+ logger.verbose('Detailed verbose log');
1213
+ ```
1214
+
1215
+ ### BaseAppLogger
1216
+
1217
+ Advanced logger with structured logging and OpenTelemetry integration.
1218
+
1219
+ **Constructor:**
1220
+ ```typescript
1221
+ new BaseAppLogger(appName?: string, context?: string)
1222
+ ```
1223
+
1224
+ **All Parameters (for logging methods):**
1225
+ - `message: any` - The log message (required)
1226
+ - `action?: string` - Action tag (default: 'none')
1227
+ - `originateServiceName?: string` - Source service (default: 'none')
1228
+ - `recordName?: string` - Record identifier (default: 'none')
1229
+ - `sessionId?: string` - Session ID (default: 'none')
1230
+ - `transactionId?: string` - Transaction ID (default: 'none')
1231
+ - `channel?: string` - Channel identifier (default: 'none')
1232
+ - `componentVersion?: string` - Component version (default: 'none')
1233
+ - `useCase?: string` - Use case name (default: 'none')
1234
+ - `useCaseStep?: string` - Use case step (default: 'none')
1235
+ - `user?: string` - User identifier (default: 'none')
1236
+ - `device?: string | string[]` - Device identifier(s) (default: 'none')
1237
+ - `public_?: string` - Public identifier (default: 'none')
1238
+ - `opt?: LoggerOpt` - Optional configuration object
1239
+
1240
+ **Logging Methods:**
1241
+ ```typescript
1242
+ debug(message, action?, ...): void
1243
+ info(message, action?, ...): void
1244
+ log(message, action?, ...): void // Alias for info()
1245
+ warn(message, action?, ...): void
1246
+ error(message, action?, ...): void
1247
+ verbose(message, action?, ...): void
1248
+ ```
1249
+
1250
+ **Summary Methods:**
1251
+ ```typescript
1252
+ summarySuccess(
1253
+ appResult?: string,
1254
+ appResultCode?: string,
1255
+ serviceTime?: number,
1256
+ originateServiceName?: string,
1257
+ recordName?: string,
1258
+ sessionId?: string,
1259
+ transactionId?: string,
1260
+ channel?: string,
1261
+ componentVersion?: string,
1262
+ useCase?: string,
1263
+ useCaseStep?: string,
1264
+ user?: string,
1265
+ device?: string | string[],
1266
+ public_?: string,
1267
+ opt?: LoggerOpt
1268
+ ): LoggerDto
1269
+
1270
+ summaryError(
1271
+ appResult?: string,
1272
+ appResultCode?: string,
1273
+ serviceTime?: number,
1274
+ originateServiceName?: string,
1275
+ recordName?: string,
1276
+ sessionId?: string,
1277
+ transactionId?: string,
1278
+ channel?: string,
1279
+ componentVersion?: string,
1280
+ useCase?: string,
1281
+ useCaseStep?: string,
1282
+ user?: string,
1283
+ device?: string | string[],
1284
+ public_?: string,
1285
+ stack?: string[],
1286
+ opt?: LoggerOpt
1287
+ ): LoggerDto
1288
+ ```
1289
+
1290
+ **Example:**
1291
+ ```typescript
1292
+ const logger = new BaseAppLogger('MyApp', 'MyContext');
1293
+
1294
+ // Simple logging
1295
+ logger.info('User logged in', '[USER_LOGIN]');
1296
+
1297
+ // Full structured logging
1298
+ logger.info(
1299
+ 'Payment processed',
1300
+ '[PAYMENT_SUCCESS]',
1301
+ 'PaymentService',
1302
+ 'pay-123',
1303
+ 'sess-456',
1304
+ 'txn-789',
1305
+ 'mobile',
1306
+ '1.0.0',
1307
+ 'ProcessPayment',
1308
+ 'Complete',
1309
+ 'user@example.com',
1310
+ ['mobile', 'android'],
1311
+ 'public-ref-123'
1312
+ );
1313
+
1314
+ // Summary with telemetry
1315
+ logger.summarySuccess('Success', '200', 150, 'PaymentService', 'pay-123');
1316
+ logger.summaryError('Failed', '500', 200, 'PaymentService', 'pay-123', undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, ['Error stack']);
1317
+ ```
1318
+
1319
+ ### AppLogger
1320
+
1321
+ Wrapper class providing access to all logger types (app, M1, M2, M3).
1322
+
1323
+ **Constructor:**
1324
+ ```typescript
1325
+ new AppLogger(appName?: string, context?: string)
1326
+ ```
1327
+
1328
+ **Properties:**
1329
+ - `app: BaseAppLogger` - Standard structured logger
1330
+ - `loggerM1: LoggerFormat` - M1 message format logger
1331
+ - `loggerM2: LoggerFormat` - M2 message format logger
1332
+ - `loggerM3: LoggerFormat` - M3 message format logger
1333
+
1334
+ **Example:**
1335
+ ```typescript
1336
+ const logger = new AppLogger('MyApp');
1337
+
1338
+ // Use standard logger
1339
+ logger.app.info('Standard log');
1340
+
1341
+ // Use M1 format
1342
+ logger.loggerM1.info('topic', '[ACTION]', dataM1, 'Message');
1343
+
1344
+ // Use M2 format
1345
+ logger.loggerM2.info('topic', '[ACTION]', dataM2, 'Message');
1346
+
1347
+ // Use M3 format
1348
+ logger.loggerM3.info('topic', '[ACTION]', dataM3, 'Message');
1349
+ ```
1350
+
1351
+ ### LoggerFormat (M1/M2/M3)
1352
+
1353
+ Format-specific loggers for different message protocols.
1354
+
1355
+ **Constructor:**
1356
+ ```typescript
1357
+ new LoggerFormat(baseAppLogger: BaseAppLogger, messageType: 'M1' | 'M2' | 'M3')
1358
+ ```
1359
+
1360
+ **Logging Methods:**
1361
+ ```typescript
1362
+ debug(topic: string, action: string, data: DataM1I | DataM2I | DataM3I, message?: string, opt?: LoggerOpt): void
1363
+ info(topic: string, action: string, data: DataM1I | DataM2I | DataM3I, message?: string, opt?: LoggerOpt): void
1364
+ log(topic: string, action: string, data: DataM1I | DataM2I | DataM3I, message?: string, opt?: LoggerOpt): void
1365
+ error(topic: string, action: string, data: DataM1I | DataM2I | DataM3I, message?: string, opt?: LoggerOpt): void
1366
+ warn(topic: string, action: string, data: DataM1I | DataM2I | DataM3I, message?: string, opt?: LoggerOpt): void
1367
+ verbose(topic: string, action: string, data: DataM1I | DataM2I | DataM3I, message?: string, opt?: LoggerOpt): void
1368
+ ```
1369
+
1370
+ **Summary Methods:**
1371
+ ```typescript
1372
+ summarySuccess(
1373
+ topic: string,
1374
+ appResult: string,
1375
+ appResultCode: string,
1376
+ serviceTime: number,
1377
+ data: DataM1I | DataM2I | DataM3I,
1378
+ opt?: LoggerOpt
1379
+ ): LoggerDto
1380
+
1381
+ summaryError(
1382
+ topic: string,
1383
+ appResult: string,
1384
+ appResultCode: string,
1385
+ serviceTime: number,
1386
+ data: DataM1I | DataM2I | DataM3I,
1387
+ stack?: string[],
1388
+ opt?: LoggerOpt
1389
+ ): LoggerDto
1390
+ ```
1391
+
1392
+ **Example:**
1393
+ ```typescript
1394
+ import { AppLogger, DataM1I } from '@eqxjs/nest-logger';
1395
+
1396
+ const logger = new AppLogger('KafkaService');
1397
+ const data: DataM1I = {
1398
+ header: {
1399
+ sessionId: 'sess-123',
1400
+ transactionId: 'txn-456',
1401
+ broker: 'kafka'
1402
+ }
1403
+ };
1404
+
1405
+ // M1 format logging
1406
+ logger.loggerM1.info('payment.topic', '[CONSUMING]', data, 'Processing message');
1407
+ logger.loggerM1.summarySuccess('payment.topic', 'Success', '200', 150, data);
1408
+ ```
1409
+
1410
+ ### Utility Classes and Functions
1411
+
1412
+ #### TimeDiff
1413
+
1414
+ Measures time elapsed using high-resolution timer.
1415
+
1416
+ **Constructor:**
1417
+ ```typescript
1418
+ new TimeDiff()
1419
+ ```
1420
+
1421
+ **Methods:**
1422
+ - `diff(): number` - Returns elapsed time in milliseconds
1423
+
1424
+ **Example:**
1425
+ ```typescript
1426
+ import { TimeDiff } from '@eqxjs/nest-logger';
1427
+
1428
+ const timer = new TimeDiff();
1429
+ await someAsyncOperation();
1430
+ const duration = timer.diff();
1431
+ console.log(`Operation took ${duration}ms`);
1432
+ ```
1433
+
1434
+ #### ActionMessage
1435
+
1436
+ Static class providing predefined action tags for consistent logging.
1437
+
1438
+ **Static Methods:**
1439
+ - `consume(): string` - Returns `[CONSUMING]`
1440
+ - `consumed(): string` - Returns `[CONSUMED]`
1441
+ - `produce(): string` - Returns `[PRODUCING]`
1442
+ - `produced(): string` - Returns `[PRODUCED]`
1443
+ - `httpRequest(): string` - Returns `[HTTP_REQUEST]`
1444
+ - `httpResponse(): string` - Returns `[HTTP_RESPONSE]`
1445
+ - `wsRecv(): string` - Returns `[WS_RECEIVED]`
1446
+ - `wsSent(): string` - Returns `[WS_SENT]`
1447
+ - `dbRequest(): string` - Returns `[DB_REQUEST]`
1448
+ - `dbResponse(): string` - Returns `[DB_RESPONSE]`
1449
+ - `appLogic(): string` - Returns `[APP_LOGIC]`
1450
+ - `inbound(): string` - Returns `[INBOUND]`
1451
+ - `outbound(): string` - Returns `[OUTBOUND]`
1452
+ - `exception(): string` - Returns `[EXCEPTION]`
1453
+
1454
+ **Example:**
1455
+ ```typescript
1456
+ import { ActionMessage } from '@eqxjs/nest-logger';
1457
+
1458
+ logger.info('Consuming message', ActionMessage.consume());
1459
+ logger.info('Message consumed', ActionMessage.consumed());
1460
+ logger.info('HTTP request received', ActionMessage.httpRequest());
1461
+ ```
1462
+
1463
+ #### Helper Functions
1464
+
1465
+ **dateFormat()**
1466
+
1467
+ Returns current timestamp in ISO 8601 format.
1468
+
1469
+ ```typescript
1470
+ import { dateFormat } from '@eqxjs/nest-logger';
1471
+
1472
+ const timestamp = dateFormat();
1473
+ console.log(timestamp); // "2026-01-12T10:30:00.000Z"
1474
+ ```
1475
+
1476
+ **isLevelEnable(level: string): boolean**
1477
+
1478
+ Checks if a log level is enabled based on `LOG_LEVEL` environment variable.
1479
+
1480
+ ```typescript
1481
+ import { isLevelEnable } from '@eqxjs/nest-logger';
1482
+
1483
+ process.env.LOG_LEVEL = 'info,error';
1484
+
1485
+ if (isLevelEnable('debug')) {
1486
+ // Won't execute
1487
+ }
1488
+
1489
+ if (isLevelEnable('info')) {
1490
+ // Will execute
1491
+ }
1492
+ ```
1493
+
1494
+ **logStringify(message: any): string**
1495
+
1496
+ Converts any value to string with automatic sensitive data masking.
1497
+
1498
+ ```typescript
1499
+ import { logStringify } from '@eqxjs/nest-logger';
1500
+
1501
+ process.env.LOG_MASK_KEYS = 'password,token';
1502
+
1503
+ const data = { username: 'john', password: 'secret' };
1504
+ const masked = logStringify(data);
1505
+ console.log(masked); // {"username":"john","password":"*****"}
1506
+ ```
1507
+
1508
+ **maskMessageReplacer(key: string, value: any): any**
1509
+
1510
+ JSON replacer function for masking sensitive fields.
1511
+
1512
+ ```typescript
1513
+ import { maskMessageReplacer } from '@eqxjs/nest-logger';
1514
+
1515
+ process.env.LOG_MASK_KEYS = 'apiKey,secret';
1516
+
1517
+ const data = { apiKey: 'abc123', name: 'John' };
1518
+ const masked = JSON.stringify(data, maskMessageReplacer);
1519
+ console.log(masked); // {"apiKey":"*****","name":"John"}
1520
+ ```
1521
+
1522
+ ### Interfaces
1523
+
1524
+ #### DataM1I
1525
+
1526
+ Message format for broker/queue operations.
1527
+
1528
+ ```typescript
1529
+ interface DataM1I {
1530
+ header: DataHeaderI;
1531
+ }
1532
+ ```
1533
+
1534
+ #### DataM2I
1535
+
1536
+ Message format for HTTP/protocol operations.
1537
+
1538
+ ```typescript
1539
+ interface DataM2I {
1540
+ header: DataHeaderI;
1541
+ protocol: DataProtocolI;
1542
+ }
1543
+ ```
1544
+
1545
+ #### DataM3I
1546
+
1547
+ Message format for service-to-service operations.
1548
+
1549
+ ```typescript
1550
+ interface DataM3I {
1551
+ header: DataHeaderI;
1552
+ service: DataServiceI;
1553
+ }
1554
+ ```
1555
+
1556
+ #### DataHeaderI
1557
+
1558
+ Common header fields for all message formats.
1559
+
1560
+ ```typescript
1561
+ interface DataHeaderI {
1562
+ sessionId?: string;
1563
+ transactionId?: string;
1564
+ broker?: string;
1565
+ channel?: string;
1566
+ useCase?: string;
1567
+ useCaseStep?: string;
1568
+ [key: string]: unknown;
1569
+ }
1570
+ ```
1571
+
1572
+ #### LoggerOpt
1573
+
1574
+ Optional configuration for logging.
1575
+
1576
+ ```typescript
1577
+ interface LoggerOpt {
1578
+ broker?: string;
1579
+ [key: string]: unknown;
1580
+ }
1581
+ ```
1582
+
1583
+ #### LoggerDto
1584
+
1585
+ Data transfer object for log entries.
1586
+
1587
+ ```typescript
1588
+ class LoggerDto {
1589
+ level?: string;
1590
+ timestamp?: string;
1591
+ message?: string;
1592
+ action?: string;
1593
+ componentName?: string;
1594
+ appName?: string;
1595
+ // ... and many more fields
1596
+ }
1597
+ ```
1598
+
1599
+ ## Best Practices
1600
+
1601
+ ### 1. Choose the Right Logger
1602
+
1603
+ ```typescript
1604
+ // For simple applications - use CustomLogger
1605
+ const logger = new CustomLogger('MyApp');
1606
+ logger.log('Simple message');
1607
+
1608
+ // For structured logging - use BaseAppLogger
1609
+ const appLogger = new BaseAppLogger('MyApp', 'UserService');
1610
+ appLogger.info('User action', '[USER_CREATE]');
1611
+
1612
+ // For multiple formats - use AppLogger
1613
+ const multiLogger = new AppLogger('MyApp');
1614
+ multiLogger.app.info('Standard log');
1615
+ multiLogger.loggerM1.info('kafka.topic', '[CONSUMING]', data);
1616
+ ```
1617
+
1618
+ ### 2. Use Appropriate Log Levels
1619
+
1620
+ Choose the right level based on the situation:
1621
+
1622
+ ```typescript
1623
+ // DEBUG - Detailed diagnostic information (development only)
1624
+ logger.debug('Request payload:', { userId: 123, action: 'create' });
1625
+
1626
+ // INFO - General informational messages (normal operations)
1627
+ logger.info('User logged in successfully', '[USER_LOGIN]');
1628
+
1629
+ // WARN - Potentially harmful situations (recoverable issues)
1630
+ logger.warn('API rate limit approaching 80%', '[RATE_LIMIT]');
1631
+
1632
+ // ERROR - Error events that might still allow the app to continue
1633
+ logger.error('Failed to send email notification', '[EMAIL_ERROR]');
1634
+
1635
+ // VERBOSE - Most detailed information (deep debugging only)
1636
+ logger.verbose('Internal state:', { state: complexObject });
1637
+ ```
1638
+
1639
+ ### 3. Include Meaningful Context
1640
+
1641
+ Always provide context to make logs searchable and traceable:
1642
+
1643
+ ```typescript
1644
+ // ❌ Bad - No context
1645
+ logger.log('User created');
1646
+
1647
+ // ✅ Good - With context
1648
+ logger.log('User created', 'UserService');
1649
+
1650
+ // ✅ Better - Structured with action tag
1651
+ logger.app.info(
1652
+ 'User created successfully',
1653
+ '[USER_CREATE]',
1654
+ 'UserService',
1655
+ 'user-123' // recordName
1656
+ );
1657
+
1658
+ // ✅ Best - Full metadata for distributed tracing
1659
+ logger.app.info(
1660
+ 'User created successfully',
1661
+ '[USER_CREATE]',
1662
+ 'UserService',
1663
+ 'user-123', // recordName
1664
+ 'sess-456', // sessionId
1665
+ 'txn-789', // transactionId
1666
+ 'mobile', // channel
1667
+ '1.0.0', // componentVersion
1668
+ 'CreateUser', // useCase
1669
+ 'Complete' // useCaseStep
1670
+ );
1671
+ ```
1672
+
1673
+ ### 4. Use Summary Logging for Operations
1674
+
1675
+ Track operation duration and outcomes with summary logs:
1676
+
1677
+ ```typescript
1678
+ // ✅ Best Practice - Track operation with telemetry
1679
+ const timer = new TimeDiff();
1680
+
1681
+ try {
1682
+ const result = await operation();
1683
+
1684
+ // Log success with metrics (automatically creates OpenTelemetry data)
1685
+ logger.app.summarySuccess(
1686
+ 'Operation completed',
1687
+ '200',
1688
+ timer.diff(),
1689
+ 'ServiceName',
1690
+ 'record-123',
1691
+ sessionId,
1692
+ transactionId
1693
+ );
1694
+
1695
+ return result;
1696
+ } catch (error) {
1697
+ // Log error with stack trace and metrics
1698
+ logger.app.summaryError(
1699
+ 'Operation failed',
1700
+ error.code || '500',
1701
+ timer.diff(),
1702
+ 'ServiceName',
1703
+ 'record-123',
1704
+ sessionId,
1705
+ transactionId,
1706
+ undefined,
1707
+ undefined,
1708
+ undefined,
1709
+ undefined,
1710
+ undefined,
1711
+ undefined,
1712
+ [error.stack] // Include stack trace
1713
+ );
1714
+
1715
+ throw error;
1716
+ }
1717
+ ```
1718
+
1719
+ ### 5. Leverage Message Formats
1720
+
1721
+ Use the appropriate format for your use case:
1722
+
1723
+ ```typescript
1724
+ // ✅ M1 for message broker/queue operations
1725
+ logger.loggerM1.info(
1726
+ 'order.created',
1727
+ ActionMessage.consume(),
1728
+ dataM1,
1729
+ 'Processing order message'
1730
+ );
1731
+
1732
+ // ✅ M2 for HTTP/protocol operations
1733
+ logger.loggerM2.info(
1734
+ 'api.users',
1735
+ ActionMessage.httpRequest(),
1736
+ dataM2,
1737
+ 'POST /api/users'
1738
+ );
1739
+
1740
+ // ✅ M3 for database/service operations
1741
+ logger.loggerM3.debug(
1742
+ 'db.users',
1743
+ ActionMessage.dbRequest(),
1744
+ dataM3,
1745
+ 'SELECT * FROM users WHERE id = ?'
1746
+ );
1747
+ ```
1748
+
1749
+ ### 6. Use Action Constants
1750
+
1751
+ Leverage predefined action tags for consistency:
1752
+
1753
+ ```typescript
1754
+ import { ActionMessage } from '@eqxjs/nest-logger';
1755
+
1756
+ // ✅ Use constants instead of strings
1757
+ logger.info('Message received', ActionMessage.consume());
1758
+ logger.info('Request sent', ActionMessage.httpRequest());
1759
+ logger.error('Exception occurred', ActionMessage.exception());
1760
+
1761
+ // ❌ Avoid - Manual strings (typos, inconsistency)
1762
+ logger.info('Message received', '[CONSUMMING]'); // Typo!
1763
+ logger.info('Request sent', '[HTTP-REQUEST]'); // Wrong format
1764
+ ```
1765
+
1766
+ ### 7. Mask Sensitive Data
1767
+
1768
+ Configure masking to protect sensitive information:
1769
+
1770
+ ```typescript
1771
+ // Set up masking in environment
1772
+ process.env.LOG_MASK_KEYS = 'password,apiKey,token,creditCard,ssn';
1773
+
1774
+ // ✅ All sensitive fields will be automatically masked
1775
+ const user = {
1776
+ username: 'john',
1777
+ password: 'secret123', // Will be masked
1778
+ email: 'john@example.com'
1779
+ };
1780
+
1781
+ logger.info('User data', user);
1782
+ // Output: { username: 'john', password: '*****', email: 'john@example.com' }
1783
+ ```
1784
+
1785
+ ### 8. Configure Environment Variables
1786
+
1787
+ Set up proper configuration for each environment:
1788
+
1789
+ ```typescript
1790
+ // Development
1791
+ process.env.LOG_LEVEL = 'debug,info,log,warn,error,verbose';
1792
+ process.env.LOG_MASK_KEYS = 'password,token';
1793
+ process.env.TELEMETRY_IGNORE_CODE = '';
1794
+
1795
+ // Production
1796
+ process.env.LOG_LEVEL = 'info,warn,error';
1797
+ process.env.LOG_MASK_KEYS = 'password,token,apiKey,secret,creditCard,ssn';
1798
+ process.env.TELEMETRY_IGNORE_CODE = '404,401,403';
1799
+ process.env.APP_VERSION = '1.0.0';
1800
+ process.env.DESTINATION = 'production';
1801
+ ```
1802
+
1803
+ ### 9. Use TimeDiff for Performance Tracking
1804
+
1805
+ Measure and log operation performance:
1806
+
1807
+ ```typescript
1808
+ import { TimeDiff } from '@eqxjs/nest-logger';
1809
+
1810
+ // ✅ Track operation duration
1811
+ async function processData() {
1812
+ const timer = TimeDiff.start();
1813
+
1814
+ // Step 1
1815
+ await step1();
1816
+ logger.debug(`Step 1 completed in ${timer.diff()}ms`);
1817
+
1818
+ // Step 2
1819
+ await step2();
1820
+ logger.debug(`Step 2 completed in ${timer.diff()}ms`);
1821
+
1822
+ // Total time
1823
+ const total = timer.end();
1824
+ logger.info(`Total processing time: ${total}ms`);
1825
+ }
1826
+ ```
1827
+
1828
+ ### 10. Handle Errors Consistently
1829
+
1830
+ Establish a consistent pattern for error handling:
1831
+
1832
+ ```typescript
1833
+ async function businessOperation() {
1834
+ const timer = new TimeDiff();
1835
+ const sessionId = 'sess-123';
1836
+ const transactionId = 'txn-456';
1837
+
1838
+ try {
1839
+ logger.app.info(
1840
+ 'Starting operation',
1841
+ ActionMessage.appLogic(),
1842
+ 'MyService',
1843
+ 'record-123',
1844
+ sessionId,
1845
+ transactionId
1846
+ );
1847
+
1848
+ const result = await performOperation();
1849
+
1850
+ logger.app.summarySuccess(
1851
+ 'Operation successful',
1852
+ '200',
1853
+ timer.diff(),
1854
+ 'MyService',
1855
+ 'record-123',
1856
+ sessionId,
1857
+ transactionId
1858
+ );
1859
+
1860
+ return result;
1861
+
1862
+ } catch (error) {
1863
+ logger.app.error(
1864
+ `Operation failed: ${error.message}`,
1865
+ ActionMessage.exception(),
1866
+ 'MyService',
1867
+ 'record-123',
1868
+ sessionId,
1869
+ transactionId
1870
+ );
1871
+
1872
+ logger.app.summaryError(
1873
+ 'Operation failed',
1874
+ error.code || '500',
1875
+ timer.diff(),
1876
+ 'MyService',
1877
+ 'record-123',
1878
+ sessionId,
1879
+ transactionId,
1880
+ undefined,
1881
+ undefined,
1882
+ undefined,
1883
+ undefined,
1884
+ undefined,
1885
+ undefined,
1886
+ [error.stack]
1887
+ );
1888
+
1889
+ throw error;
1890
+ }
1891
+ }
1892
+ ```
1893
+
1894
+ ## Performance Considerations
1895
+
1896
+ - **Caching**: Logger caches hostname and app version for performance
1897
+ - **Fast Paths**: String messages use optimized fast paths
1898
+ - **Message Truncation**: Long messages automatically truncated to 4096 chars
1899
+ - **Level Filtering**: Disabled log levels have minimal overhead (early return)
1900
+ - **Lazy Evaluation**: Complex operations only performed for enabled levels
1901
+
1902
+ ## Troubleshooting
1903
+
1904
+ ### Logs Not Appearing
1905
+
1906
+ Check that the log level is enabled:
1907
+
1908
+ ```typescript
1909
+ process.env.LOG_LEVEL = 'debug,info,warn,error,verbose';
1910
+ // Make sure the level you're using is in this list
1911
+ ```
1912
+
1913
+ ### Sensitive Data Still Visible
1914
+
1915
+ Ensure masking is configured:
1916
+
1917
+ ```typescript
1918
+ process.env.LOG_MASK_KEYS = 'password,token,apiKey,secret';
1919
+ // Add all field names that should be masked
1920
+ ```
1921
+
1922
+ ### Telemetry Not Working
1923
+
1924
+ Verify OpenTelemetry is configured in your application and the result codes aren't ignored:
1925
+
1926
+ ```typescript
1927
+ // Check if code is in ignore list
1928
+ process.env.TELEMETRY_IGNORE_CODE = '404,401';
1929
+ // These codes won't be tracked in telemetry
1930
+ ```
1931
+
1932
+ ### TypeScript Type Errors
1933
+
1934
+ Import the correct interfaces:
1935
+
1936
+ ```typescript
1937
+ import {
1938
+ DataM1I,
1939
+ DataM2I,
1940
+ DataM3I,
1941
+ LoggerOpt
1942
+ } from '@eqxjs/nest-logger';
1943
+ ```
1944
+
1945
+ ## Testing
1946
+
1947
+ The module includes comprehensive test coverage (100% lines):
1948
+
1949
+ ```bash
1950
+ # Run tests
1951
+ yarn test
1952
+
1953
+ # Run tests with coverage
1954
+ yarn test:cov
1955
+
1956
+ # Watch mode
1957
+ yarn test:watch
22
1958
  ```
23
1959
 
24
1960
  ## Development
25
1961
 
26
- Please see [docs/README.md](docs/README.md)
1962
+ Please see [docs/README.md](docs/README.md) for development guidelines.
27
1963
 
28
1964
  ## Contributing
29
1965
 
30
- Please see [contributing.md](CONTRIBUTING.md)
1966
+ Please see [CONTRIBUTING.md](CONTRIBUTING.md) for contribution guidelines.
31
1967
 
32
1968
  ## License
33
1969
 
34
- Please see [LICENSE](LICENSE)
1970
+ ISC
1971
+
1972
+ ## Support
1973
+
1974
+ For issues, questions, or contributions, please visit the [GitHub repository](https://github.com/eqxjs/nest-logger).
1975
+
1976
+ ## Changelog
1977
+
1978
+ See [CHANGELOG](CHANGELOG) for release notes and version history.
1979
+
1980
+ ---
1981
+
1982
+ **Made with ❤️ by the EQXJS Team**
1983
+ - Use M2 for HTTP/protocol-specific operations
1984
+ - Use M3 for service-to-service operations
1985
+
1986
+ 5. **Configure Environment Variables**
1987
+ - Set `LOG_LEVEL` in production to reduce log volume
1988
+ - Configure `LOG_MASK_KEYS` to protect sensitive data
1989
+ - Use `TELEMETRY_IGNORE_CODE` to filter noise from metrics
1990
+
1991
+ ## Testing
1992
+
1993
+ The module includes comprehensive test coverage (98.32%):
1994
+
1995
+ ```bash
1996
+ # Run tests
1997
+ yarn test
1998
+
1999
+ # Run tests with coverage
2000
+ yarn test:cov
2001
+
2002
+ # Watch mode
2003
+ yarn test:watch
2004
+ ```
2005
+
2006
+ ## Development
2007
+
2008
+ Please see [docs/README.md](docs/README.md) for development guidelines.
2009
+
2010
+ ## Contributing
2011
+
2012
+ Please see [CONTRIBUTING.md](CONTRIBUTING.md) for contribution guidelines.
2013
+
2014
+ ## License
2015
+
2016
+ ISC
2017
+
2018
+ ## Support
2019
+
2020
+ For issues, questions, or contributions, please visit the [GitHub repository](https://github.com/eqxjs/nest-logger).
2021
+
2022
+ ## Changelog
2023
+
2024
+ See [CHANGELOG](CHANGELOG) for release notes and version history.
2025
+
2026
+ ---
35
2027
 
36
- ## Remark
2028
+ **Made with ❤️ by the EQXJS Team**