nestjs-log-decorator 1.3.0 → 1.5.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.
- package/README.md +123 -61
- package/dist/index.cjs +64 -152
- package/dist/index.d.cts +116 -100
- package/package.json +19 -5
package/README.md
CHANGED
|
@@ -25,14 +25,15 @@ TypeScript decorators that eliminate logging boilerplate from NestJS application
|
|
|
25
25
|
|
|
26
26
|
## Description
|
|
27
27
|
|
|
28
|
-
`@Log()` decorator replaces the try-catch logging pattern in NestJS service methods by automatically logging method invocation
|
|
28
|
+
`@Log()` decorator replaces the try-catch logging pattern in NestJS service methods by automatically logging method success and errors, with optional invocation and result logging.
|
|
29
29
|
|
|
30
30
|
**Key Features**
|
|
31
31
|
|
|
32
32
|
- By default uses structured output
|
|
33
33
|
- Prettifies Axios errors
|
|
34
34
|
- Zero configuration
|
|
35
|
-
-
|
|
35
|
+
- Minimal dependencies
|
|
36
|
+
- Uses default `@nestjs/common` Logger instance
|
|
36
37
|
|
|
37
38
|
## Installation
|
|
38
39
|
|
|
@@ -42,19 +43,17 @@ npm install nestjs-log-decorator @nestjs/common
|
|
|
42
43
|
|
|
43
44
|
## Quick Start
|
|
44
45
|
|
|
46
|
+
Simply apply `@Log()` to your class or method:
|
|
47
|
+
|
|
45
48
|
```typescript
|
|
46
|
-
import { Logger } from '@nestjs/common';
|
|
47
49
|
import { Log } from 'nestjs-log-decorator';
|
|
48
50
|
|
|
49
51
|
class UserService {
|
|
50
|
-
readonly logger = new Logger(UserService.name);
|
|
51
|
-
|
|
52
52
|
@Log()
|
|
53
53
|
createUser(name: string, email: string) {
|
|
54
54
|
return { id: 1, name, email };
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
|
-
|
|
58
57
|
```
|
|
59
58
|
|
|
60
59
|
Once a service method is called, it will log the method invocation with all arguments.
|
|
@@ -104,18 +103,43 @@ const result = await resultPromise;
|
|
|
104
103
|
// [UserService] { method: 'createUser', state: 'success', args: { name: 'John' } }
|
|
105
104
|
```
|
|
106
105
|
|
|
106
|
+
### Result Logging
|
|
107
|
+
|
|
108
|
+
If you want to include method results in success logs, use the `result` option.
|
|
109
|
+
|
|
110
|
+
```typescript
|
|
111
|
+
class UserService {
|
|
112
|
+
// Logs result as-is
|
|
113
|
+
@Log({ result: true })
|
|
114
|
+
findUser(id: number) {
|
|
115
|
+
return { id, name: 'John', email: 'john@example.com' };
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Logs formatted result
|
|
119
|
+
@Log({
|
|
120
|
+
result: (res: { id: number; name: string; email: string }) => ({ id: res.id, name: res.name }),
|
|
121
|
+
})
|
|
122
|
+
findPublicUser(id: number) {
|
|
123
|
+
return { id, name: 'John', email: 'john@example.com' };
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Example success output:
|
|
129
|
+
|
|
130
|
+
```typescript
|
|
131
|
+
// [UserService] { method: 'findUser', state: 'success', args: { id: 1 }, result: { id: 1, name: 'John', email: 'john@example.com' } }
|
|
132
|
+
// [UserService] { method: 'findPublicUser', state: 'success', args: { id: 1 }, result: { id: 1, name: 'John' } }
|
|
133
|
+
```
|
|
134
|
+
|
|
107
135
|
### Complete Example
|
|
108
136
|
|
|
109
|
-
After installation, no additional configuration is needed,
|
|
137
|
+
After installation, no additional configuration is needed. If the class has `logger` properly, the `@Log()` decorator will use it log method. If the logger is missing, the decorator will inject `@nestjs/common` Logger instance using the class name as the context.
|
|
110
138
|
|
|
111
139
|
```typescript
|
|
112
|
-
import { Logger } from '@nestjs/common';
|
|
113
140
|
import { Log } from 'nestjs-log-decorator';
|
|
114
141
|
|
|
115
|
-
|
|
116
142
|
class PaymentService {
|
|
117
|
-
// `logger` property will be used by decorator
|
|
118
|
-
readonly logger = new Logger(PaymentService.name);
|
|
119
143
|
|
|
120
144
|
@Log()
|
|
121
145
|
async processPayment(amount: number, currency: string) {
|
|
@@ -130,7 +154,25 @@ class PaymentService {
|
|
|
130
154
|
}
|
|
131
155
|
```
|
|
132
156
|
|
|
133
|
-
|
|
157
|
+
#### Explicit Logger (Optional)
|
|
158
|
+
|
|
159
|
+
If you need a custom logger (e.g., for testing or a different context), you can still define your own:
|
|
160
|
+
|
|
161
|
+
```typescript
|
|
162
|
+
import { Logger } from '@nestjs/common';
|
|
163
|
+
import { Log } from 'nestjs-log-decorator';
|
|
164
|
+
|
|
165
|
+
@Log()
|
|
166
|
+
class PaymentService {
|
|
167
|
+
// Explicit logger takes precedence over auto-injected one
|
|
168
|
+
readonly logger = new Logger('CustomPaymentContext');
|
|
169
|
+
|
|
170
|
+
async processPayment(amount: number, currency: string) {
|
|
171
|
+
// Logs using the explicit logger with 'CustomPaymentContext' context
|
|
172
|
+
return await this.gateway.processPayment(amount, currency);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
```
|
|
134
176
|
|
|
135
177
|
## How It Works
|
|
136
178
|
|
|
@@ -141,38 +183,38 @@ The `@Log()` decorator wraps your methods with automatic try-catch logging. It e
|
|
|
141
183
|
│ @Log() Decorator Flow │
|
|
142
184
|
└─────────────────────────────────────────────────────────────────────────────┘
|
|
143
185
|
|
|
144
|
-
Method Call
|
|
145
|
-
│
|
|
146
|
-
▼
|
|
147
|
-
┌──────────────────┐
|
|
148
|
-
│ Extract Args │ ──▶ { id: 1, name: 'John' }
|
|
149
|
-
│ (auto or custom) │
|
|
150
|
-
└────────┬─────────┘
|
|
151
|
-
│
|
|
152
|
-
▼
|
|
153
|
-
┌──────────────────┐ ┌─────────────────────────────────────┐
|
|
154
|
-
│ onInvoke: true? │──YES─▶│ logger.log({ state: 'invoked' }) │
|
|
155
|
-
└────────┬─────────┘ └─────────────────────────────────────┘
|
|
156
|
-
│ NO
|
|
157
|
-
▼
|
|
158
|
-
┌──────────────────────┐
|
|
159
|
-
│ Execute Original │
|
|
160
|
-
│ Method (sync/async) │
|
|
161
|
-
└────────┬─────────────┘
|
|
162
|
-
│
|
|
163
|
-
┌────┴────┐
|
|
164
|
-
▼ ▼
|
|
165
|
-
SUCCESS ERROR
|
|
166
|
-
│ │
|
|
167
|
-
▼ ▼
|
|
168
|
-
┌────────┐ ┌──────────────────────────────────────────────────────┐
|
|
169
|
-
│log() │ │ logger.error({ state: 'error', error: prettify(e) })│
|
|
170
|
-
│success │ │ (Axios errors auto-prettified) │
|
|
171
|
-
└────────┘ └──────────────────────────────────────────────────────┘
|
|
172
|
-
│ │
|
|
173
|
-
▼ ▼
|
|
174
|
-
Return Re-throw
|
|
175
|
-
Result Error
|
|
186
|
+
Method Call
|
|
187
|
+
│
|
|
188
|
+
▼
|
|
189
|
+
┌──────────────────┐
|
|
190
|
+
│ Extract Args │ ──▶ { id: 1, name: 'John' }
|
|
191
|
+
│ (auto or custom) │
|
|
192
|
+
└────────┬─────────┘
|
|
193
|
+
│
|
|
194
|
+
▼
|
|
195
|
+
┌──────────────────┐ ┌─────────────────────────────────────┐
|
|
196
|
+
│ onInvoke: true? │──YES─▶│ logger.log({ state: 'invoked' }) │
|
|
197
|
+
└────────┬─────────┘ └─────────────────────────────────────┘
|
|
198
|
+
│ NO
|
|
199
|
+
▼
|
|
200
|
+
┌──────────────────────┐
|
|
201
|
+
│ Execute Original │
|
|
202
|
+
│ Method (sync/async) │
|
|
203
|
+
└────────┬─────────────┘
|
|
204
|
+
│
|
|
205
|
+
┌────┴────┐
|
|
206
|
+
▼ ▼
|
|
207
|
+
SUCCESS ERROR
|
|
208
|
+
│ │
|
|
209
|
+
▼ ▼
|
|
210
|
+
┌────────┐ ┌──────────────────────────────────────────────────────┐
|
|
211
|
+
│log() │ │ logger.error({ state: 'error', error: prettify(e) })│
|
|
212
|
+
│success │ │ (Axios errors auto-prettified) │
|
|
213
|
+
└────────┘ └──────────────────────────────────────────────────────┘
|
|
214
|
+
│ │
|
|
215
|
+
▼ ▼
|
|
216
|
+
Return Re-throw
|
|
217
|
+
Result Error
|
|
176
218
|
```
|
|
177
219
|
|
|
178
220
|
## Usage
|
|
@@ -182,9 +224,9 @@ The `@Log()` decorator wraps your methods with automatic try-catch logging. It e
|
|
|
182
224
|
Apply `@Log()` to specific methods for granular control:
|
|
183
225
|
|
|
184
226
|
```typescript
|
|
185
|
-
|
|
186
|
-
readonly logger = new Logger(DataService.name);
|
|
227
|
+
import { Log } from 'nestjs-log-decorator';
|
|
187
228
|
|
|
229
|
+
class DataService {
|
|
188
230
|
@Log()
|
|
189
231
|
async fetchData(id: number) {
|
|
190
232
|
// This method is logged
|
|
@@ -203,14 +245,11 @@ class DataService {
|
|
|
203
245
|
If you want to log all methods in a class, use the `@Log()` decorator on its definition:
|
|
204
246
|
|
|
205
247
|
```typescript
|
|
206
|
-
import { Logger } from '@nestjs/common';
|
|
207
248
|
import { Log } from 'nestjs-log-decorator';
|
|
208
249
|
|
|
209
250
|
@Log()
|
|
210
251
|
@Injectable()
|
|
211
252
|
class PaymentService {
|
|
212
|
-
readonly logger = new Logger(PaymentService.name);
|
|
213
|
-
|
|
214
253
|
processPayment(amount: number, currency: string) {
|
|
215
254
|
// Automatically logged on success or error
|
|
216
255
|
return { status: 'completed', amount, currency };
|
|
@@ -232,8 +271,6 @@ import { Log, NoLog } from 'nestjs-log-decorator';
|
|
|
232
271
|
|
|
233
272
|
@Log()
|
|
234
273
|
class UserService {
|
|
235
|
-
readonly logger = new Logger(UserService.name);
|
|
236
|
-
|
|
237
274
|
createUser(name: string) {
|
|
238
275
|
// Logged
|
|
239
276
|
return { name };
|
|
@@ -268,8 +305,6 @@ Class-level with `onInvoke`:
|
|
|
268
305
|
```typescript
|
|
269
306
|
@Log({ onInvoke: true })
|
|
270
307
|
class ApiService {
|
|
271
|
-
readonly logger = new Logger(ApiService.name);
|
|
272
|
-
|
|
273
308
|
// All methods will log invocation + completion
|
|
274
309
|
}
|
|
275
310
|
```
|
|
@@ -289,8 +324,6 @@ interface LargePayload {
|
|
|
289
324
|
}
|
|
290
325
|
|
|
291
326
|
class SyncService {
|
|
292
|
-
readonly logger = new Logger(SyncService.name);
|
|
293
|
-
|
|
294
327
|
// Only log the ID, exclude the large payload
|
|
295
328
|
@Log({ args: (id: number, _payload: LargePayload) => ({ id }) })
|
|
296
329
|
async syncData(id: number, payload: LargePayload) {
|
|
@@ -319,6 +352,31 @@ class SyncService {
|
|
|
319
352
|
[SyncService] { method: 'lookupUser', state: 'success', args: '1:John' }
|
|
320
353
|
```
|
|
321
354
|
|
|
355
|
+
### `result` — Success Result Logging
|
|
356
|
+
|
|
357
|
+
Control how return values are included in success logs:
|
|
358
|
+
|
|
359
|
+
- `result: true` logs the raw return value
|
|
360
|
+
- `result: (value) => ...` logs a formatted value
|
|
361
|
+
|
|
362
|
+
```typescript
|
|
363
|
+
class PaymentService {
|
|
364
|
+
// Log full return value
|
|
365
|
+
@Log({ result: true })
|
|
366
|
+
createPayment(id: number) {
|
|
367
|
+
return { id, status: 'success', cardToken: 'tok_123' };
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// Log only safe result fields
|
|
371
|
+
@Log({
|
|
372
|
+
result: (res: { id: number; status: string; cardToken: string }) => ({ id: res.id, status: res.status }),
|
|
373
|
+
})
|
|
374
|
+
createPaymentSafe(id: number) {
|
|
375
|
+
return { id, status: 'success', cardToken: 'tok_123' };
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
```
|
|
379
|
+
|
|
322
380
|
## Log Format
|
|
323
381
|
|
|
324
382
|
All logs are structured JSON objects:
|
|
@@ -329,7 +387,9 @@ All logs are structured JSON objects:
|
|
|
329
387
|
{
|
|
330
388
|
method: 'methodName',
|
|
331
389
|
state: 'success',
|
|
332
|
-
args: { param1: value1, param2: value2 }
|
|
390
|
+
args: { param1: value1, param2: value2 },
|
|
391
|
+
// Present only when `result` option is configured
|
|
392
|
+
result: { any: 'value' }
|
|
333
393
|
}
|
|
334
394
|
```
|
|
335
395
|
|
|
@@ -437,12 +497,13 @@ async fetchData(url: string) {
|
|
|
437
497
|
|
|
438
498
|
### `Log(options?)`
|
|
439
499
|
|
|
440
|
-
Decorator that can be applied to classes or methods.
|
|
500
|
+
Decorator that can be applied to classes or methods. When applied to a class, by default all methods are logged.
|
|
441
501
|
|
|
442
502
|
| Option | Type | Default | Description |
|
|
443
503
|
|--------|------|---------|-------------|
|
|
444
504
|
| `onInvoke` | `boolean` | `false` | Log method invocation before execution |
|
|
445
505
|
| `args` | `(...args) => any` | `undefined` | Custom function to format logged arguments |
|
|
506
|
+
| `result` | `true \| (result) => any` | `undefined` | Include and optionally format successful method result |
|
|
446
507
|
|
|
447
508
|
### `NoLog()`
|
|
448
509
|
|
|
@@ -459,7 +520,7 @@ import { Log, NoLog, LogOptions, Loggable, isLoggable } from 'nestjs-log-decorat
|
|
|
459
520
|
| `Log` | Decorator | Main logging decorator |
|
|
460
521
|
| `NoLog` | Decorator | Exclude method from logging |
|
|
461
522
|
| `LogOptions` | Interface | Options for `@Log()` decorator |
|
|
462
|
-
| `Loggable` | Interface | Interface for classes with a `logger` property |
|
|
523
|
+
| `Loggable` | Interface | Interface for classes with a `logger` property (optional) |
|
|
463
524
|
| `isLoggable` | Function | Type guard to check if instance has logger |
|
|
464
525
|
|
|
465
526
|
## Advanced Example
|
|
@@ -471,6 +532,7 @@ import { Log, NoLog } from 'nestjs-log-decorator';
|
|
|
471
532
|
@Log()
|
|
472
533
|
@Injectable()
|
|
473
534
|
export class OrderService {
|
|
535
|
+
// Optional: explicit logger takes precedence over auto-injected one
|
|
474
536
|
readonly logger = new Logger(OrderService.name);
|
|
475
537
|
|
|
476
538
|
constructor(
|
|
@@ -485,9 +547,9 @@ export class OrderService {
|
|
|
485
547
|
}
|
|
486
548
|
|
|
487
549
|
// Logged with invocation + custom args (exclude sensitive card data)
|
|
488
|
-
@Log({
|
|
489
|
-
onInvoke: true,
|
|
490
|
-
args: (orderId: number, _cardDetails: CardDetails) => ({ orderId })
|
|
550
|
+
@Log({
|
|
551
|
+
onInvoke: true,
|
|
552
|
+
args: (orderId: number, _cardDetails: CardDetails) => ({ orderId })
|
|
491
553
|
})
|
|
492
554
|
async processPayment(orderId: number, cardDetails: CardDetails) {
|
|
493
555
|
const result = await this.paymentGateway.charge(orderId, cardDetails);
|
package/dist/index.cjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
require("
|
|
1
|
+
let base_decorators = require("base-decorators");
|
|
2
|
+
let _nestjs_common = require("@nestjs/common");
|
|
2
3
|
|
|
3
4
|
//#region src/axios/axios.stub.ts
|
|
4
5
|
/**
|
|
@@ -67,35 +68,40 @@ var LogWrapper = class {
|
|
|
67
68
|
this.method = method;
|
|
68
69
|
this.args = args;
|
|
69
70
|
}
|
|
70
|
-
invoked() {
|
|
71
|
+
invoked(message) {
|
|
71
72
|
this.logger.log({
|
|
72
73
|
method: this.method,
|
|
73
74
|
state: "invoked",
|
|
74
|
-
args: this.args
|
|
75
|
+
args: this.args,
|
|
76
|
+
...message ? { message } : {}
|
|
75
77
|
});
|
|
76
78
|
}
|
|
77
|
-
success() {
|
|
79
|
+
success(message, additionalFields = {}) {
|
|
78
80
|
this.logger.log({
|
|
79
81
|
method: this.method,
|
|
80
82
|
state: "success",
|
|
81
|
-
args: this.args
|
|
83
|
+
args: this.args,
|
|
84
|
+
...message ? { message } : {},
|
|
85
|
+
...additionalFields
|
|
82
86
|
});
|
|
83
87
|
}
|
|
84
|
-
error(error) {
|
|
88
|
+
error(error, message) {
|
|
85
89
|
try {
|
|
86
90
|
const pretifiedError = prettifyAxiosError(error);
|
|
87
91
|
this.logger.error({
|
|
88
92
|
method: this.method,
|
|
89
93
|
state: "error",
|
|
90
94
|
args: this.args,
|
|
91
|
-
error: pretifiedError
|
|
95
|
+
error: pretifiedError,
|
|
96
|
+
...message ? { message } : {}
|
|
92
97
|
});
|
|
93
98
|
} catch {
|
|
94
99
|
this.logger.error({
|
|
95
100
|
method: this.method,
|
|
96
101
|
state: "error",
|
|
97
102
|
args: this.args,
|
|
98
|
-
error
|
|
103
|
+
error,
|
|
104
|
+
...message ? { message } : {}
|
|
99
105
|
});
|
|
100
106
|
}
|
|
101
107
|
}
|
|
@@ -104,95 +110,24 @@ const isLoggable = (instance) => {
|
|
|
104
110
|
return typeof instance === "object" && instance !== null && "logger" in instance;
|
|
105
111
|
};
|
|
106
112
|
/**
|
|
107
|
-
* Creates a LogWrapper instance
|
|
108
|
-
* @internal
|
|
109
|
-
*/
|
|
110
|
-
const createLogWrapper = (instance, className, methodName, argsObject) => {
|
|
111
|
-
if (!isLoggable(instance)) throw new Error(`Logger not found in ${className}. Please add: readonly logger = new Logger(${className}.name)`);
|
|
112
|
-
return new LogWrapper(instance.logger, methodName, argsObject);
|
|
113
|
-
};
|
|
114
|
-
/**
|
|
115
|
-
* Builds an object mapping parameter names to their values.
|
|
116
|
-
*
|
|
117
|
-
* Creates a record where keys are parameter names and values are the
|
|
118
|
-
* corresponding argument values passed to the function.
|
|
119
|
-
*
|
|
120
|
-
* @param parameterNames - Array of parameter names
|
|
121
|
-
* @param args - Array of argument values
|
|
122
|
-
* @returns Object mapping parameter names to values
|
|
123
|
-
*
|
|
124
|
-
* @example
|
|
125
|
-
* buildArgsObject(['id', 'name'], [1, 'John'])
|
|
126
|
-
* // Returns: { id: 1, name: 'John' }
|
|
127
|
-
*
|
|
128
|
-
* @internal
|
|
129
|
-
*/
|
|
130
|
-
const buildArgsObject = (parameterNames, args) => {
|
|
131
|
-
if (args.length === 0 && parameterNames.length === 0) return;
|
|
132
|
-
const argsObject = {};
|
|
133
|
-
parameterNames.forEach((paramName, index) => {
|
|
134
|
-
if (index < args.length) argsObject[paramName] = args[index];
|
|
135
|
-
});
|
|
136
|
-
return argsObject;
|
|
137
|
-
};
|
|
138
|
-
|
|
139
|
-
//#endregion
|
|
140
|
-
//#region src/decorate/applyToMethod.ts
|
|
141
|
-
/**
|
|
142
|
-
* Applies logging to a single method.
|
|
143
|
-
* @internal
|
|
144
|
-
*/
|
|
145
|
-
const applyToMethod = (target, propertyKey, descriptor, { onInvoke: shouldLogInvoke = false, args: formatArgs } = {}) => {
|
|
146
|
-
const originalMethod = descriptor.value;
|
|
147
|
-
const parameterNames = getParameterNames(originalMethod);
|
|
148
|
-
descriptor.value = function(...args) {
|
|
149
|
-
const argsObject = formatArgs ? formatArgs(...args) : buildArgsObject(parameterNames, args);
|
|
150
|
-
const logWrapper = createLogWrapper(this, target.constructor.name, propertyKey, argsObject);
|
|
151
|
-
if (shouldLogInvoke) logWrapper.invoked();
|
|
152
|
-
try {
|
|
153
|
-
const result = originalMethod.apply(this, args);
|
|
154
|
-
if (result instanceof Promise) return handleAsyncExecution(result, logWrapper);
|
|
155
|
-
logWrapper.success();
|
|
156
|
-
return result;
|
|
157
|
-
} catch (error) {
|
|
158
|
-
logWrapper.error(error);
|
|
159
|
-
throw error;
|
|
160
|
-
}
|
|
161
|
-
};
|
|
162
|
-
return descriptor;
|
|
163
|
-
};
|
|
164
|
-
/**
|
|
165
|
-
* Extracts parameter names from a function signature.
|
|
113
|
+
* Creates a LogWrapper instance for structured method logging.
|
|
166
114
|
*
|
|
167
|
-
*
|
|
168
|
-
*
|
|
115
|
+
* When the target instance already has a `logger` property (i.e., satisfies
|
|
116
|
+
* the {@link Loggable} interface), that logger is used directly. Otherwise,
|
|
117
|
+
* a new `Logger` from `@nestjs/common` is created with `className` as its
|
|
118
|
+
* context and assigned to `instance.logger`, so subsequent calls reuse it.
|
|
169
119
|
*
|
|
170
|
-
* @param
|
|
171
|
-
* @
|
|
172
|
-
*
|
|
173
|
-
* @
|
|
174
|
-
*
|
|
175
|
-
* getParameterNames(example) // Returns: ['id', 'name']
|
|
120
|
+
* @param instance - The class instance whose method is being logged
|
|
121
|
+
* @param className - The name of the class (used as Logger context if auto-injected)
|
|
122
|
+
* @param methodName - The name of the method being logged
|
|
123
|
+
* @param argsObject - Formatted arguments to include in the log entry
|
|
124
|
+
* @returns A configured {@link LogWrapper} ready for invoked/success/error calls
|
|
176
125
|
*
|
|
177
126
|
* @internal
|
|
178
127
|
*/
|
|
179
|
-
const
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
return match[1].split(",").map((param) => param.trim().split(/[=:]/)[0].trim()).filter((param) => param.length > 0);
|
|
183
|
-
};
|
|
184
|
-
/**
|
|
185
|
-
* Handles execution of async methods with proper logging.
|
|
186
|
-
* @internal
|
|
187
|
-
*/
|
|
188
|
-
const handleAsyncExecution = (result, logWrapper) => {
|
|
189
|
-
return result.then((value) => {
|
|
190
|
-
logWrapper.success();
|
|
191
|
-
return value;
|
|
192
|
-
}).catch((error) => {
|
|
193
|
-
logWrapper.error(error);
|
|
194
|
-
throw error;
|
|
195
|
-
});
|
|
128
|
+
const createLogWrapper = (instance, className, methodName, argsObject) => {
|
|
129
|
+
if (!isLoggable(instance)) instance.logger = new _nestjs_common.Logger(className);
|
|
130
|
+
return new LogWrapper(instance.logger, methodName, argsObject);
|
|
196
131
|
};
|
|
197
132
|
|
|
198
133
|
//#endregion
|
|
@@ -203,23 +138,6 @@ const handleAsyncExecution = (result, logWrapper) => {
|
|
|
203
138
|
*/
|
|
204
139
|
const NO_LOG_METADATA_KEY = Symbol("noLog");
|
|
205
140
|
|
|
206
|
-
//#endregion
|
|
207
|
-
//#region src/decorate/applyToClass.ts
|
|
208
|
-
/**
|
|
209
|
-
* Applies logging to all methods in a class.
|
|
210
|
-
* @internal
|
|
211
|
-
*/
|
|
212
|
-
const applyToClass = (target, options) => {
|
|
213
|
-
Object.getOwnPropertyNames(target.prototype).forEach((propertyName) => {
|
|
214
|
-
if (propertyName === "constructor") return;
|
|
215
|
-
const descriptor = Object.getOwnPropertyDescriptor(target.prototype, propertyName);
|
|
216
|
-
if (!descriptor || typeof descriptor.value !== "function") return;
|
|
217
|
-
if (descriptor.value[NO_LOG_METADATA_KEY] === true) return;
|
|
218
|
-
applyToMethod(target.prototype, propertyName, descriptor, options);
|
|
219
|
-
Object.defineProperty(target.prototype, propertyName, descriptor);
|
|
220
|
-
});
|
|
221
|
-
};
|
|
222
|
-
|
|
223
141
|
//#endregion
|
|
224
142
|
//#region src/log.decorator.ts
|
|
225
143
|
/**
|
|
@@ -229,6 +147,7 @@ const applyToClass = (target, options) => {
|
|
|
229
147
|
*
|
|
230
148
|
* **Usage on Classes:**
|
|
231
149
|
* When applied to a class, wraps all methods in the class with logging.
|
|
150
|
+
* A `logger` property is auto-injected if not already defined.
|
|
232
151
|
*
|
|
233
152
|
* **Usage on Methods:**
|
|
234
153
|
* When applied to a method, wraps only that specific method with logging.
|
|
@@ -238,13 +157,10 @@ const applyToClass = (target, options) => {
|
|
|
238
157
|
* - Successful completion with arguments
|
|
239
158
|
* - Errors with arguments and error details (Axios errors are automatically prettified)
|
|
240
159
|
*
|
|
241
|
-
* **Requirements:**
|
|
242
|
-
* The class must have a `logger` property (typically a NestJS Logger instance).
|
|
243
|
-
*
|
|
244
160
|
* **Log Format:**
|
|
245
161
|
* All logs are output as structured objects with the following format:
|
|
246
162
|
* - Invocation: `{ method: string, state: 'invoked', args: Record<string, any> }` (only when `onInvoke: true`)
|
|
247
|
-
* - Success: `{ method: string, state: 'success', args: Record<string, any
|
|
163
|
+
* - Success: `{ method: string, state: 'success', args: Record<string, any>, result?: unknown }`
|
|
248
164
|
* - Error: `{ method: string, state: 'error', args: Record<string, any>, error: Error | PrettifiedAxiosError }`
|
|
249
165
|
*
|
|
250
166
|
* **Custom Argument Formatting:**
|
|
@@ -253,6 +169,11 @@ const applyToClass = (target, options) => {
|
|
|
253
169
|
* - Logging only specific arguments
|
|
254
170
|
* - Transforming sensitive data before logging
|
|
255
171
|
*
|
|
172
|
+
* **Result Logging:**
|
|
173
|
+
* Use the `result` option to include successful return values in success logs.
|
|
174
|
+
* - `result: true` logs the raw returned value
|
|
175
|
+
* - `result: (value) => ...` logs a formatted value
|
|
176
|
+
*
|
|
256
177
|
* **Error Handling:**
|
|
257
178
|
* - Axios errors are automatically prettified using `prettifyAxiosError` to provide structured error information
|
|
258
179
|
* - Regular errors are logged as-is
|
|
@@ -265,11 +186,9 @@ const applyToClass = (target, options) => {
|
|
|
265
186
|
* - Methods with no arguments
|
|
266
187
|
*
|
|
267
188
|
* @example
|
|
268
|
-
* // Class-level usage - logs all methods
|
|
189
|
+
* // Class-level usage - logs all methods, logger auto-injected
|
|
269
190
|
* @Log()
|
|
270
191
|
* class UserService {
|
|
271
|
-
* readonly logger = new Logger(UserService.name)
|
|
272
|
-
*
|
|
273
192
|
* createUser(name: string, email: string) {
|
|
274
193
|
* return { id: 1, name, email }
|
|
275
194
|
* }
|
|
@@ -282,8 +201,6 @@ const applyToClass = (target, options) => {
|
|
|
282
201
|
* @example
|
|
283
202
|
* // Method-level usage - logs only specific method
|
|
284
203
|
* class DataService {
|
|
285
|
-
* readonly logger = new Logger(DataService.name)
|
|
286
|
-
*
|
|
287
204
|
* @Log({ onInvoke: true })
|
|
288
205
|
* async fetchData(id: number) {
|
|
289
206
|
* const data = await this.repository.findById(id)
|
|
@@ -295,8 +212,7 @@ const applyToClass = (target, options) => {
|
|
|
295
212
|
* return 'helper'
|
|
296
213
|
* }
|
|
297
214
|
* }
|
|
298
|
-
*
|
|
299
|
-
* @example
|
|
215
|
+
*
|
|
300
216
|
* // Error handling with regular errors
|
|
301
217
|
* class PaymentService {
|
|
302
218
|
* readonly logger = new Logger(PaymentService.name)
|
|
@@ -342,17 +258,15 @@ const applyToClass = (target, options) => {
|
|
|
342
258
|
* @example
|
|
343
259
|
* // Custom argument formatting - exclude large objects from logs
|
|
344
260
|
* class SyncService {
|
|
345
|
-
* readonly logger = new Logger(SyncService.name)
|
|
346
|
-
*
|
|
347
261
|
* @Log({ args: (loanId: number) => ({ loanId }) })
|
|
348
|
-
* async syncLoan(loanId: number, loanData?:
|
|
262
|
+
* async syncLoan(loanId: number, loanData?: unknown) {
|
|
349
263
|
* // loanData is excluded from logs due to large size
|
|
350
264
|
* // Only loanId will be logged
|
|
351
265
|
* return this.processLoan(loanId, loanData)
|
|
352
266
|
* }
|
|
353
|
-
*
|
|
267
|
+
*
|
|
354
268
|
* @Log({ args: (loanId: number, transactionId: number) => ({ loanId, transactionId }) })
|
|
355
|
-
* async syncPayment(loanId: number, transactionId: number, loanData?:
|
|
269
|
+
* async syncPayment(loanId: number, transactionId: number, loanData?: unknown) {
|
|
356
270
|
* // Only loanId and transactionId are logged, loanData is excluded
|
|
357
271
|
* return this.processPayment(loanId, transactionId, loanData)
|
|
358
272
|
* }
|
|
@@ -361,22 +275,26 @@ const applyToClass = (target, options) => {
|
|
|
361
275
|
* // Logs output:
|
|
362
276
|
* // [SyncService] { method: 'syncLoan', state: 'success', args: { loanId: 123 } }
|
|
363
277
|
* // [SyncService] { method: 'syncPayment', state: 'success', args: { loanId: 123, transactionId: 456 } }
|
|
364
|
-
*
|
|
278
|
+
*
|
|
365
279
|
* @param options - Configuration options for the decorator
|
|
366
|
-
* @throws {Error} If the logger property is not found in the class instance
|
|
367
|
-
*
|
|
368
280
|
* @returns Decorator function that can be applied to classes or methods
|
|
369
281
|
*/
|
|
370
|
-
const Log = (
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
282
|
+
const Log = ({ onInvoke: shouldLogInvoke = false, args: formatArgs, result: formatResult } = {}) => (0, base_decorators.Effect)(({ args, argsObject, target, propertyKey, className }) => {
|
|
283
|
+
const formattedArgs = formatArgs ? formatArgs(...args) : argsObject;
|
|
284
|
+
const resultFormatter = typeof formatResult === "function" ? formatResult : (value) => value;
|
|
285
|
+
const logger = createLogWrapper(target, className, String(propertyKey), formattedArgs);
|
|
286
|
+
return {
|
|
287
|
+
onInvoke: shouldLogInvoke ? () => logger.invoked() : void 0,
|
|
288
|
+
onReturn: ({ result }) => {
|
|
289
|
+
logger.success(void 0, formatResult ? { result: resultFormatter(result) } : void 0);
|
|
290
|
+
return result;
|
|
291
|
+
},
|
|
292
|
+
onError: ({ error }) => {
|
|
293
|
+
logger.error(error);
|
|
294
|
+
throw error;
|
|
375
295
|
}
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
});
|
|
379
|
-
};
|
|
296
|
+
};
|
|
297
|
+
}, NO_LOG_METADATA_KEY);
|
|
380
298
|
/**
|
|
381
299
|
* Method decorator that prevents logging when used with class-level @Log()
|
|
382
300
|
*
|
|
@@ -388,8 +306,6 @@ const Log = (options = {}) => {
|
|
|
388
306
|
* @example
|
|
389
307
|
* @Log()
|
|
390
308
|
* class UserService {
|
|
391
|
-
* readonly logger = new Logger(UserService.name)
|
|
392
|
-
*
|
|
393
309
|
* createUser(name: string) {
|
|
394
310
|
* // This will be logged
|
|
395
311
|
* return { name }
|
|
@@ -425,27 +341,23 @@ const Log = (options = {}) => {
|
|
|
425
341
|
* return 'helper'
|
|
426
342
|
* }
|
|
427
343
|
* }
|
|
428
|
-
*
|
|
344
|
+
*
|
|
429
345
|
* @returns {MethodDecorator} The method decorator function
|
|
430
346
|
*/
|
|
431
|
-
const NoLog = () =>
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
}
|
|
347
|
+
const NoLog = () => (0, base_decorators.SetMeta)(NO_LOG_METADATA_KEY, true);
|
|
348
|
+
|
|
349
|
+
//#endregion
|
|
350
|
+
//#region src/axios/isTimoutError.ts
|
|
351
|
+
function isTimeoutError(error) {
|
|
352
|
+
return error.code === "ECONNABORTED" || error.code === "ETIMEDOUT";
|
|
353
|
+
}
|
|
438
354
|
|
|
439
355
|
//#endregion
|
|
440
356
|
exports.Log = Log;
|
|
441
357
|
exports.LogWrapper = LogWrapper;
|
|
442
358
|
exports.NO_LOG_METADATA_KEY = NO_LOG_METADATA_KEY;
|
|
443
359
|
exports.NoLog = NoLog;
|
|
444
|
-
exports.applyToClass = applyToClass;
|
|
445
|
-
exports.applyToMethod = applyToMethod;
|
|
446
|
-
exports.buildArgsObject = buildArgsObject;
|
|
447
360
|
exports.createLogWrapper = createLogWrapper;
|
|
448
|
-
exports.getParameterNames = getParameterNames;
|
|
449
|
-
exports.handleAsyncExecution = handleAsyncExecution;
|
|
450
361
|
exports.isLoggable = isLoggable;
|
|
362
|
+
exports.isTimeoutError = isTimeoutError;
|
|
451
363
|
exports.prettifyAxiosError = prettifyAxiosError;
|
package/dist/index.d.cts
CHANGED
|
@@ -2,10 +2,11 @@ import { Logger } from "@nestjs/common";
|
|
|
2
2
|
|
|
3
3
|
//#region src/types.d.ts
|
|
4
4
|
type LogArgsFormatter<TArgs extends unknown[]> = (...args: TArgs) => string | number | Record<string, unknown> | undefined;
|
|
5
|
+
type LogResultFormatter<TResult = unknown> = (result: TResult) => unknown;
|
|
5
6
|
/**
|
|
6
7
|
* Configuration options for the Log decorator.
|
|
7
8
|
*/
|
|
8
|
-
interface LogOptions<TArgs extends unknown[] = unknown[]> {
|
|
9
|
+
interface LogOptions<TArgs extends unknown[] = unknown[], TResult = unknown> {
|
|
9
10
|
/**
|
|
10
11
|
* When true, logs method invocation with arguments.
|
|
11
12
|
* When false or not set, only logs success and error states.
|
|
@@ -28,6 +29,21 @@ interface LogOptions<TArgs extends unknown[] = unknown[]> {
|
|
|
28
29
|
* @returns Formatted arguments as string, number, object, or undefined
|
|
29
30
|
*/
|
|
30
31
|
args?: LogArgsFormatter<TArgs>;
|
|
32
|
+
/**
|
|
33
|
+
* Controls how successful method result is logged.
|
|
34
|
+
*
|
|
35
|
+
* - `true`: logs the returned result value as-is
|
|
36
|
+
* - formatter function: receives the method result and returns a formatted value
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* // Log raw result
|
|
40
|
+
* @Log({ result: true })
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* // Log only selected result fields
|
|
44
|
+
* @Log({ result: (res: { id: number; data: unknown }) => ({ id: res.id }) })
|
|
45
|
+
*/
|
|
46
|
+
result?: true | LogResultFormatter<TResult>;
|
|
31
47
|
}
|
|
32
48
|
/**
|
|
33
49
|
* Symbol used to mark methods that should not be logged
|
|
@@ -35,59 +51,23 @@ interface LogOptions<TArgs extends unknown[] = unknown[]> {
|
|
|
35
51
|
*/
|
|
36
52
|
declare const NO_LOG_METADATA_KEY: unique symbol;
|
|
37
53
|
//#endregion
|
|
38
|
-
//#region src/LogWrapper.d.ts
|
|
39
|
-
/**
|
|
40
|
-
* Wrapper class for logging operations with consistent format.
|
|
41
|
-
* @internal
|
|
42
|
-
*/
|
|
43
|
-
declare class LogWrapper {
|
|
44
|
-
private readonly logger;
|
|
45
|
-
private readonly method;
|
|
46
|
-
private readonly args;
|
|
47
|
-
constructor(logger: Logger, method: string, args: string | number | Record<string, unknown> | undefined);
|
|
48
|
-
invoked(): void;
|
|
49
|
-
success(): void;
|
|
50
|
-
error(error: unknown): void;
|
|
51
|
-
}
|
|
52
|
-
/** If you see it, then you probably forgot to add `readonly logger = new Logger(YourClass.name)` to your class */
|
|
53
|
-
interface Loggable {
|
|
54
|
-
logger: Logger;
|
|
55
|
-
}
|
|
56
|
-
declare const isLoggable: (instance: unknown) => instance is Loggable;
|
|
57
|
-
/**
|
|
58
|
-
* Creates a LogWrapper instance with validated logger and built args object.
|
|
59
|
-
* @internal
|
|
60
|
-
*/
|
|
61
|
-
declare const createLogWrapper: (instance: unknown, className: string, methodName: string, argsObject: string | number | Record<string, unknown> | undefined) => LogWrapper;
|
|
62
|
-
/**
|
|
63
|
-
* Builds an object mapping parameter names to their values.
|
|
64
|
-
*
|
|
65
|
-
* Creates a record where keys are parameter names and values are the
|
|
66
|
-
* corresponding argument values passed to the function.
|
|
67
|
-
*
|
|
68
|
-
* @param parameterNames - Array of parameter names
|
|
69
|
-
* @param args - Array of argument values
|
|
70
|
-
* @returns Object mapping parameter names to values
|
|
71
|
-
*
|
|
72
|
-
* @example
|
|
73
|
-
* buildArgsObject(['id', 'name'], [1, 'John'])
|
|
74
|
-
* // Returns: { id: 1, name: 'John' }
|
|
75
|
-
*
|
|
76
|
-
* @internal
|
|
77
|
-
*/
|
|
78
|
-
declare const buildArgsObject: (parameterNames: string[], args: unknown[]) => Record<string, unknown> | undefined;
|
|
79
|
-
//#endregion
|
|
80
54
|
//#region src/log.decorator.d.ts
|
|
81
|
-
type LoggableConstructor = new (...args: any[]) => Loggable;
|
|
82
55
|
/**
|
|
83
56
|
* Decorator function that can be applied to classes or methods.
|
|
84
57
|
* Uses overloads to provide type checking for class decorators while
|
|
85
58
|
* keeping method decorators flexible.
|
|
86
59
|
*/
|
|
87
60
|
interface LogDecorator {
|
|
88
|
-
/**
|
|
89
|
-
|
|
90
|
-
|
|
61
|
+
/**
|
|
62
|
+
* Class decorator - applies logging to all methods in the class.
|
|
63
|
+
* The class no longer needs to define a `logger` property; one will
|
|
64
|
+
* be auto-injected if missing.
|
|
65
|
+
*/
|
|
66
|
+
<T extends new (...args: any[]) => unknown>(target: T): T;
|
|
67
|
+
/**
|
|
68
|
+
* Method decorator - no compile-time constraint on `this`.
|
|
69
|
+
* Wraps only the specific method with logging.
|
|
70
|
+
*/
|
|
91
71
|
(target: object, propertyKey: string | symbol, descriptor: PropertyDescriptor): PropertyDescriptor;
|
|
92
72
|
}
|
|
93
73
|
/**
|
|
@@ -97,6 +77,7 @@ interface LogDecorator {
|
|
|
97
77
|
*
|
|
98
78
|
* **Usage on Classes:**
|
|
99
79
|
* When applied to a class, wraps all methods in the class with logging.
|
|
80
|
+
* A `logger` property is auto-injected if not already defined.
|
|
100
81
|
*
|
|
101
82
|
* **Usage on Methods:**
|
|
102
83
|
* When applied to a method, wraps only that specific method with logging.
|
|
@@ -106,13 +87,10 @@ interface LogDecorator {
|
|
|
106
87
|
* - Successful completion with arguments
|
|
107
88
|
* - Errors with arguments and error details (Axios errors are automatically prettified)
|
|
108
89
|
*
|
|
109
|
-
* **Requirements:**
|
|
110
|
-
* The class must have a `logger` property (typically a NestJS Logger instance).
|
|
111
|
-
*
|
|
112
90
|
* **Log Format:**
|
|
113
91
|
* All logs are output as structured objects with the following format:
|
|
114
92
|
* - Invocation: `{ method: string, state: 'invoked', args: Record<string, any> }` (only when `onInvoke: true`)
|
|
115
|
-
* - Success: `{ method: string, state: 'success', args: Record<string, any
|
|
93
|
+
* - Success: `{ method: string, state: 'success', args: Record<string, any>, result?: unknown }`
|
|
116
94
|
* - Error: `{ method: string, state: 'error', args: Record<string, any>, error: Error | PrettifiedAxiosError }`
|
|
117
95
|
*
|
|
118
96
|
* **Custom Argument Formatting:**
|
|
@@ -121,6 +99,11 @@ interface LogDecorator {
|
|
|
121
99
|
* - Logging only specific arguments
|
|
122
100
|
* - Transforming sensitive data before logging
|
|
123
101
|
*
|
|
102
|
+
* **Result Logging:**
|
|
103
|
+
* Use the `result` option to include successful return values in success logs.
|
|
104
|
+
* - `result: true` logs the raw returned value
|
|
105
|
+
* - `result: (value) => ...` logs a formatted value
|
|
106
|
+
*
|
|
124
107
|
* **Error Handling:**
|
|
125
108
|
* - Axios errors are automatically prettified using `prettifyAxiosError` to provide structured error information
|
|
126
109
|
* - Regular errors are logged as-is
|
|
@@ -133,11 +116,9 @@ interface LogDecorator {
|
|
|
133
116
|
* - Methods with no arguments
|
|
134
117
|
*
|
|
135
118
|
* @example
|
|
136
|
-
* // Class-level usage - logs all methods
|
|
119
|
+
* // Class-level usage - logs all methods, logger auto-injected
|
|
137
120
|
* @Log()
|
|
138
121
|
* class UserService {
|
|
139
|
-
* readonly logger = new Logger(UserService.name)
|
|
140
|
-
*
|
|
141
122
|
* createUser(name: string, email: string) {
|
|
142
123
|
* return { id: 1, name, email }
|
|
143
124
|
* }
|
|
@@ -150,8 +131,6 @@ interface LogDecorator {
|
|
|
150
131
|
* @example
|
|
151
132
|
* // Method-level usage - logs only specific method
|
|
152
133
|
* class DataService {
|
|
153
|
-
* readonly logger = new Logger(DataService.name)
|
|
154
|
-
*
|
|
155
134
|
* @Log({ onInvoke: true })
|
|
156
135
|
* async fetchData(id: number) {
|
|
157
136
|
* const data = await this.repository.findById(id)
|
|
@@ -164,7 +143,6 @@ interface LogDecorator {
|
|
|
164
143
|
* }
|
|
165
144
|
* }
|
|
166
145
|
*
|
|
167
|
-
* @example
|
|
168
146
|
* // Error handling with regular errors
|
|
169
147
|
* class PaymentService {
|
|
170
148
|
* readonly logger = new Logger(PaymentService.name)
|
|
@@ -210,17 +188,15 @@ interface LogDecorator {
|
|
|
210
188
|
* @example
|
|
211
189
|
* // Custom argument formatting - exclude large objects from logs
|
|
212
190
|
* class SyncService {
|
|
213
|
-
* readonly logger = new Logger(SyncService.name)
|
|
214
|
-
*
|
|
215
191
|
* @Log({ args: (loanId: number) => ({ loanId }) })
|
|
216
|
-
* async syncLoan(loanId: number, loanData?:
|
|
192
|
+
* async syncLoan(loanId: number, loanData?: unknown) {
|
|
217
193
|
* // loanData is excluded from logs due to large size
|
|
218
194
|
* // Only loanId will be logged
|
|
219
195
|
* return this.processLoan(loanId, loanData)
|
|
220
196
|
* }
|
|
221
197
|
*
|
|
222
198
|
* @Log({ args: (loanId: number, transactionId: number) => ({ loanId, transactionId }) })
|
|
223
|
-
* async syncPayment(loanId: number, transactionId: number, loanData?:
|
|
199
|
+
* async syncPayment(loanId: number, transactionId: number, loanData?: unknown) {
|
|
224
200
|
* // Only loanId and transactionId are logged, loanData is excluded
|
|
225
201
|
* return this.processPayment(loanId, transactionId, loanData)
|
|
226
202
|
* }
|
|
@@ -231,11 +207,13 @@ interface LogDecorator {
|
|
|
231
207
|
* // [SyncService] { method: 'syncPayment', state: 'success', args: { loanId: 123, transactionId: 456 } }
|
|
232
208
|
*
|
|
233
209
|
* @param options - Configuration options for the decorator
|
|
234
|
-
* @throws {Error} If the logger property is not found in the class instance
|
|
235
|
-
*
|
|
236
210
|
* @returns Decorator function that can be applied to classes or methods
|
|
237
211
|
*/
|
|
238
|
-
declare const Log: <TArgs extends unknown[]
|
|
212
|
+
declare const Log: <TArgs extends unknown[], TResult = unknown>({
|
|
213
|
+
onInvoke: shouldLogInvoke,
|
|
214
|
+
args: formatArgs,
|
|
215
|
+
result: formatResult
|
|
216
|
+
}?: LogOptions<TArgs, TResult>) => LogDecorator;
|
|
239
217
|
/**
|
|
240
218
|
* Method decorator that prevents logging when used with class-level @Log()
|
|
241
219
|
*
|
|
@@ -247,8 +225,6 @@ declare const Log: <TArgs extends unknown[]>(options?: LogOptions<TArgs>) => Log
|
|
|
247
225
|
* @example
|
|
248
226
|
* @Log()
|
|
249
227
|
* class UserService {
|
|
250
|
-
* readonly logger = new Logger(UserService.name)
|
|
251
|
-
*
|
|
252
228
|
* createUser(name: string) {
|
|
253
229
|
* // This will be logged
|
|
254
230
|
* return { name }
|
|
@@ -287,51 +263,91 @@ declare const Log: <TArgs extends unknown[]>(options?: LogOptions<TArgs>) => Log
|
|
|
287
263
|
*
|
|
288
264
|
* @returns {MethodDecorator} The method decorator function
|
|
289
265
|
*/
|
|
290
|
-
declare const NoLog: () =>
|
|
266
|
+
declare const NoLog: () => MethodDecorator;
|
|
291
267
|
//#endregion
|
|
292
|
-
//#region src/
|
|
293
|
-
declare function prettifyAxiosError(error: unknown): unknown;
|
|
294
|
-
//#endregion
|
|
295
|
-
//#region src/decorate/applyToMethod.d.ts
|
|
296
|
-
type MethodFunction = (...args: unknown[]) => unknown;
|
|
268
|
+
//#region src/LogWrapper.d.ts
|
|
297
269
|
/**
|
|
298
|
-
*
|
|
270
|
+
* Wrapper class for logging operations with consistent format.
|
|
299
271
|
* @internal
|
|
300
272
|
*/
|
|
301
|
-
declare
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
273
|
+
declare class LogWrapper {
|
|
274
|
+
private readonly logger;
|
|
275
|
+
private readonly method;
|
|
276
|
+
private readonly args;
|
|
277
|
+
constructor(logger: Logger, method: string, args: string | number | Record<string, unknown> | undefined);
|
|
278
|
+
invoked(message?: string): void;
|
|
279
|
+
success(message?: string, additionalFields?: Record<string, unknown>): void;
|
|
280
|
+
error(error: unknown, message?: string): void;
|
|
281
|
+
}
|
|
305
282
|
/**
|
|
306
|
-
*
|
|
283
|
+
* Interface for classes that expose a NestJS Logger instance.
|
|
307
284
|
*
|
|
308
|
-
*
|
|
309
|
-
*
|
|
285
|
+
* Implementing this interface is optional when using the `@Log()` decorator.
|
|
286
|
+
* If a class does not define a `logger` property, the decorator will
|
|
287
|
+
* automatically inject a `new Logger(ClassName)` instance at runtime.
|
|
310
288
|
*
|
|
311
|
-
*
|
|
312
|
-
*
|
|
313
|
-
*
|
|
314
|
-
* @example
|
|
315
|
-
* function example(id: number, name: string = 'default') {}
|
|
316
|
-
* getParameterNames(example) // Returns: ['id', 'name']
|
|
317
|
-
*
|
|
318
|
-
* @internal
|
|
289
|
+
* You may still implement this interface explicitly to provide a custom logger
|
|
290
|
+
* (e.g., a mock for testing, or a logger with a non-default context).
|
|
319
291
|
*/
|
|
320
|
-
|
|
292
|
+
interface Loggable {
|
|
293
|
+
logger: Logger;
|
|
294
|
+
}
|
|
295
|
+
declare const isLoggable: (instance: unknown) => instance is Loggable;
|
|
321
296
|
/**
|
|
322
|
-
*
|
|
297
|
+
* Creates a LogWrapper instance for structured method logging.
|
|
298
|
+
*
|
|
299
|
+
* When the target instance already has a `logger` property (i.e., satisfies
|
|
300
|
+
* the {@link Loggable} interface), that logger is used directly. Otherwise,
|
|
301
|
+
* a new `Logger` from `@nestjs/common` is created with `className` as its
|
|
302
|
+
* context and assigned to `instance.logger`, so subsequent calls reuse it.
|
|
303
|
+
*
|
|
304
|
+
* @param instance - The class instance whose method is being logged
|
|
305
|
+
* @param className - The name of the class (used as Logger context if auto-injected)
|
|
306
|
+
* @param methodName - The name of the method being logged
|
|
307
|
+
* @param argsObject - Formatted arguments to include in the log entry
|
|
308
|
+
* @returns A configured {@link LogWrapper} ready for invoked/success/error calls
|
|
309
|
+
*
|
|
323
310
|
* @internal
|
|
324
311
|
*/
|
|
325
|
-
declare const
|
|
312
|
+
declare const createLogWrapper: (instance: unknown, className: string, methodName: string, argsObject: string | number | Record<string, unknown> | undefined) => LogWrapper;
|
|
326
313
|
//#endregion
|
|
327
|
-
//#region src/
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
314
|
+
//#region src/axios/axios.logger.d.ts
|
|
315
|
+
declare function prettifyAxiosError(error: unknown): unknown;
|
|
316
|
+
//#endregion
|
|
317
|
+
//#region src/axios/axios.stub.d.ts
|
|
331
318
|
/**
|
|
332
|
-
*
|
|
333
|
-
*
|
|
334
|
-
|
|
335
|
-
|
|
319
|
+
* Stub for axios types and utils, to avoid ading axios as a dependency
|
|
320
|
+
*
|
|
321
|
+
* Please avoid adding business logic to this file.
|
|
322
|
+
* */
|
|
323
|
+
interface AxiosError extends Error {
|
|
324
|
+
name: string;
|
|
325
|
+
message: string;
|
|
326
|
+
stack?: string;
|
|
327
|
+
isAxiosError: true;
|
|
328
|
+
config: AxiosRequestConfig;
|
|
329
|
+
response: AxiosResponse;
|
|
330
|
+
code?: string;
|
|
331
|
+
request?: any;
|
|
332
|
+
status?: number;
|
|
333
|
+
}
|
|
334
|
+
interface AxiosRequestConfig {
|
|
335
|
+
url?: string;
|
|
336
|
+
method?: string;
|
|
337
|
+
baseURL?: string;
|
|
338
|
+
path?: string;
|
|
339
|
+
headers?: unknown;
|
|
340
|
+
data?: unknown;
|
|
341
|
+
params?: unknown;
|
|
342
|
+
}
|
|
343
|
+
interface AxiosResponse {
|
|
344
|
+
status: number;
|
|
345
|
+
statusText: string;
|
|
346
|
+
data: unknown;
|
|
347
|
+
headers: unknown;
|
|
348
|
+
}
|
|
349
|
+
//#endregion
|
|
350
|
+
//#region src/axios/isTimoutError.d.ts
|
|
351
|
+
declare function isTimeoutError(error: AxiosError): boolean;
|
|
336
352
|
//#endregion
|
|
337
|
-
export { Log, LogArgsFormatter, LogOptions, LogWrapper, Loggable, NO_LOG_METADATA_KEY, NoLog,
|
|
353
|
+
export { Log, LogArgsFormatter, LogOptions, LogResultFormatter, LogWrapper, Loggable, NO_LOG_METADATA_KEY, NoLog, createLogWrapper, isLoggable, isTimeoutError, prettifyAxiosError };
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nestjs-log-decorator",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"description": "Decorator that removes try catch boilerplate logging from NestJS service methods",
|
|
5
|
-
"author": "Vlad Goncharov <
|
|
5
|
+
"author": "Vlad Goncharov <vlad.goncharov@neolab.com>",
|
|
6
6
|
"license": "AGPL-3.0",
|
|
7
7
|
"homepage": "https://github.com/NeoLabHQ/nestjs-log-decorator#readme",
|
|
8
8
|
"repository": {
|
|
@@ -24,13 +24,18 @@
|
|
|
24
24
|
"scripts": {
|
|
25
25
|
"build": "tsdown",
|
|
26
26
|
"build:watch": "tsdown --watch",
|
|
27
|
-
"dev": "concurrently -c auto --names build,test npm:build:watch npm:test",
|
|
28
|
-
"
|
|
27
|
+
"dev": "concurrently -c auto --names build,test npm:build:watch npm:test:watch",
|
|
28
|
+
"lint": "npm run typecheck",
|
|
29
|
+
"test": "vitest --run",
|
|
30
|
+
"test:watch": "vitest",
|
|
29
31
|
"typecheck": "tsc --noEmit",
|
|
30
32
|
"prepublishOnly": "npm run build",
|
|
31
33
|
"commit": "cz help",
|
|
32
34
|
"cz": "git add . && cz"
|
|
33
35
|
},
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"base-decorators": "^0.1.1"
|
|
38
|
+
},
|
|
34
39
|
"devDependencies": {
|
|
35
40
|
"@semantic-release/git": "^10.0.1",
|
|
36
41
|
"@types/node": "^25.0.3",
|
|
@@ -49,5 +54,14 @@
|
|
|
49
54
|
"commitizen": {
|
|
50
55
|
"path": "./node_modules/cz-conventional-changelog"
|
|
51
56
|
}
|
|
52
|
-
}
|
|
57
|
+
},
|
|
58
|
+
"keywords": [
|
|
59
|
+
"decorator",
|
|
60
|
+
"decorators",
|
|
61
|
+
"library",
|
|
62
|
+
"nestjs",
|
|
63
|
+
"typescript",
|
|
64
|
+
"utility",
|
|
65
|
+
"logger"
|
|
66
|
+
]
|
|
53
67
|
}
|