@eqxjs/nest-logger 3.1.0-beta.13 โ 3.1.0-beta.15
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.
- package/README.md +646 -78
- package/dist/constants/action-message.constant.d.ts +171 -0
- package/dist/constants/action-message.constant.js +171 -0
- package/dist/constants/action-message.constant.js.map +1 -1
- package/dist/core/formatters/logger.formatter.d.ts +107 -0
- package/dist/core/formatters/logger.formatter.js +107 -0
- package/dist/core/formatters/logger.formatter.js.map +1 -1
- package/dist/core/loggers/app.logger.d.ts +33 -0
- package/dist/core/loggers/app.logger.js +51 -0
- package/dist/core/loggers/app.logger.js.map +1 -1
- package/dist/core/loggers/custom.logger.d.ts +111 -0
- package/dist/core/loggers/custom.logger.js +119 -0
- package/dist/core/loggers/custom.logger.js.map +1 -1
- package/dist/helpers/datetime.helper.d.ts +23 -0
- package/dist/helpers/datetime.helper.js +23 -0
- package/dist/helpers/datetime.helper.js.map +1 -1
- package/dist/helpers/log.helper.d.ts +81 -0
- package/dist/helpers/log.helper.js +81 -0
- package/dist/helpers/log.helper.js.map +1 -1
- package/dist/helpers/logger-builder.helper.d.ts +207 -2
- package/dist/helpers/logger-builder.helper.js +207 -2
- package/dist/helpers/logger-builder.helper.js.map +1 -1
- package/dist/helpers/message-formatter.helper.d.ts +74 -7
- package/dist/helpers/message-formatter.helper.js +74 -7
- package/dist/helpers/message-formatter.helper.js.map +1 -1
- package/dist/helpers/time-performance.helper.d.ts +61 -0
- package/dist/helpers/time-performance.helper.js +62 -1
- package/dist/helpers/time-performance.helper.js.map +1 -1
- package/dist/interfaces/data-service.interface.d.ts +1 -1
- package/dist/interfaces/data.interface.d.ts +1 -1
- package/dist/models/logger.dto.d.ts +43 -0
- package/dist/models/logger.dto.js +43 -0
- package/dist/models/logger.dto.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -3,23 +3,28 @@
|
|
|
3
3
|
A comprehensive, production-ready logging module for NestJS applications with built-in OpenTelemetry integration, structured logging, and support for multiple message formats.
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/@eqxjs/nest-logger)
|
|
6
|
-
[](./coverage)
|
|
7
7
|
[](https://nodejs.org)
|
|
8
8
|
|
|
9
9
|
## Features
|
|
10
10
|
|
|
11
11
|
โจ **Key Features:**
|
|
12
12
|
|
|
13
|
-
- ๐ **NestJS Integration** - Seamless integration with NestJS framework
|
|
14
|
-
- ๐ **OpenTelemetry Support** - Built-in metrics, traces, and spans
|
|
15
|
-
- ๐ท๏ธ **Structured Logging** - Consistent log format with rich metadata
|
|
16
|
-
- ๐ **Sensitive Data Masking** - Automatic masking of sensitive fields
|
|
17
|
-
- ๐ **Multiple Log Levels** - Debug, Info, Warn, Error, Verbose support
|
|
18
|
-
- ๐ฏ **Message Formats** - Support for M1, M2, and M3 message protocols
|
|
19
|
-
- โก **Performance Optimized** - Efficient logging with minimal overhead
|
|
20
|
-
- ๐งช **Well Tested** - 98%+
|
|
21
|
-
- ๐ **Telemetry Metrics** - Counter and histogram metrics for observability
|
|
22
|
-
- ๐ฆ **TypeScript** - Full TypeScript support with type definitions
|
|
13
|
+
- ๐ **NestJS Integration** - Seamless integration with NestJS framework (v11+)
|
|
14
|
+
- ๐ **OpenTelemetry Support** - Built-in metrics, traces, and spans 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
|
|
23
28
|
|
|
24
29
|
## Installation
|
|
25
30
|
|
|
@@ -35,6 +40,46 @@ npm install @eqxjs/nest-logger
|
|
|
35
40
|
- Node.js >= 22
|
|
36
41
|
- NestJS >= 11
|
|
37
42
|
|
|
43
|
+
## Feature Overview
|
|
44
|
+
|
|
45
|
+
### Logger Types Comparison
|
|
46
|
+
|
|
47
|
+
| Feature | CustomLogger | BaseAppLogger | AppLogger | LoggerFormat (M1/M2/M3) |
|
|
48
|
+
|---------|--------------|---------------|-----------|-------------------------|
|
|
49
|
+
| **Basic Logging** | โ
| โ
| โ
| โ
|
|
|
50
|
+
| **Structured Metadata** | โ | โ
| โ
| โ
|
|
|
51
|
+
| **OpenTelemetry** | โ | โ
| โ
| โ
|
|
|
52
|
+
| **Message Formats** | โ | โ | โ
| โ
|
|
|
53
|
+
| **Summary Logs** | โ | โ
| โ
| โ
|
|
|
54
|
+
| **Sensitive Masking** | โ
| โ
| โ
| โ
|
|
|
55
|
+
| **Use Case** | Simple apps | Advanced apps | Multi-format | Specific protocols |
|
|
56
|
+
|
|
57
|
+
### Supported Log Levels
|
|
58
|
+
|
|
59
|
+
All loggers support these levels (controlled by `LOG_LEVEL` environment variable):
|
|
60
|
+
|
|
61
|
+
- **debug** - Detailed diagnostic information
|
|
62
|
+
- **info** - General informational messages
|
|
63
|
+
- **log** - Alias for info level
|
|
64
|
+
- **warn** - Warning messages for potentially harmful situations
|
|
65
|
+
- **error** - Error events that might still allow the app to continue
|
|
66
|
+
- **verbose** - Most detailed information for deep debugging
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
### Metadata Fields
|
|
70
|
+
|
|
71
|
+
LoggerDto includes 27+ fields for comprehensive logging:
|
|
72
|
+
|
|
73
|
+
| Category | Fields |
|
|
74
|
+
|----------|--------|
|
|
75
|
+
| **Core** | level, timestamp, message, action |
|
|
76
|
+
| **Application** | appName, componentName, componentVersion |
|
|
77
|
+
| **Tracking** | sessionId, transactionId, recordName, guid |
|
|
78
|
+
| **Context** | channel, broker, device, user, public |
|
|
79
|
+
| **Use Case** | useCase, useCaseStep |
|
|
80
|
+
| **Result** | appResult, appResultCode, serviceTime, stack |
|
|
81
|
+
| **Infrastructure** | instance, originateServiceName, recordType |
|
|
82
|
+
|
|
38
83
|
## Quick Start
|
|
39
84
|
|
|
40
85
|
### 1. Import the Module
|
|
@@ -69,6 +114,116 @@ export class MyService {
|
|
|
69
114
|
}
|
|
70
115
|
```
|
|
71
116
|
|
|
117
|
+
## Message Protocol Data Structures
|
|
118
|
+
|
|
119
|
+
The logger supports three message protocols (M1, M2, M3), each with specific required properties:
|
|
120
|
+
|
|
121
|
+
### DataM1I - Broker/Queue Messages
|
|
122
|
+
|
|
123
|
+
**Required Properties:**
|
|
124
|
+
- `header`: DataHeaderI - Message header with identity
|
|
125
|
+
- `protocol`: DataProtocolI - Protocol-specific information
|
|
126
|
+
- `body`: Record<string, unknown> - Message payload
|
|
127
|
+
|
|
128
|
+
```typescript
|
|
129
|
+
import { DataM1I } from '@eqxjs/nest-logger';
|
|
130
|
+
|
|
131
|
+
const data: DataM1I = {
|
|
132
|
+
header: {
|
|
133
|
+
sessionId: 'session-123',
|
|
134
|
+
transactionId: 'txn-456',
|
|
135
|
+
broker: 'kafka',
|
|
136
|
+
channel: 'order-queue',
|
|
137
|
+
useCase: 'ProcessOrder',
|
|
138
|
+
identity: {
|
|
139
|
+
device: 'mobile-app',
|
|
140
|
+
user: 'user-123',
|
|
141
|
+
public: 'public-id'
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
protocol: {
|
|
145
|
+
topic: 'order.created',
|
|
146
|
+
command: 'PROCESS',
|
|
147
|
+
qos: '1'
|
|
148
|
+
},
|
|
149
|
+
body: {
|
|
150
|
+
orderId: '12345',
|
|
151
|
+
amount: 100.00
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### DataM2I - HTTP/Protocol Messages
|
|
157
|
+
|
|
158
|
+
**Required Properties:**
|
|
159
|
+
- `header`: DataHeaderI - Message header with identity
|
|
160
|
+
- `body`: Record<string, unknown> - Message payload
|
|
161
|
+
|
|
162
|
+
**Optional Properties:**
|
|
163
|
+
- `protocol`: DataProtocolI - HTTP/protocol information
|
|
164
|
+
|
|
165
|
+
```typescript
|
|
166
|
+
import { DataM2I } from '@eqxjs/nest-logger';
|
|
167
|
+
|
|
168
|
+
const data: DataM2I = {
|
|
169
|
+
header: {
|
|
170
|
+
sessionId: 'session-123',
|
|
171
|
+
transactionId: 'txn-456',
|
|
172
|
+
channel: 'web',
|
|
173
|
+
useCase: 'CreatePayment',
|
|
174
|
+
identity: {
|
|
175
|
+
user: 'user-123',
|
|
176
|
+
public: 'public-id'
|
|
177
|
+
}
|
|
178
|
+
},
|
|
179
|
+
body: {
|
|
180
|
+
paymentId: 'pay-123',
|
|
181
|
+
status: 'completed'
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### DataM3I - Service/Database Messages
|
|
187
|
+
|
|
188
|
+
**Required Properties:**
|
|
189
|
+
- `service`: DataServiceI - Service-specific information with identity
|
|
190
|
+
- `body`: Record<string, unknown> - Message payload
|
|
191
|
+
|
|
192
|
+
**Optional Properties:**
|
|
193
|
+
- `header`: DataHeaderI - Message header with identity
|
|
194
|
+
|
|
195
|
+
```typescript
|
|
196
|
+
import { DataM3I } from '@eqxjs/nest-logger';
|
|
197
|
+
|
|
198
|
+
const data: DataM3I = {
|
|
199
|
+
service: {
|
|
200
|
+
serviceName: 'PostgreSQL',
|
|
201
|
+
name: 'users-db',
|
|
202
|
+
invoke: 'SELECT',
|
|
203
|
+
identity: {
|
|
204
|
+
device: 'db-server-1',
|
|
205
|
+
user: 'db-user'
|
|
206
|
+
}
|
|
207
|
+
},
|
|
208
|
+
body: {
|
|
209
|
+
query: 'SELECT * FROM users WHERE id = $1',
|
|
210
|
+
resultCount: 1
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### Identity Structure
|
|
216
|
+
|
|
217
|
+
All message types include an `identity` object with optional fields:
|
|
218
|
+
|
|
219
|
+
```typescript
|
|
220
|
+
identity: {
|
|
221
|
+
device?: string | string[]; // Device identifier(s)
|
|
222
|
+
public?: string; // Public identifier
|
|
223
|
+
user?: string; // User identifier
|
|
224
|
+
}
|
|
225
|
+
```
|
|
226
|
+
|
|
72
227
|
## Usage Examples
|
|
73
228
|
|
|
74
229
|
### Basic Logging
|
|
@@ -114,11 +269,11 @@ export class PaymentController {
|
|
|
114
269
|
transactionId,
|
|
115
270
|
channel: 'web',
|
|
116
271
|
useCase: 'ProcessPayment',
|
|
272
|
+
identity: {},
|
|
117
273
|
},
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
statusCode: 200,
|
|
274
|
+
body: {
|
|
275
|
+
amount: request.body.amount,
|
|
276
|
+
currency: request.body.currency,
|
|
122
277
|
},
|
|
123
278
|
};
|
|
124
279
|
|
|
@@ -182,6 +337,15 @@ export class OrderConsumer {
|
|
|
182
337
|
channel: 'order-topic',
|
|
183
338
|
useCase: 'ProcessOrder',
|
|
184
339
|
useCaseStep: 'Consume',
|
|
340
|
+
identity: {},
|
|
341
|
+
},
|
|
342
|
+
protocol: {
|
|
343
|
+
topic: 'order.created',
|
|
344
|
+
command: 'CONSUME',
|
|
345
|
+
},
|
|
346
|
+
body: {
|
|
347
|
+
orderId: message.orderId,
|
|
348
|
+
customerId: message.customerId,
|
|
185
349
|
},
|
|
186
350
|
};
|
|
187
351
|
|
|
@@ -250,15 +414,16 @@ export class UserRepository {
|
|
|
250
414
|
const timer = new TimeDiff();
|
|
251
415
|
|
|
252
416
|
const data: DataM3I = {
|
|
253
|
-
|
|
254
|
-
sessionId,
|
|
255
|
-
transactionId,
|
|
256
|
-
useCase: 'GetUser',
|
|
257
|
-
},
|
|
417
|
+
|
|
258
418
|
service: {
|
|
259
419
|
serviceName: 'PostgreSQL',
|
|
260
|
-
|
|
261
|
-
|
|
420
|
+
invoke: 'SELECT',
|
|
421
|
+
name: 'users',
|
|
422
|
+
identity: {},
|
|
423
|
+
},
|
|
424
|
+
body: {
|
|
425
|
+
userId: userId,
|
|
426
|
+
operation: 'findById',
|
|
262
427
|
},
|
|
263
428
|
};
|
|
264
429
|
|
|
@@ -320,12 +485,6 @@ export class NotificationService {
|
|
|
320
485
|
const timer = new TimeDiff();
|
|
321
486
|
|
|
322
487
|
const data: DataM3I = {
|
|
323
|
-
header: {
|
|
324
|
-
sessionId,
|
|
325
|
-
transactionId,
|
|
326
|
-
useCase: 'SendNotification',
|
|
327
|
-
useCaseStep: 'SendEmail',
|
|
328
|
-
},
|
|
329
488
|
service: {
|
|
330
489
|
serviceName: 'EmailService',
|
|
331
490
|
operation: 'SEND',
|
|
@@ -644,6 +803,15 @@ export class KafkaConsumerService {
|
|
|
644
803
|
broker: 'kafka',
|
|
645
804
|
channel: 'queue',
|
|
646
805
|
useCase: 'MessageProcessing',
|
|
806
|
+
identity: {},
|
|
807
|
+
},
|
|
808
|
+
protocol: {
|
|
809
|
+
topic: 'payment.topic',
|
|
810
|
+
command: 'PROCESS',
|
|
811
|
+
},
|
|
812
|
+
body: {
|
|
813
|
+
messageId: message.id,
|
|
814
|
+
payload: message.data,
|
|
647
815
|
},
|
|
648
816
|
};
|
|
649
817
|
|
|
@@ -681,12 +849,17 @@ export class HttpService {
|
|
|
681
849
|
header: {
|
|
682
850
|
sessionId: req.sessionId,
|
|
683
851
|
transactionId: req.transactionId,
|
|
852
|
+
identity: {},
|
|
684
853
|
},
|
|
685
854
|
protocol: {
|
|
686
855
|
requestId: req.id,
|
|
687
856
|
method: req.method,
|
|
688
857
|
path: req.path,
|
|
689
858
|
},
|
|
859
|
+
body: {
|
|
860
|
+
endpoint: req.path,
|
|
861
|
+
params: req.params,
|
|
862
|
+
},
|
|
690
863
|
};
|
|
691
864
|
|
|
692
865
|
this.logger.loggerM2.info(
|
|
@@ -713,11 +886,17 @@ export class DatabaseService {
|
|
|
713
886
|
header: {
|
|
714
887
|
sessionId: 'session-123',
|
|
715
888
|
transactionId: 'txn-456',
|
|
889
|
+
identity: {},
|
|
716
890
|
},
|
|
717
891
|
service: {
|
|
718
892
|
serviceName: 'PostgreSQL',
|
|
719
|
-
|
|
720
|
-
|
|
893
|
+
invoke: 'SELECT',
|
|
894
|
+
name: 'users',
|
|
895
|
+
identity: {},
|
|
896
|
+
},
|
|
897
|
+
body: {
|
|
898
|
+
query: query,
|
|
899
|
+
database: 'users_db',
|
|
721
900
|
},
|
|
722
901
|
};
|
|
723
902
|
|
|
@@ -828,25 +1007,31 @@ const manualMask = JSON.stringify(sensitiveData, maskMessageReplacer);
|
|
|
828
1007
|
|
|
829
1008
|
### Environment Variables
|
|
830
1009
|
|
|
831
|
-
|
|
832
|
-
# Log levels (comma-separated)
|
|
833
|
-
LOG_LEVEL=debug,info,warn,error,verbose
|
|
1010
|
+
Configure the logger behavior using these environment variables:
|
|
834
1011
|
|
|
835
|
-
|
|
836
|
-
|
|
1012
|
+
| Variable | Type | Default | Description |
|
|
1013
|
+
|----------|------|---------|-------------|
|
|
1014
|
+
| `LOG_LEVEL` | string | - | Comma-separated list of enabled log levels: `debug,info,log,warn,error,verbose` |
|
|
1015
|
+
| `LOG_MASK_KEYS` | string | - | Comma-separated list of field names to mask (e.g., `password,token,apiKey,secret`) |
|
|
1016
|
+
| `APP_VERSION` | string | - | Application version included in telemetry and logs |
|
|
1017
|
+
| `DESTINATION` | string | - | Deployment destination/environment name |
|
|
1018
|
+
| `TELEMETRY_IGNORE_CODE` | string | - | Comma-separated list of result codes to exclude from telemetry metrics |
|
|
837
1019
|
|
|
838
|
-
|
|
839
|
-
APP_VERSION=1.0.0
|
|
1020
|
+
**Example Configuration:**
|
|
840
1021
|
|
|
841
|
-
|
|
1022
|
+
```bash
|
|
1023
|
+
# .env file
|
|
1024
|
+
LOG_LEVEL=debug,info,warn,error,verbose
|
|
1025
|
+
LOG_MASK_KEYS=password,secret,token,apiKey,creditCard,ssn
|
|
1026
|
+
APP_VERSION=1.0.0
|
|
842
1027
|
DESTINATION=production
|
|
843
|
-
|
|
844
|
-
# Ignore specific result codes from telemetry
|
|
845
|
-
TELEMETRY_IGNORE_CODE=404,401
|
|
1028
|
+
TELEMETRY_IGNORE_CODE=404,401,403
|
|
846
1029
|
```
|
|
847
1030
|
|
|
848
1031
|
### Log Level Filtering
|
|
849
1032
|
|
|
1033
|
+
Control which log levels are output by configuring the `LOG_LEVEL` environment variable:
|
|
1034
|
+
|
|
850
1035
|
```typescript
|
|
851
1036
|
// Only logs matching the LOG_LEVEL env var will be output
|
|
852
1037
|
process.env.LOG_LEVEL = 'info,error';
|
|
@@ -854,22 +1039,58 @@ process.env.LOG_LEVEL = 'info,error';
|
|
|
854
1039
|
logger.debug('This will NOT be logged');
|
|
855
1040
|
logger.info('This WILL be logged');
|
|
856
1041
|
logger.error('This WILL be logged');
|
|
1042
|
+
logger.verbose('This will NOT be logged');
|
|
857
1043
|
```
|
|
858
1044
|
|
|
859
1045
|
### Sensitive Data Masking
|
|
860
1046
|
|
|
1047
|
+
Protect sensitive information by automatically masking specified fields:
|
|
1048
|
+
|
|
861
1049
|
```typescript
|
|
862
1050
|
// Set masked fields via environment
|
|
863
|
-
process.env.LOG_MASK_KEYS = 'password,creditCard,ssn';
|
|
1051
|
+
process.env.LOG_MASK_KEYS = 'password,creditCard,ssn,token';
|
|
864
1052
|
|
|
865
1053
|
const userData = {
|
|
866
1054
|
username: 'john',
|
|
867
1055
|
password: 'secret123',
|
|
868
1056
|
creditCard: '4111-1111-1111-1111',
|
|
1057
|
+
email: 'john@example.com',
|
|
1058
|
+
token: 'abc-def-123'
|
|
869
1059
|
};
|
|
870
1060
|
|
|
871
1061
|
logger.log(userData);
|
|
872
|
-
// Output: { username: 'john', password: '*****', creditCard: '*****' }
|
|
1062
|
+
// Output: { username: 'john', password: '*****', creditCard: '*****', email: 'john@example.com', token: '*****' }
|
|
1063
|
+
```
|
|
1064
|
+
|
|
1065
|
+
### Telemetry Filtering
|
|
1066
|
+
|
|
1067
|
+
Exclude specific result codes from telemetry metrics to reduce noise:
|
|
1068
|
+
|
|
1069
|
+
```typescript
|
|
1070
|
+
// Don't track 404 and 401 errors in telemetry
|
|
1071
|
+
process.env.TELEMETRY_IGNORE_CODE = '404,401';
|
|
1072
|
+
|
|
1073
|
+
// These won't be recorded in OpenTelemetry metrics
|
|
1074
|
+
logger.app.summaryError('Not found', '404', 100);
|
|
1075
|
+
logger.app.summaryError('Unauthorized', '401', 50);
|
|
1076
|
+
|
|
1077
|
+
// This will be recorded
|
|
1078
|
+
logger.app.summaryError('Server error', '500', 200);
|
|
1079
|
+
```
|
|
1080
|
+
|
|
1081
|
+
### Message Truncation
|
|
1082
|
+
|
|
1083
|
+
Long messages are automatically truncated to prevent log overflow:
|
|
1084
|
+
|
|
1085
|
+
```typescript
|
|
1086
|
+
// Messages longer than 4096 characters are truncated
|
|
1087
|
+
const longMessage = 'a'.repeat(5000);
|
|
1088
|
+
logger.info(longMessage);
|
|
1089
|
+
// Logged message will be truncated to 4096 chars + '...'
|
|
1090
|
+
|
|
1091
|
+
// The limit is defined in DEFAULT_VALUES.MAX_MESSAGE_LENGTH
|
|
1092
|
+
import { DEFAULT_VALUES } from '@eqxjs/nest-logger';
|
|
1093
|
+
console.log(DEFAULT_VALUES.MAX_MESSAGE_LENGTH); // 4096
|
|
873
1094
|
```
|
|
874
1095
|
|
|
875
1096
|
## OpenTelemetry Integration
|
|
@@ -1323,41 +1544,388 @@ class LoggerDto {
|
|
|
1323
1544
|
|
|
1324
1545
|
## Best Practices
|
|
1325
1546
|
|
|
1326
|
-
1.
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1547
|
+
### 1. Choose the Right Logger
|
|
1548
|
+
|
|
1549
|
+
```typescript
|
|
1550
|
+
// For simple applications - use CustomLogger
|
|
1551
|
+
const logger = new CustomLogger('MyApp');
|
|
1552
|
+
logger.log('Simple message');
|
|
1553
|
+
|
|
1554
|
+
// For structured logging - use BaseAppLogger
|
|
1555
|
+
const appLogger = new BaseAppLogger('MyApp', 'UserService');
|
|
1556
|
+
appLogger.info('User action', '[USER_CREATE]');
|
|
1557
|
+
|
|
1558
|
+
// For multiple formats - use AppLogger
|
|
1559
|
+
const multiLogger = new AppLogger('MyApp');
|
|
1560
|
+
multiLogger.app.info('Standard log');
|
|
1561
|
+
multiLogger.loggerM1.info('kafka.topic', '[CONSUMING]', data);
|
|
1562
|
+
```
|
|
1563
|
+
|
|
1564
|
+
### 2. Use Appropriate Log Levels
|
|
1565
|
+
|
|
1566
|
+
Choose the right level based on the situation:
|
|
1567
|
+
|
|
1568
|
+
```typescript
|
|
1569
|
+
// DEBUG - Detailed diagnostic information (development only)
|
|
1570
|
+
logger.debug('Request payload:', { userId: 123, action: 'create' });
|
|
1571
|
+
|
|
1572
|
+
// INFO - General informational messages (normal operations)
|
|
1573
|
+
logger.info('User logged in successfully', '[USER_LOGIN]');
|
|
1574
|
+
|
|
1575
|
+
// WARN - Potentially harmful situations (recoverable issues)
|
|
1576
|
+
logger.warn('API rate limit approaching 80%', '[RATE_LIMIT]');
|
|
1577
|
+
|
|
1578
|
+
// ERROR - Error events that might still allow the app to continue
|
|
1579
|
+
logger.error('Failed to send email notification', '[EMAIL_ERROR]');
|
|
1580
|
+
|
|
1581
|
+
// VERBOSE - Most detailed information (deep debugging only)
|
|
1582
|
+
logger.verbose('Internal state:', { state: complexObject });
|
|
1583
|
+
```
|
|
1584
|
+
|
|
1585
|
+
### 3. Include Meaningful Context
|
|
1586
|
+
|
|
1587
|
+
Always provide context to make logs searchable and traceable:
|
|
1588
|
+
|
|
1589
|
+
```typescript
|
|
1590
|
+
// โ Bad - No context
|
|
1591
|
+
logger.log('User created');
|
|
1592
|
+
|
|
1593
|
+
// โ
Good - With context
|
|
1594
|
+
logger.log('User created', 'UserService');
|
|
1595
|
+
|
|
1596
|
+
// โ
Better - Structured with action tag
|
|
1597
|
+
logger.app.info(
|
|
1598
|
+
'User created successfully',
|
|
1599
|
+
'[USER_CREATE]',
|
|
1600
|
+
'UserService',
|
|
1601
|
+
'user-123' // recordName
|
|
1602
|
+
);
|
|
1603
|
+
|
|
1604
|
+
// โ
Best - Full metadata for distributed tracing
|
|
1605
|
+
logger.app.info(
|
|
1606
|
+
'User created successfully',
|
|
1607
|
+
'[USER_CREATE]',
|
|
1608
|
+
'UserService',
|
|
1609
|
+
'user-123', // recordName
|
|
1610
|
+
'sess-456', // sessionId
|
|
1611
|
+
'txn-789', // transactionId
|
|
1612
|
+
'mobile', // channel
|
|
1613
|
+
'1.0.0', // componentVersion
|
|
1614
|
+
'CreateUser', // useCase
|
|
1615
|
+
'Complete' // useCaseStep
|
|
1616
|
+
);
|
|
1617
|
+
```
|
|
1618
|
+
|
|
1619
|
+
### 4. Use Summary Logging for Operations
|
|
1620
|
+
|
|
1621
|
+
Track operation duration and outcomes with summary logs:
|
|
1622
|
+
|
|
1623
|
+
```typescript
|
|
1624
|
+
// โ
Best Practice - Track operation with telemetry
|
|
1625
|
+
const timer = new TimeDiff();
|
|
1626
|
+
|
|
1627
|
+
try {
|
|
1628
|
+
const result = await operation();
|
|
1629
|
+
|
|
1630
|
+
// Log success with metrics (automatically creates OpenTelemetry data)
|
|
1631
|
+
logger.app.summarySuccess(
|
|
1632
|
+
'Operation completed',
|
|
1633
|
+
'200',
|
|
1634
|
+
timer.diff(),
|
|
1635
|
+
'ServiceName',
|
|
1636
|
+
'record-123',
|
|
1637
|
+
sessionId,
|
|
1638
|
+
transactionId
|
|
1639
|
+
);
|
|
1640
|
+
|
|
1641
|
+
return result;
|
|
1642
|
+
} catch (error) {
|
|
1643
|
+
// Log error with stack trace and metrics
|
|
1644
|
+
logger.app.summaryError(
|
|
1645
|
+
'Operation failed',
|
|
1646
|
+
error.code || '500',
|
|
1647
|
+
timer.diff(),
|
|
1648
|
+
'ServiceName',
|
|
1649
|
+
'record-123',
|
|
1650
|
+
sessionId,
|
|
1651
|
+
transactionId,
|
|
1652
|
+
undefined,
|
|
1653
|
+
undefined,
|
|
1654
|
+
undefined,
|
|
1655
|
+
undefined,
|
|
1656
|
+
undefined,
|
|
1657
|
+
undefined,
|
|
1658
|
+
[error.stack] // Include stack trace
|
|
1659
|
+
);
|
|
1660
|
+
|
|
1661
|
+
throw error;
|
|
1662
|
+
}
|
|
1663
|
+
```
|
|
1664
|
+
|
|
1665
|
+
### 5. Leverage Message Formats
|
|
1666
|
+
|
|
1667
|
+
Use the appropriate format for your use case:
|
|
1668
|
+
|
|
1669
|
+
```typescript
|
|
1670
|
+
// โ
M1 for message broker/queue operations
|
|
1671
|
+
logger.loggerM1.info(
|
|
1672
|
+
'order.created',
|
|
1673
|
+
ActionMessage.consume(),
|
|
1674
|
+
dataM1,
|
|
1675
|
+
'Processing order message'
|
|
1676
|
+
);
|
|
1677
|
+
|
|
1678
|
+
// โ
M2 for HTTP/protocol operations
|
|
1679
|
+
logger.loggerM2.info(
|
|
1680
|
+
'api.users',
|
|
1681
|
+
ActionMessage.httpRequest(),
|
|
1682
|
+
dataM2,
|
|
1683
|
+
'POST /api/users'
|
|
1684
|
+
);
|
|
1685
|
+
|
|
1686
|
+
// โ
M3 for database/service operations
|
|
1687
|
+
logger.loggerM3.debug(
|
|
1688
|
+
'db.users',
|
|
1689
|
+
ActionMessage.dbRequest(),
|
|
1690
|
+
dataM3,
|
|
1691
|
+
'SELECT * FROM users WHERE id = ?'
|
|
1692
|
+
);
|
|
1693
|
+
```
|
|
1694
|
+
|
|
1695
|
+
### 6. Use Action Constants
|
|
1696
|
+
|
|
1697
|
+
Leverage predefined action tags for consistency:
|
|
1698
|
+
|
|
1699
|
+
```typescript
|
|
1700
|
+
import { ActionMessage } from '@eqxjs/nest-logger';
|
|
1701
|
+
|
|
1702
|
+
// โ
Use constants instead of strings
|
|
1703
|
+
logger.info('Message received', ActionMessage.consume());
|
|
1704
|
+
logger.info('Request sent', ActionMessage.httpRequest());
|
|
1705
|
+
logger.error('Exception occurred', ActionMessage.exception());
|
|
1706
|
+
|
|
1707
|
+
// โ Avoid - Manual strings (typos, inconsistency)
|
|
1708
|
+
logger.info('Message received', '[CONSUMMING]'); // Typo!
|
|
1709
|
+
logger.info('Request sent', '[HTTP-REQUEST]'); // Wrong format
|
|
1710
|
+
```
|
|
1711
|
+
|
|
1712
|
+
### 7. Mask Sensitive Data
|
|
1713
|
+
|
|
1714
|
+
Configure masking to protect sensitive information:
|
|
1715
|
+
|
|
1716
|
+
```typescript
|
|
1717
|
+
// Set up masking in environment
|
|
1718
|
+
process.env.LOG_MASK_KEYS = 'password,apiKey,token,creditCard,ssn';
|
|
1719
|
+
|
|
1720
|
+
// โ
All sensitive fields will be automatically masked
|
|
1721
|
+
const user = {
|
|
1722
|
+
username: 'john',
|
|
1723
|
+
password: 'secret123', // Will be masked
|
|
1724
|
+
email: 'john@example.com'
|
|
1725
|
+
};
|
|
1726
|
+
|
|
1727
|
+
logger.info('User data', user);
|
|
1728
|
+
// Output: { username: 'john', password: '*****', email: 'john@example.com' }
|
|
1729
|
+
```
|
|
1730
|
+
|
|
1731
|
+
### 8. Configure Environment Variables
|
|
1732
|
+
|
|
1733
|
+
Set up proper configuration for each environment:
|
|
1734
|
+
|
|
1735
|
+
```typescript
|
|
1736
|
+
// Development
|
|
1737
|
+
process.env.LOG_LEVEL = 'debug,info,log,warn,error,verbose';
|
|
1738
|
+
process.env.LOG_MASK_KEYS = 'password,token';
|
|
1739
|
+
process.env.TELEMETRY_IGNORE_CODE = '';
|
|
1740
|
+
|
|
1741
|
+
// Production
|
|
1742
|
+
process.env.LOG_LEVEL = 'info,warn,error';
|
|
1743
|
+
process.env.LOG_MASK_KEYS = 'password,token,apiKey,secret,creditCard,ssn';
|
|
1744
|
+
process.env.TELEMETRY_IGNORE_CODE = '404,401,403';
|
|
1745
|
+
process.env.APP_VERSION = '1.0.0';
|
|
1746
|
+
process.env.DESTINATION = 'production';
|
|
1747
|
+
```
|
|
1748
|
+
|
|
1749
|
+
### 9. Use TimeDiff for Performance Tracking
|
|
1750
|
+
|
|
1751
|
+
Measure and log operation performance:
|
|
1752
|
+
|
|
1753
|
+
```typescript
|
|
1754
|
+
import { TimeDiff } from '@eqxjs/nest-logger';
|
|
1755
|
+
|
|
1756
|
+
// โ
Track operation duration
|
|
1757
|
+
async function processData() {
|
|
1758
|
+
const timer = TimeDiff.start();
|
|
1759
|
+
|
|
1760
|
+
// Step 1
|
|
1761
|
+
await step1();
|
|
1762
|
+
logger.debug(`Step 1 completed in ${timer.diff()}ms`);
|
|
1763
|
+
|
|
1764
|
+
// Step 2
|
|
1765
|
+
await step2();
|
|
1766
|
+
logger.debug(`Step 2 completed in ${timer.diff()}ms`);
|
|
1767
|
+
|
|
1768
|
+
// Total time
|
|
1769
|
+
const total = timer.end();
|
|
1770
|
+
logger.info(`Total processing time: ${total}ms`);
|
|
1771
|
+
}
|
|
1772
|
+
```
|
|
1773
|
+
|
|
1774
|
+
### 10. Handle Errors Consistently
|
|
1775
|
+
|
|
1776
|
+
Establish a consistent pattern for error handling:
|
|
1777
|
+
|
|
1778
|
+
```typescript
|
|
1779
|
+
async function businessOperation() {
|
|
1780
|
+
const timer = new TimeDiff();
|
|
1781
|
+
const sessionId = 'sess-123';
|
|
1782
|
+
const transactionId = 'txn-456';
|
|
1783
|
+
|
|
1784
|
+
try {
|
|
1785
|
+
logger.app.info(
|
|
1786
|
+
'Starting operation',
|
|
1787
|
+
ActionMessage.appLogic(),
|
|
1788
|
+
'MyService',
|
|
1789
|
+
'record-123',
|
|
1790
|
+
sessionId,
|
|
1791
|
+
transactionId
|
|
1792
|
+
);
|
|
1793
|
+
|
|
1794
|
+
const result = await performOperation();
|
|
1795
|
+
|
|
1796
|
+
logger.app.summarySuccess(
|
|
1797
|
+
'Operation successful',
|
|
1798
|
+
'200',
|
|
1799
|
+
timer.diff(),
|
|
1800
|
+
'MyService',
|
|
1801
|
+
'record-123',
|
|
1802
|
+
sessionId,
|
|
1803
|
+
transactionId
|
|
1804
|
+
);
|
|
1805
|
+
|
|
1806
|
+
return result;
|
|
1807
|
+
|
|
1808
|
+
} catch (error) {
|
|
1809
|
+
logger.app.error(
|
|
1810
|
+
`Operation failed: ${error.message}`,
|
|
1811
|
+
ActionMessage.exception(),
|
|
1812
|
+
'MyService',
|
|
1813
|
+
'record-123',
|
|
1814
|
+
sessionId,
|
|
1815
|
+
transactionId
|
|
1816
|
+
);
|
|
1817
|
+
|
|
1818
|
+
logger.app.summaryError(
|
|
1819
|
+
'Operation failed',
|
|
1820
|
+
error.code || '500',
|
|
1821
|
+
timer.diff(),
|
|
1822
|
+
'MyService',
|
|
1823
|
+
'record-123',
|
|
1824
|
+
sessionId,
|
|
1825
|
+
transactionId,
|
|
1826
|
+
undefined,
|
|
1827
|
+
undefined,
|
|
1828
|
+
undefined,
|
|
1829
|
+
undefined,
|
|
1830
|
+
undefined,
|
|
1831
|
+
undefined,
|
|
1832
|
+
[error.stack]
|
|
1833
|
+
);
|
|
1834
|
+
|
|
1835
|
+
throw error;
|
|
1836
|
+
}
|
|
1837
|
+
}
|
|
1838
|
+
```
|
|
1839
|
+
|
|
1840
|
+
## Performance Considerations
|
|
1841
|
+
|
|
1842
|
+
- **Caching**: Logger caches hostname and app version for performance
|
|
1843
|
+
- **Fast Paths**: String messages use optimized fast paths
|
|
1844
|
+
- **Message Truncation**: Long messages automatically truncated to 4096 chars
|
|
1845
|
+
- **Level Filtering**: Disabled log levels have minimal overhead (early return)
|
|
1846
|
+
- **Lazy Evaluation**: Complex operations only performed for enabled levels
|
|
1847
|
+
|
|
1848
|
+
## Troubleshooting
|
|
1849
|
+
|
|
1850
|
+
### Logs Not Appearing
|
|
1851
|
+
|
|
1852
|
+
Check that the log level is enabled:
|
|
1853
|
+
|
|
1854
|
+
```typescript
|
|
1855
|
+
process.env.LOG_LEVEL = 'debug,info,warn,error,verbose';
|
|
1856
|
+
// Make sure the level you're using is in this list
|
|
1857
|
+
```
|
|
1858
|
+
|
|
1859
|
+
### Sensitive Data Still Visible
|
|
1860
|
+
|
|
1861
|
+
Ensure masking is configured:
|
|
1862
|
+
|
|
1863
|
+
```typescript
|
|
1864
|
+
process.env.LOG_MASK_KEYS = 'password,token,apiKey,secret';
|
|
1865
|
+
// Add all field names that should be masked
|
|
1866
|
+
```
|
|
1867
|
+
|
|
1868
|
+
### Telemetry Not Working
|
|
1869
|
+
|
|
1870
|
+
Verify OpenTelemetry is configured in your application and the result codes aren't ignored:
|
|
1871
|
+
|
|
1872
|
+
```typescript
|
|
1873
|
+
// Check if code is in ignore list
|
|
1874
|
+
process.env.TELEMETRY_IGNORE_CODE = '404,401';
|
|
1875
|
+
// These codes won't be tracked in telemetry
|
|
1876
|
+
```
|
|
1877
|
+
|
|
1878
|
+
### TypeScript Type Errors
|
|
1879
|
+
|
|
1880
|
+
Import the correct interfaces:
|
|
1881
|
+
|
|
1882
|
+
```typescript
|
|
1883
|
+
import {
|
|
1884
|
+
DataM1I,
|
|
1885
|
+
DataM2I,
|
|
1886
|
+
DataM3I,
|
|
1887
|
+
LoggerOpt
|
|
1888
|
+
} from '@eqxjs/nest-logger';
|
|
1889
|
+
```
|
|
1890
|
+
|
|
1891
|
+
## Testing
|
|
1892
|
+
|
|
1893
|
+
The module includes comprehensive test coverage (100% lines):
|
|
1894
|
+
|
|
1895
|
+
```bash
|
|
1896
|
+
# Run tests
|
|
1897
|
+
yarn test
|
|
1898
|
+
|
|
1899
|
+
# Run tests with coverage
|
|
1900
|
+
yarn test:cov
|
|
1901
|
+
|
|
1902
|
+
# Watch mode
|
|
1903
|
+
yarn test:watch
|
|
1904
|
+
```
|
|
1905
|
+
|
|
1906
|
+
## Development
|
|
1907
|
+
|
|
1908
|
+
Please see [docs/README.md](docs/README.md) for development guidelines.
|
|
1909
|
+
|
|
1910
|
+
## Contributing
|
|
1911
|
+
|
|
1912
|
+
Please see [CONTRIBUTING.md](CONTRIBUTING.md) for contribution guidelines.
|
|
1913
|
+
|
|
1914
|
+
## License
|
|
1915
|
+
|
|
1916
|
+
ISC
|
|
1917
|
+
|
|
1918
|
+
## Support
|
|
1919
|
+
|
|
1920
|
+
For issues, questions, or contributions, please visit the [GitHub repository](https://github.com/eqxjs/nest-logger).
|
|
1921
|
+
|
|
1922
|
+
## Changelog
|
|
1923
|
+
|
|
1924
|
+
See [CHANGELOG](CHANGELOG) for release notes and version history.
|
|
1925
|
+
|
|
1926
|
+
---
|
|
1927
|
+
|
|
1928
|
+
**Made with โค๏ธ by the EQXJS Team**
|
|
1361
1929
|
- Use M2 for HTTP/protocol-specific operations
|
|
1362
1930
|
- Use M3 for service-to-service operations
|
|
1363
1931
|
|