@nest-packages/nestjs-trace-logger 0.1.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 +447 -0
- package/package.json +24 -0
package/README.md
ADDED
|
@@ -0,0 +1,447 @@
|
|
|
1
|
+
# @nest-packages/nestjs-trace-logger
|
|
2
|
+
|
|
3
|
+
一个功能强大的 NestJS 日志追踪包,提供完整的 traceId 支持、上下文管理和自定义格式化功能。
|
|
4
|
+
|
|
5
|
+
## 特性
|
|
6
|
+
|
|
7
|
+
- ✅ **完全继承 NestJS Logger** - 保持所有原生功能,API 完全兼容
|
|
8
|
+
- ✅ **自动 traceId 注入** - 使用 AsyncLocalStorage 自动在异步调用链中传递 traceId
|
|
9
|
+
- ✅ **支持 LogLevel 配置** - 兼容 `getLogLevels` 函数,支持生产/开发环境不同日志级别
|
|
10
|
+
- ✅ **自定义格式化器** - 支持默认、SLS、JSON 等多种格式化方式
|
|
11
|
+
- ✅ **中间件和拦截器** - 开箱即用的 TraceMiddleware 和 TraceInterceptor
|
|
12
|
+
- ✅ **类型安全** - 完整的 TypeScript 类型定义
|
|
13
|
+
- ✅ **零配置** - 默认配置即可使用,也支持深度自定义
|
|
14
|
+
|
|
15
|
+
## 安装
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install @nest-packages/nestjs-trace-logger
|
|
19
|
+
# 或
|
|
20
|
+
pnpm add @nest-packages/nestjs-trace-logger
|
|
21
|
+
# 或
|
|
22
|
+
yarn add @nest-packages/nestjs-trace-logger
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### 依赖要求
|
|
26
|
+
|
|
27
|
+
- `@nestjs/common`: ^11.0.0
|
|
28
|
+
- `@nestjs/core`: ^11.0.0
|
|
29
|
+
- `uuid`: ^9.0.0
|
|
30
|
+
- `fast-safe-stringify`: ^2.1.0
|
|
31
|
+
|
|
32
|
+
## 快速开始
|
|
33
|
+
|
|
34
|
+
### 1. 在 main.ts 中配置
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
import { NestFactory } from '@nestjs/core';
|
|
38
|
+
import {
|
|
39
|
+
TraceConsoleLogger,
|
|
40
|
+
TraceMiddleware,
|
|
41
|
+
TraceInterceptor,
|
|
42
|
+
} from '@nest-packages/nestjs-trace-logger';
|
|
43
|
+
import { AppModule } from './app.module';
|
|
44
|
+
|
|
45
|
+
function getLogLevels(isProduction: boolean): LogLevel[] {
|
|
46
|
+
if (isProduction) {
|
|
47
|
+
return ['warn', 'error', 'log'];
|
|
48
|
+
}
|
|
49
|
+
return ['error', 'warn', 'log', 'verbose', 'debug'];
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async function bootstrap() {
|
|
53
|
+
const app = await NestFactory.create(AppModule, {
|
|
54
|
+
logger: new TraceConsoleLogger({
|
|
55
|
+
logLevels: getLogLevels(process.env.NODE_ENV === 'production'),
|
|
56
|
+
compact: true,
|
|
57
|
+
json: false,
|
|
58
|
+
colors: true,
|
|
59
|
+
}),
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
// 注册 Trace 中间件(在健康检查之后)
|
|
63
|
+
const traceMiddleware = new TraceMiddleware();
|
|
64
|
+
app.use((req, res, next) => traceMiddleware.use(req, res, next));
|
|
65
|
+
|
|
66
|
+
// 注册 Trace 拦截器
|
|
67
|
+
app.useGlobalInterceptors(new TraceInterceptor());
|
|
68
|
+
|
|
69
|
+
await app.listen(3000);
|
|
70
|
+
}
|
|
71
|
+
bootstrap();
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### 2. 在服务中使用
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
import { Injectable } from '@nestjs/common';
|
|
78
|
+
import { TraceLogger } from '@nest-packages/nestjs-trace-logger';
|
|
79
|
+
|
|
80
|
+
@Injectable()
|
|
81
|
+
export class MyService {
|
|
82
|
+
private readonly logger = new TraceLogger(MyService.name);
|
|
83
|
+
|
|
84
|
+
async doSomething() {
|
|
85
|
+
// 自动注入 traceId,支持对象上下文
|
|
86
|
+
this.logger.log('操作完成', { userId: 123, action: 'create' });
|
|
87
|
+
|
|
88
|
+
// 支持 NestJS Logger 的所有方法
|
|
89
|
+
this.logger.debug('调试信息');
|
|
90
|
+
this.logger.warn('警告信息');
|
|
91
|
+
this.logger.error('错误信息', 'stack trace');
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## API 文档
|
|
97
|
+
|
|
98
|
+
### TraceContextService
|
|
99
|
+
|
|
100
|
+
用于管理请求上下文和 traceId 的服务类。
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
import { TraceContextService } from '@nest-packages/nestjs-trace-logger';
|
|
104
|
+
|
|
105
|
+
// 获取当前 traceId
|
|
106
|
+
const traceId = TraceContextService.getTraceId();
|
|
107
|
+
|
|
108
|
+
// 运行函数并设置 traceId(同步)
|
|
109
|
+
TraceContextService.run('trace-id-123', () => {
|
|
110
|
+
// 在这个函数内部,traceId 自动可用
|
|
111
|
+
const id = TraceContextService.getTraceId(); // 'trace-id-123'
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
// 运行函数并设置 traceId(异步)
|
|
115
|
+
await TraceContextService.runAsync('trace-id-123', async () => {
|
|
116
|
+
// 异步函数内部,traceId 自动可用
|
|
117
|
+
const id = TraceContextService.getTraceId(); // 'trace-id-123'
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
// 设置自定义上下文数据
|
|
121
|
+
TraceContextService.set('userId', 123);
|
|
122
|
+
const userId = TraceContextService.get<number>('userId'); // 123
|
|
123
|
+
|
|
124
|
+
// 获取完整上下文
|
|
125
|
+
const context = TraceContextService.getContext();
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### TraceLogger
|
|
129
|
+
|
|
130
|
+
完全继承 NestJS Logger 的日志类,自动注入 traceId。
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
import { TraceLogger } from '@nest-packages/nestjs-trace-logger';
|
|
134
|
+
|
|
135
|
+
// 创建实例
|
|
136
|
+
const logger = new TraceLogger('MyService');
|
|
137
|
+
|
|
138
|
+
// 使用默认格式化器
|
|
139
|
+
logger.log('消息', { key: 'value' });
|
|
140
|
+
// 输出: [traceId] 消息 | {"traceId":"abc123","key":"value"}
|
|
141
|
+
|
|
142
|
+
// 使用自定义格式化器
|
|
143
|
+
import { JsonFormatter } from '@nest-packages/nestjs-trace-logger';
|
|
144
|
+
logger.setFormatter(new JsonFormatter());
|
|
145
|
+
logger.log('消息', { key: 'value' });
|
|
146
|
+
// 输出: {"message":"消息","timestamp":"2024-01-01T00:00:00.000Z","traceId":"abc123","key":"value"}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### TraceConsoleLogger
|
|
150
|
+
|
|
151
|
+
类似 ConsoleLogger,支持 LogLevel 配置。
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
import { TraceConsoleLogger, LogLevel } from '@nest-packages/nestjs-trace-logger';
|
|
155
|
+
|
|
156
|
+
const logger = new TraceConsoleLogger({
|
|
157
|
+
logLevels: ['error', 'warn', 'log'] as LogLevel[],
|
|
158
|
+
compact: true,
|
|
159
|
+
json: false,
|
|
160
|
+
colors: true,
|
|
161
|
+
formatter: new SlsFormatter(), // 可选:自定义格式化器
|
|
162
|
+
});
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### TraceMiddleware
|
|
166
|
+
|
|
167
|
+
自动从请求头获取或生成 traceId 的中间件。
|
|
168
|
+
|
|
169
|
+
```typescript
|
|
170
|
+
import { TraceMiddleware } from '@nest-packages/nestjs-trace-logger';
|
|
171
|
+
|
|
172
|
+
// 在 main.ts 中注册
|
|
173
|
+
const traceMiddleware = new TraceMiddleware();
|
|
174
|
+
app.use((req, res, next) => traceMiddleware.use(req, res, next));
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
**功能:**
|
|
178
|
+
- 从 `x-request-id` 请求头获取 traceId
|
|
179
|
+
- 如果没有,自动生成 UUID 并截取前 8 位
|
|
180
|
+
- 在响应头中设置 `X-Request-ID`
|
|
181
|
+
- 使用 AsyncLocalStorage 存储上下文
|
|
182
|
+
|
|
183
|
+
### TraceInterceptor
|
|
184
|
+
|
|
185
|
+
确保 NestJS 执行上下文中 traceId 可用的拦截器。
|
|
186
|
+
|
|
187
|
+
```typescript
|
|
188
|
+
import { TraceInterceptor } from '@nest-packages/nestjs-trace-logger';
|
|
189
|
+
|
|
190
|
+
// 在 main.ts 中注册
|
|
191
|
+
app.useGlobalInterceptors(new TraceInterceptor());
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
## 格式化器
|
|
195
|
+
|
|
196
|
+
### DefaultFormatter(默认)
|
|
197
|
+
|
|
198
|
+
格式:`[traceId] message | {context}`
|
|
199
|
+
|
|
200
|
+
```typescript
|
|
201
|
+
import { DefaultFormatter } from '@nest-packages/nestjs-trace-logger';
|
|
202
|
+
|
|
203
|
+
const logger = new TraceLogger('MyService', new DefaultFormatter());
|
|
204
|
+
logger.log('操作完成', { userId: 123 });
|
|
205
|
+
// 输出: [abc123] 操作完成 | {"traceId":"abc123","userId":123}
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### SlsFormatter(阿里云 SLS)
|
|
209
|
+
|
|
210
|
+
适配阿里云 SLS 日志格式,traceId 包含在 context 中。
|
|
211
|
+
|
|
212
|
+
```typescript
|
|
213
|
+
import { SlsFormatter } from '@nest-packages/nestjs-trace-logger';
|
|
214
|
+
|
|
215
|
+
const logger = new TraceLogger('MyService', new SlsFormatter());
|
|
216
|
+
logger.log('操作完成', { userId: 123 });
|
|
217
|
+
// 输出: 操作完成 | {"traceId":"abc123","userId":123}
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### JsonFormatter(JSON 格式)
|
|
221
|
+
|
|
222
|
+
输出完整的 JSON 格式日志。
|
|
223
|
+
|
|
224
|
+
```typescript
|
|
225
|
+
import { JsonFormatter } from '@nest-packages/nestjs-trace-logger';
|
|
226
|
+
|
|
227
|
+
const logger = new TraceLogger('MyService', new JsonFormatter());
|
|
228
|
+
logger.log('操作完成', { userId: 123 });
|
|
229
|
+
// 输出: {"message":"操作完成","timestamp":"2024-01-01T00:00:00.000Z","traceId":"abc123","userId":123}
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
### 自定义格式化器
|
|
233
|
+
|
|
234
|
+
```typescript
|
|
235
|
+
import { IFormatter, LogContext } from '@nest-packages/nestjs-trace-logger';
|
|
236
|
+
|
|
237
|
+
class CustomFormatter implements IFormatter {
|
|
238
|
+
format(message: string, traceId?: string, context?: LogContext): string {
|
|
239
|
+
return `[${traceId || 'N/A'}] ${message} - ${JSON.stringify(context || {})}`;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
const logger = new TraceLogger('MyService', new CustomFormatter());
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
## 高级用法
|
|
247
|
+
|
|
248
|
+
### 在队列任务中使用
|
|
249
|
+
|
|
250
|
+
```typescript
|
|
251
|
+
import { TraceContextService } from '@nest-packages/nestjs-trace-logger';
|
|
252
|
+
|
|
253
|
+
@Processor('my-queue')
|
|
254
|
+
export class MyProcessor {
|
|
255
|
+
@Process()
|
|
256
|
+
async handle(job: Job) {
|
|
257
|
+
const traceId = job.data.traceId || 'generated-id';
|
|
258
|
+
|
|
259
|
+
await TraceContextService.runAsync(traceId, async () => {
|
|
260
|
+
// 在这个异步函数中,traceId 自动可用
|
|
261
|
+
const logger = new TraceLogger(MyProcessor.name);
|
|
262
|
+
logger.log('处理任务', { jobId: job.id });
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
### 继承 TraceLogger 创建自定义 Logger
|
|
269
|
+
|
|
270
|
+
```typescript
|
|
271
|
+
import { TraceLogger, LogContext } from '@nest-packages/nestjs-trace-logger';
|
|
272
|
+
|
|
273
|
+
export class AlarmLogger extends TraceLogger {
|
|
274
|
+
constructor(context: string) {
|
|
275
|
+
super(context);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
log(message: string, context?: LogContext | string): void {
|
|
279
|
+
if (context && typeof context === 'object') {
|
|
280
|
+
super.log(message, context as LogContext);
|
|
281
|
+
} else {
|
|
282
|
+
super.log(message, context);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
### 使用 LoggerManager
|
|
289
|
+
|
|
290
|
+
```typescript
|
|
291
|
+
import { LoggerManager, TraceLogger } from '@nest-packages/nestjs-trace-logger';
|
|
292
|
+
|
|
293
|
+
// 设置自定义 Logger 工厂
|
|
294
|
+
LoggerManager.setLoggerFactory((context: string) => {
|
|
295
|
+
return new TraceLogger(context, new SlsFormatter());
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
// 创建 Logger
|
|
299
|
+
const logger = LoggerManager.createLogger('MyService');
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
### 在模块配置中使用
|
|
303
|
+
|
|
304
|
+
```typescript
|
|
305
|
+
import { TraceLogger } from '@nest-packages/nestjs-trace-logger';
|
|
306
|
+
|
|
307
|
+
@Module({
|
|
308
|
+
imports: [
|
|
309
|
+
SomeModule.forRootAsync({
|
|
310
|
+
useFactory: () => ({
|
|
311
|
+
loggerFactory: (context: string) => new TraceLogger(context),
|
|
312
|
+
}),
|
|
313
|
+
}),
|
|
314
|
+
],
|
|
315
|
+
})
|
|
316
|
+
export class AppModule {}
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
## 配置选项
|
|
320
|
+
|
|
321
|
+
### TraceConsoleLoggerOptions
|
|
322
|
+
|
|
323
|
+
```typescript
|
|
324
|
+
interface TraceConsoleLoggerOptions {
|
|
325
|
+
/**
|
|
326
|
+
* 日志级别数组
|
|
327
|
+
* @example ['error', 'warn', 'log', 'verbose', 'debug']
|
|
328
|
+
*/
|
|
329
|
+
logLevels?: LogLevel[];
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* 是否使用紧凑格式
|
|
333
|
+
* @default false
|
|
334
|
+
*/
|
|
335
|
+
compact?: boolean;
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* 是否输出 JSON 格式
|
|
339
|
+
* @default false
|
|
340
|
+
*/
|
|
341
|
+
json?: boolean;
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
* 是否使用颜色
|
|
345
|
+
* @default true
|
|
346
|
+
*/
|
|
347
|
+
colors?: boolean;
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* 自定义格式化器
|
|
351
|
+
*/
|
|
352
|
+
formatter?: IFormatter;
|
|
353
|
+
}
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
## 最佳实践
|
|
357
|
+
|
|
358
|
+
### 1. 日志级别配置
|
|
359
|
+
|
|
360
|
+
根据环境配置不同的日志级别:
|
|
361
|
+
|
|
362
|
+
```typescript
|
|
363
|
+
function getLogLevels(isProduction: boolean): LogLevel[] {
|
|
364
|
+
if (isProduction) {
|
|
365
|
+
return ['warn', 'error', 'log'];
|
|
366
|
+
}
|
|
367
|
+
return ['error', 'warn', 'log', 'verbose', 'debug'];
|
|
368
|
+
}
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
### 2. 在异步操作中保持 traceId
|
|
372
|
+
|
|
373
|
+
使用 `TraceContextService.runAsync` 确保异步操作中 traceId 可用:
|
|
374
|
+
|
|
375
|
+
```typescript
|
|
376
|
+
await TraceContextService.runAsync(traceId, async () => {
|
|
377
|
+
// 所有异步操作都会自动包含 traceId
|
|
378
|
+
await someAsyncOperation();
|
|
379
|
+
await anotherAsyncOperation();
|
|
380
|
+
});
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
### 3. 使用对象上下文
|
|
384
|
+
|
|
385
|
+
传递结构化数据而不是字符串拼接:
|
|
386
|
+
|
|
387
|
+
```typescript
|
|
388
|
+
// ✅ 推荐
|
|
389
|
+
logger.log('用户登录', { userId: 123, ip: '192.168.1.1' });
|
|
390
|
+
|
|
391
|
+
// ❌ 不推荐
|
|
392
|
+
logger.log(`用户登录: userId=${userId}, ip=${ip}`);
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
### 4. 错误日志记录
|
|
396
|
+
|
|
397
|
+
```typescript
|
|
398
|
+
try {
|
|
399
|
+
// 业务逻辑
|
|
400
|
+
} catch (error) {
|
|
401
|
+
logger.error('操作失败', {
|
|
402
|
+
error: error.message,
|
|
403
|
+
stack: error.stack,
|
|
404
|
+
userId: 123
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
## 类型定义
|
|
410
|
+
|
|
411
|
+
```typescript
|
|
412
|
+
// TraceContext
|
|
413
|
+
interface TraceContext {
|
|
414
|
+
traceId: string;
|
|
415
|
+
startTime: number;
|
|
416
|
+
[key: string]: any;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
// LogContext
|
|
420
|
+
type LogContext = Record<string, unknown>;
|
|
421
|
+
|
|
422
|
+
// ILogger
|
|
423
|
+
interface ILogger {
|
|
424
|
+
log(message: string, ...context: any[]): void;
|
|
425
|
+
debug(message: string, ...context: any[]): void;
|
|
426
|
+
warn(message: string, ...context: any[]): void;
|
|
427
|
+
error(message: string, ...context: any[]): void;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
// IFormatter
|
|
431
|
+
interface IFormatter {
|
|
432
|
+
format(message: string, traceId?: string, context?: LogContext): string;
|
|
433
|
+
}
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
## 许可证
|
|
437
|
+
|
|
438
|
+
MIT
|
|
439
|
+
|
|
440
|
+
## 贡献
|
|
441
|
+
|
|
442
|
+
欢迎提交 Issue 和 Pull Request!
|
|
443
|
+
|
|
444
|
+
## 相关链接
|
|
445
|
+
|
|
446
|
+
- [NestJS 官方文档](https://docs.nestjs.com/)
|
|
447
|
+
- [AsyncLocalStorage 文档](https://nodejs.org/api/async_hooks.html#async_hooks_class_asynclocalstorage)
|
package/package.json
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@nest-packages/nestjs-trace-logger",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"main": "dist/index.js",
|
|
5
|
+
"types": "dist/index.d.ts",
|
|
6
|
+
"files": [
|
|
7
|
+
"dist"
|
|
8
|
+
],
|
|
9
|
+
"peerDependencies": {
|
|
10
|
+
"@nestjs/common": "^11.0.0",
|
|
11
|
+
"@nestjs/core": "^11.0.0"
|
|
12
|
+
},
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"uuid": "^9.0.0",
|
|
15
|
+
"fast-safe-stringify": "^2.1.0"
|
|
16
|
+
},
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "tsc -p tsconfig.build.json"
|
|
19
|
+
},
|
|
20
|
+
"publishConfig": {
|
|
21
|
+
"access": "public"
|
|
22
|
+
},
|
|
23
|
+
"license": "MIT"
|
|
24
|
+
}
|