@globalart/nestjs-logger 1.0.2 → 1.0.4
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 +184 -83
- package/dist/contracts/index.d.ts +6 -6
- package/dist/core/http-logger.interceptor.d.ts +1 -0
- package/dist/core/http-logger.interceptor.js +34 -11
- package/dist/core/logger.service.d.ts +6 -6
- package/dist/core/logger.service.js +10 -10
- package/dist/types/index.d.ts +6 -0
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -1,26 +1,27 @@
|
|
|
1
1
|
# @globalart/nestjs-logger
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A professional logging module for NestJS with clean architecture, strict typing, and extensibility.
|
|
4
4
|
|
|
5
|
-
## 🚀
|
|
5
|
+
## 🚀 Features
|
|
6
6
|
|
|
7
|
-
- **Clean Architecture** -
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
- **HTTP
|
|
14
|
-
-
|
|
15
|
-
-
|
|
7
|
+
- **Clean Architecture** - separation of concerns, SOLID principles
|
|
8
|
+
- **Strict Typing** - full TypeScript type safety
|
|
9
|
+
- **Performance** - optimized architecture with minimal allocations
|
|
10
|
+
- **Extensibility** - easy to add new formatters and transports
|
|
11
|
+
- **Testability** - dependency injection, easy mocking
|
|
12
|
+
- **Automatic Context** - class detection from call stack
|
|
13
|
+
- **HTTP Logging** - detailed request logging with format consistency
|
|
14
|
+
- **Security** - automatic sanitization of sensitive data
|
|
15
|
+
- **Colored Output** - beautiful console logs
|
|
16
|
+
- **Multiple Formats** - Text, JSON, and Pino support
|
|
16
17
|
|
|
17
|
-
## 📦
|
|
18
|
+
## 📦 Installation
|
|
18
19
|
|
|
19
20
|
```bash
|
|
20
21
|
npm install @globalart/nestjs-logger
|
|
21
22
|
```
|
|
22
23
|
|
|
23
|
-
## 🎯
|
|
24
|
+
## 🎯 Quick Start
|
|
24
25
|
|
|
25
26
|
```typescript
|
|
26
27
|
import { Module } from '@nestjs/common';
|
|
@@ -39,9 +40,9 @@ import { LoggerModule } from '@globalart/nestjs-logger';
|
|
|
39
40
|
export class AppModule {}
|
|
40
41
|
```
|
|
41
42
|
|
|
42
|
-
## 🔧
|
|
43
|
+
## 🔧 Configuration
|
|
43
44
|
|
|
44
|
-
###
|
|
45
|
+
### Synchronous Configuration
|
|
45
46
|
|
|
46
47
|
```typescript
|
|
47
48
|
LoggerModule.forRoot({
|
|
@@ -50,10 +51,11 @@ LoggerModule.forRoot({
|
|
|
50
51
|
colors: true,
|
|
51
52
|
format: 'pino',
|
|
52
53
|
sensitiveFields: ['password', 'secret'],
|
|
54
|
+
exclude: ['/health', '/metrics'],
|
|
53
55
|
})
|
|
54
56
|
```
|
|
55
57
|
|
|
56
|
-
###
|
|
58
|
+
### Asynchronous Configuration
|
|
57
59
|
|
|
58
60
|
```typescript
|
|
59
61
|
LoggerModule.forRootAsync({
|
|
@@ -61,14 +63,15 @@ LoggerModule.forRootAsync({
|
|
|
61
63
|
level: configService.get('LOG_LEVEL', 'info'),
|
|
62
64
|
format: configService.get('LOG_FORMAT', 'text'),
|
|
63
65
|
colors: !configService.get('PRODUCTION'),
|
|
66
|
+
sensitiveFields: configService.get('SENSITIVE_FIELDS', []),
|
|
64
67
|
}),
|
|
65
68
|
inject: [ConfigService],
|
|
66
69
|
})
|
|
67
70
|
```
|
|
68
71
|
|
|
69
|
-
## 📝
|
|
72
|
+
## 📝 Usage
|
|
70
73
|
|
|
71
|
-
###
|
|
74
|
+
### In Services
|
|
72
75
|
|
|
73
76
|
```typescript
|
|
74
77
|
import { Injectable } from '@nestjs/common';
|
|
@@ -79,15 +82,23 @@ export class UserService {
|
|
|
79
82
|
constructor(private readonly logger: LoggerService) {}
|
|
80
83
|
|
|
81
84
|
async createUser(userData: CreateUserDto) {
|
|
82
|
-
this.logger.log(
|
|
85
|
+
this.logger.log({
|
|
86
|
+
message: 'Creating new user',
|
|
87
|
+
metadata: { userId: userData.email }
|
|
88
|
+
});
|
|
83
89
|
|
|
84
90
|
try {
|
|
85
91
|
const user = await this.userRepository.save(userData);
|
|
86
|
-
this.logger.log(
|
|
92
|
+
this.logger.log({
|
|
93
|
+
message: 'User created successfully',
|
|
94
|
+
metadata: { id: user.id }
|
|
95
|
+
});
|
|
87
96
|
return user;
|
|
88
97
|
} catch (error) {
|
|
89
|
-
this.logger.error(
|
|
90
|
-
|
|
98
|
+
this.logger.error({
|
|
99
|
+
message: 'Failed to create user',
|
|
100
|
+
trace: error.stack,
|
|
101
|
+
metadata: { email: userData.email }
|
|
91
102
|
});
|
|
92
103
|
throw error;
|
|
93
104
|
}
|
|
@@ -95,7 +106,7 @@ export class UserService {
|
|
|
95
106
|
}
|
|
96
107
|
```
|
|
97
108
|
|
|
98
|
-
### HTTP
|
|
109
|
+
### HTTP Logging
|
|
99
110
|
|
|
100
111
|
```typescript
|
|
101
112
|
import { Controller, UseInterceptors } from '@nestjs/common';
|
|
@@ -105,11 +116,11 @@ import { HttpLoggerInterceptor, LogContext } from '@globalart/nestjs-logger';
|
|
|
105
116
|
@UseInterceptors(HttpLoggerInterceptor)
|
|
106
117
|
@LogContext('UserController')
|
|
107
118
|
export class UserController {
|
|
108
|
-
//
|
|
119
|
+
// All HTTP requests will be automatically logged
|
|
109
120
|
}
|
|
110
121
|
```
|
|
111
122
|
|
|
112
|
-
###
|
|
123
|
+
### Global HTTP Logging
|
|
113
124
|
|
|
114
125
|
```typescript
|
|
115
126
|
import { Module } from '@nestjs/common';
|
|
@@ -128,14 +139,15 @@ import { LoggerModule, HttpLoggerInterceptor } from '@globalart/nestjs-logger';
|
|
|
128
139
|
export class AppModule {}
|
|
129
140
|
```
|
|
130
141
|
|
|
131
|
-
## 🎨
|
|
142
|
+
## 🎨 Output Formats
|
|
132
143
|
|
|
133
|
-
### Text (
|
|
144
|
+
### Text Format (Default)
|
|
134
145
|
```
|
|
135
146
|
[2024-01-15T10:30:45.123Z] [INFO] [UserService] Creating new user {"userId":"123"}
|
|
147
|
+
[2024-01-15T10:30:45.335Z] [INFO] [HttpLogger] GET /users - 200 (12ms)
|
|
136
148
|
```
|
|
137
149
|
|
|
138
|
-
### JSON
|
|
150
|
+
### JSON Format
|
|
139
151
|
```json
|
|
140
152
|
{
|
|
141
153
|
"timestamp": "2024-01-15T10:30:45.123Z",
|
|
@@ -144,63 +156,114 @@ export class AppModule {}
|
|
|
144
156
|
"context": "UserService",
|
|
145
157
|
"metadata": {"userId": "123"}
|
|
146
158
|
}
|
|
159
|
+
{
|
|
160
|
+
"timestamp": "2024-01-15T10:30:45.335Z",
|
|
161
|
+
"level": "info",
|
|
162
|
+
"message": "GET /users - 200 (12ms)",
|
|
163
|
+
"context": "HttpLogger",
|
|
164
|
+
"metadata": {
|
|
165
|
+
"requestId": "req-123",
|
|
166
|
+
"method": "GET",
|
|
167
|
+
"url": "/users",
|
|
168
|
+
"statusCode": 200,
|
|
169
|
+
"responseTime": 12,
|
|
170
|
+
"remoteAddress": "127.0.0.1"
|
|
171
|
+
}
|
|
172
|
+
}
|
|
147
173
|
```
|
|
148
174
|
|
|
149
|
-
### Pino
|
|
175
|
+
### Pino Format
|
|
150
176
|
```json
|
|
151
|
-
{"level":30,"time":1642247445123,"pid":1234,"hostname":"app-server","req":{"id":"req-123","method":"GET","url":"/users","query":{},"params":{},"headers":{},"remoteAddress":"127.0.0.1"},"res":{"statusCode":200,"headers":{}},"responseTime":
|
|
177
|
+
{"level":30,"time":1642247445123,"pid":1234,"hostname":"app-server","req":{"id":"req-123","method":"GET","url":"/users","query":{},"params":{},"headers":{},"remoteAddress":"127.0.0.1"},"res":{"statusCode":200,"headers":{}},"responseTime":12,"msg":"request completed"}
|
|
152
178
|
```
|
|
153
179
|
|
|
154
180
|
## 🎯 API Reference
|
|
155
181
|
|
|
156
182
|
### LoggerService
|
|
157
183
|
|
|
158
|
-
|
|
|
159
|
-
|
|
160
|
-
| `log(
|
|
161
|
-
| `error(
|
|
162
|
-
| `warn(
|
|
163
|
-
| `debug(
|
|
164
|
-
| `verbose(
|
|
165
|
-
| `setContext(context)` |
|
|
184
|
+
| Method | Description |
|
|
185
|
+
|--------|-------------|
|
|
186
|
+
| `log(options: LogOptions)` | Information message |
|
|
187
|
+
| `error(options: LogOptions)` | Error with trace |
|
|
188
|
+
| `warn(options: LogOptions)` | Warning message |
|
|
189
|
+
| `debug(options: LogOptions)` | Debug information |
|
|
190
|
+
| `verbose(options: LogOptions)` | Verbose logging |
|
|
191
|
+
| `setContext(context: string)` | Set context |
|
|
192
|
+
| `logHttpRequest(entry: HttpRequestLogEntry)` | Log HTTP request (Pino format only) |
|
|
193
|
+
|
|
194
|
+
### LogOptions Interface
|
|
195
|
+
|
|
196
|
+
```typescript
|
|
197
|
+
interface LogOptions {
|
|
198
|
+
message: string;
|
|
199
|
+
context?: string;
|
|
200
|
+
metadata?: Record<string, unknown>;
|
|
201
|
+
trace?: string;
|
|
202
|
+
}
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### Decorators
|
|
206
|
+
|
|
207
|
+
- `@LogContext(context: string)` - Set context for class/method
|
|
208
|
+
- `@LogMetadata(metadata: Record<string, unknown>)` - Add metadata to logs
|
|
209
|
+
- `@ExcludeLogging()` - Exclude logging for controller/method
|
|
210
|
+
|
|
211
|
+
### Configuration Options
|
|
212
|
+
|
|
213
|
+
| Option | Type | Default | Description |
|
|
214
|
+
|--------|------|---------|-------------|
|
|
215
|
+
| `level` | `LogLevel` | `'info'` | Logging level |
|
|
216
|
+
| `timestamp` | `boolean` | `true` | Show timestamp |
|
|
217
|
+
| `colors` | `boolean` | `true` | Colored output |
|
|
218
|
+
| `format` | `LogFormat` | `'text'` | Output format |
|
|
219
|
+
| `context` | `string` | `undefined` | Default context |
|
|
220
|
+
| `sensitiveFields` | `string[]` | `[...]` | Fields to sanitize |
|
|
221
|
+
| `exclude` | `string[]` | `[]` | URLs to exclude from HTTP logging |
|
|
222
|
+
|
|
223
|
+
## 🏗️ Architecture
|
|
166
224
|
|
|
167
|
-
|
|
225
|
+
The package is built on Clean Architecture principles:
|
|
168
226
|
|
|
169
|
-
|
|
170
|
-
- `@LogMetadata(metadata)` - Добавление метаданных
|
|
227
|
+
### Core Components
|
|
171
228
|
|
|
172
|
-
|
|
229
|
+
- **LoggerModule** - Main module with configuration
|
|
230
|
+
- **LoggerService** - Primary logging service
|
|
231
|
+
- **HttpLoggerInterceptor** - HTTP request logging interceptor
|
|
173
232
|
|
|
174
|
-
|
|
175
|
-
|-------|-----|--------------|----------|
|
|
176
|
-
| `level` | `LogLevel` | `'info'` | Уровень логирования |
|
|
177
|
-
| `timestamp` | `boolean` | `true` | Показывать время |
|
|
178
|
-
| `colors` | `boolean` | `true` | Цветной вывод |
|
|
179
|
-
| `format` | `LogFormat` | `'text'` | Формат вывода |
|
|
180
|
-
| `context` | `string` | `undefined` | Контекст по умолчанию |
|
|
181
|
-
| `sensitiveFields` | `string[]` | `[...]` | Поля для санитизации |
|
|
233
|
+
### Formatters
|
|
182
234
|
|
|
183
|
-
|
|
235
|
+
- **TextFormatter** - Human-readable text output
|
|
236
|
+
- **JsonFormatter** - Structured JSON output
|
|
237
|
+
- **PinoFormatter** - Pino-compatible JSON output
|
|
184
238
|
|
|
185
|
-
|
|
239
|
+
### Utilities
|
|
186
240
|
|
|
187
|
-
- **
|
|
188
|
-
- **
|
|
189
|
-
- **
|
|
190
|
-
- **Utils** - вспомогательные утилиты
|
|
191
|
-
- **Formatters** - форматирование логов
|
|
192
|
-
- **Writers** - вывод логов
|
|
241
|
+
- **ContextResolver** - Automatic context detection
|
|
242
|
+
- **DataSanitizer** - Sensitive data sanitization
|
|
243
|
+
- **RequestIdGenerator** - Unique request ID generation
|
|
193
244
|
|
|
194
|
-
|
|
245
|
+
### Writers
|
|
195
246
|
|
|
196
|
-
|
|
247
|
+
- **ConsoleWriter** - Console output (extensible for other transports)
|
|
248
|
+
|
|
249
|
+
### Contracts & Types
|
|
250
|
+
|
|
251
|
+
- **ILogger** - Logger interface
|
|
252
|
+
- **ILogFormatter** - Formatter interface
|
|
253
|
+
- **ILogWriter** - Writer interface
|
|
254
|
+
- **LogEntry** - Standard log entry structure
|
|
255
|
+
- **HttpRequestLogEntry** - HTTP-specific log entry structure
|
|
256
|
+
|
|
257
|
+
## 🔒 Security
|
|
258
|
+
|
|
259
|
+
Automatic sanitization of sensitive fields:
|
|
197
260
|
- `password`, `pass`
|
|
198
261
|
- `token`, `accessToken`, `refreshToken`
|
|
199
262
|
- `secret`, `key`, `apiKey`
|
|
200
263
|
- `authorization`, `auth`
|
|
201
264
|
- `credential`, `credentials`
|
|
202
265
|
|
|
203
|
-
## 🧪
|
|
266
|
+
## 🧪 Testing
|
|
204
267
|
|
|
205
268
|
```typescript
|
|
206
269
|
import { LoggerService } from '@globalart/nestjs-logger';
|
|
@@ -213,7 +276,11 @@ describe('UserService', () => {
|
|
|
213
276
|
logger = {
|
|
214
277
|
log: jest.fn(),
|
|
215
278
|
error: jest.fn(),
|
|
216
|
-
|
|
279
|
+
warn: jest.fn(),
|
|
280
|
+
debug: jest.fn(),
|
|
281
|
+
verbose: jest.fn(),
|
|
282
|
+
setContext: jest.fn(),
|
|
283
|
+
logHttpRequest: jest.fn(),
|
|
217
284
|
} as any;
|
|
218
285
|
|
|
219
286
|
service = new UserService(logger);
|
|
@@ -221,43 +288,77 @@ describe('UserService', () => {
|
|
|
221
288
|
|
|
222
289
|
it('should log user creation', () => {
|
|
223
290
|
service.createUser(userData);
|
|
224
|
-
expect(logger.log).toHaveBeenCalledWith(
|
|
225
|
-
'Creating new user',
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
);
|
|
291
|
+
expect(logger.log).toHaveBeenCalledWith({
|
|
292
|
+
message: 'Creating new user',
|
|
293
|
+
metadata: { userId: userData.email }
|
|
294
|
+
});
|
|
229
295
|
});
|
|
230
296
|
});
|
|
231
297
|
```
|
|
232
298
|
|
|
233
|
-
## 🔄
|
|
299
|
+
## 🔄 Migration from v1
|
|
234
300
|
|
|
235
301
|
```typescript
|
|
236
|
-
// v1 (
|
|
302
|
+
// v1 (old API)
|
|
237
303
|
import { LoggerModule, LoggerInterceptor } from '@globalart/nestjs-logger';
|
|
238
304
|
|
|
239
|
-
// v2 (
|
|
305
|
+
// v2 (new API)
|
|
240
306
|
import { LoggerModule, HttpLoggerInterceptor } from '@globalart/nestjs-logger';
|
|
241
307
|
|
|
242
|
-
//
|
|
308
|
+
// Legacy exports available for compatibility:
|
|
243
309
|
import { LegacyLoggerModule, LoggerInterceptor } from '@globalart/nestjs-logger';
|
|
244
310
|
```
|
|
245
311
|
|
|
246
|
-
## 📈
|
|
312
|
+
## 📈 Performance
|
|
313
|
+
|
|
314
|
+
- Minimal allocations in hot paths
|
|
315
|
+
- Lazy formatter initialization
|
|
316
|
+
- Optimized context resolution
|
|
317
|
+
- Efficient data sanitization
|
|
318
|
+
- Format-specific HTTP logging optimization
|
|
319
|
+
|
|
320
|
+
## 🎨 Customization
|
|
321
|
+
|
|
322
|
+
### Custom Formatter
|
|
323
|
+
|
|
324
|
+
```typescript
|
|
325
|
+
import { Injectable } from '@nestjs/common';
|
|
326
|
+
import { BaseFormatter } from '@globalart/nestjs-logger';
|
|
327
|
+
|
|
328
|
+
@Injectable()
|
|
329
|
+
export class CustomFormatter extends BaseFormatter {
|
|
330
|
+
format(entry: LogEntry): string {
|
|
331
|
+
return `[${entry.level.toUpperCase()}] ${entry.message}`;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
formatHttpRequest(entry: HttpRequestLogEntry): string {
|
|
335
|
+
return JSON.stringify(entry);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
### Custom Writer
|
|
341
|
+
|
|
342
|
+
```typescript
|
|
343
|
+
import { Injectable } from '@nestjs/common';
|
|
344
|
+
import { ILogWriter } from '@globalart/nestjs-logger';
|
|
247
345
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
346
|
+
@Injectable()
|
|
347
|
+
export class FileWriter implements ILogWriter {
|
|
348
|
+
write(formattedLog: string): void {
|
|
349
|
+
// Write to file
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
```
|
|
252
353
|
|
|
253
|
-
## 🤝
|
|
354
|
+
## 🤝 Contributing
|
|
254
355
|
|
|
255
|
-
1. Fork
|
|
256
|
-
2.
|
|
257
|
-
3.
|
|
258
|
-
4.
|
|
259
|
-
5.
|
|
356
|
+
1. Fork the repository
|
|
357
|
+
2. Create a feature branch
|
|
358
|
+
3. Make your changes
|
|
359
|
+
4. Add tests
|
|
360
|
+
5. Create a Pull Request
|
|
260
361
|
|
|
261
|
-
## 📄
|
|
362
|
+
## 📄 License
|
|
262
363
|
|
|
263
364
|
MIT License
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { LogEntry, HttpRequestLogEntry } from "../types";
|
|
1
|
+
import { LogEntry, HttpRequestLogEntry, LogOptions } from "../types";
|
|
2
2
|
export interface ILogger {
|
|
3
|
-
log(
|
|
4
|
-
error(
|
|
5
|
-
warn(
|
|
6
|
-
debug(
|
|
7
|
-
verbose(
|
|
3
|
+
log(options: LogOptions): void;
|
|
4
|
+
error(options: LogOptions): void;
|
|
5
|
+
warn(options: LogOptions): void;
|
|
6
|
+
debug(options: LogOptions): void;
|
|
7
|
+
verbose(options: LogOptions): void;
|
|
8
8
|
setContext(context: string): void;
|
|
9
9
|
logHttpRequest(entry: HttpRequestLogEntry): void;
|
|
10
10
|
}
|
|
@@ -14,6 +14,7 @@ export declare class HttpLoggerInterceptor implements NestInterceptor {
|
|
|
14
14
|
private readonly pid;
|
|
15
15
|
constructor(logger: LoggerService, dataSanitizer: IDataSanitizer, requestIdGenerator: IRequestIdGenerator, config: LoggerConfiguration, reflector: Reflector);
|
|
16
16
|
intercept(context: ExecutionContext, next: CallHandler): Observable<unknown>;
|
|
17
|
+
private createHttpLogEntry;
|
|
17
18
|
private createLogEntry;
|
|
18
19
|
private getClientIp;
|
|
19
20
|
private sanitizeHeaders;
|
|
@@ -32,11 +32,9 @@ let HttpLoggerInterceptor = class HttpLoggerInterceptor {
|
|
|
32
32
|
intercept(context, next) {
|
|
33
33
|
const request = context.switchToHttp().getRequest();
|
|
34
34
|
const response = context.switchToHttp().getResponse();
|
|
35
|
-
// Проверяем, нужно ли исключить этот URL из логирования
|
|
36
35
|
if (this.shouldExcludeUrl(request.url)) {
|
|
37
36
|
return next.handle();
|
|
38
37
|
}
|
|
39
|
-
// Проверяем, есть ли декоратор ExcludeLogging на контроллере или методе
|
|
40
38
|
const isExcluded = this.reflector.getAllAndOverride(constants_1.LOGGER_EXCLUDE_METADATA, [context.getHandler(), context.getClass()]);
|
|
41
39
|
if (isExcluded) {
|
|
42
40
|
return next.handle();
|
|
@@ -44,17 +42,27 @@ let HttpLoggerInterceptor = class HttpLoggerInterceptor {
|
|
|
44
42
|
const requestId = this.requestIdGenerator.generate();
|
|
45
43
|
const startTime = Date.now();
|
|
46
44
|
return next.handle().pipe((0, operators_1.tap)(() => {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
45
|
+
if (this.config.format === "pino") {
|
|
46
|
+
const entry = this.createHttpLogEntry(request, response, requestId, startTime, 30, "request completed");
|
|
47
|
+
this.logger.logHttpRequest(entry);
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
const entry = this.createLogEntry(request, response, requestId, startTime);
|
|
51
|
+
this.logger.log(entry);
|
|
52
|
+
}
|
|
50
53
|
}), (0, operators_1.catchError)((error) => {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
+
if (this.config.format === "pino") {
|
|
55
|
+
const entry = this.createHttpLogEntry(request, response, requestId, startTime, 50, "request failed");
|
|
56
|
+
this.logger.logHttpRequest(entry);
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
const entry = this.createLogEntry(request, response, requestId, startTime);
|
|
60
|
+
this.logger.error(entry);
|
|
61
|
+
}
|
|
54
62
|
throw error;
|
|
55
63
|
}));
|
|
56
64
|
}
|
|
57
|
-
|
|
65
|
+
createHttpLogEntry(request, response, requestId, startTime, level, message) {
|
|
58
66
|
const responseTime = Date.now() - startTime;
|
|
59
67
|
const ip = this.getClientIp(request);
|
|
60
68
|
const httpRequest = {
|
|
@@ -83,6 +91,23 @@ let HttpLoggerInterceptor = class HttpLoggerInterceptor {
|
|
|
83
91
|
msg: message,
|
|
84
92
|
};
|
|
85
93
|
}
|
|
94
|
+
createLogEntry(request, response, requestId, startTime) {
|
|
95
|
+
const responseTime = Date.now() - startTime;
|
|
96
|
+
const ip = this.getClientIp(request);
|
|
97
|
+
return {
|
|
98
|
+
message: `${request.method} ${request.url} - ${response.statusCode || 500} (${responseTime}ms)`,
|
|
99
|
+
context: "HttpLogger",
|
|
100
|
+
metadata: {
|
|
101
|
+
requestId,
|
|
102
|
+
method: request.method,
|
|
103
|
+
url: request.url,
|
|
104
|
+
statusCode: response.statusCode || 500,
|
|
105
|
+
responseTime,
|
|
106
|
+
remoteAddress: ip,
|
|
107
|
+
userAgent: request.headers["user-agent"],
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
}
|
|
86
111
|
getClientIp(request) {
|
|
87
112
|
return (request.headers["x-forwarded-for"] ||
|
|
88
113
|
request.headers["x-real-ip"] ||
|
|
@@ -107,13 +132,11 @@ let HttpLoggerInterceptor = class HttpLoggerInterceptor {
|
|
|
107
132
|
}
|
|
108
133
|
shouldExcludeUrl(url) {
|
|
109
134
|
return this.config.exclude.some((excludeUrl) => {
|
|
110
|
-
// Поддержка простых паттернов с * (wildcard)
|
|
111
135
|
if (excludeUrl.includes("*")) {
|
|
112
136
|
const pattern = excludeUrl.replace(/\*/g, ".*");
|
|
113
137
|
const regex = new RegExp(`^${pattern}$`);
|
|
114
138
|
return regex.test(url);
|
|
115
139
|
}
|
|
116
|
-
// Точное совпадение
|
|
117
140
|
return url === excludeUrl;
|
|
118
141
|
});
|
|
119
142
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { LoggerService as NestLoggerService } from "@nestjs/common";
|
|
2
2
|
import { ILogger, ILogFormatter, ILogWriter, IContextResolver } from "../contracts";
|
|
3
|
-
import { HttpRequestLogEntry, LoggerConfiguration } from "../types";
|
|
3
|
+
import { HttpRequestLogEntry, LoggerConfiguration, LogOptions } from "../types";
|
|
4
4
|
export declare class LoggerService implements NestLoggerService, ILogger {
|
|
5
5
|
private readonly config;
|
|
6
6
|
private readonly formatter;
|
|
@@ -9,11 +9,11 @@ export declare class LoggerService implements NestLoggerService, ILogger {
|
|
|
9
9
|
private context?;
|
|
10
10
|
constructor(config: LoggerConfiguration, formatter: ILogFormatter, writer: ILogWriter, contextResolver: IContextResolver);
|
|
11
11
|
setContext(context: string): void;
|
|
12
|
-
log(
|
|
13
|
-
error(
|
|
14
|
-
warn(
|
|
15
|
-
debug(
|
|
16
|
-
verbose(
|
|
12
|
+
log(options: LogOptions): void;
|
|
13
|
+
error(options: LogOptions): void;
|
|
14
|
+
warn(options: LogOptions): void;
|
|
15
|
+
debug(options: LogOptions): void;
|
|
16
|
+
verbose(options: LogOptions): void;
|
|
17
17
|
logHttpRequest(entry: HttpRequestLogEntry): void;
|
|
18
18
|
private writeLog;
|
|
19
19
|
}
|
|
@@ -21,20 +21,20 @@ let LoggerService = class LoggerService {
|
|
|
21
21
|
setContext(context) {
|
|
22
22
|
this.context = context;
|
|
23
23
|
}
|
|
24
|
-
log(
|
|
25
|
-
this.writeLog("info", message, context, metadata);
|
|
24
|
+
log(options) {
|
|
25
|
+
this.writeLog("info", options.message, options.context, options.metadata);
|
|
26
26
|
}
|
|
27
|
-
error(
|
|
28
|
-
this.writeLog("error", message, context, metadata, trace);
|
|
27
|
+
error(options) {
|
|
28
|
+
this.writeLog("error", options.message, options.context, options.metadata, options.trace);
|
|
29
29
|
}
|
|
30
|
-
warn(
|
|
31
|
-
this.writeLog("warn", message, context, metadata);
|
|
30
|
+
warn(options) {
|
|
31
|
+
this.writeLog("warn", options.message, options.context, options.metadata);
|
|
32
32
|
}
|
|
33
|
-
debug(
|
|
34
|
-
this.writeLog("debug", message, context, metadata);
|
|
33
|
+
debug(options) {
|
|
34
|
+
this.writeLog("debug", options.message, options.context, options.metadata);
|
|
35
35
|
}
|
|
36
|
-
verbose(
|
|
37
|
-
this.writeLog("verbose", message, context, metadata);
|
|
36
|
+
verbose(options) {
|
|
37
|
+
this.writeLog("verbose", options.message, options.context, options.metadata);
|
|
38
38
|
}
|
|
39
39
|
logHttpRequest(entry) {
|
|
40
40
|
const formatted = this.formatter.formatHttpRequest(entry);
|
package/dist/types/index.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@globalart/nestjs-logger",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"description": "A advanced logger for NestJS",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "GlobalArt, Inc"
|
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
"test:cov": "jest --coverage --passWithNoTests",
|
|
35
35
|
"coveralls": "yarn run test:cov --coverageReporters=text-lcov | coveralls",
|
|
36
36
|
"build": "rm -rf ./dist && tsc",
|
|
37
|
+
"build:watch": "tsc --watch",
|
|
37
38
|
"prepublishOnly": "npm run build",
|
|
38
39
|
"publish:dev": "npm publish --access public --tag dev",
|
|
39
40
|
"publish:npm": "release-it"
|