npm package: @nest-packages/nestjs-trace-logger
Description: 一个功能强大的 NestJS 日志追踪包，提供完整的 traceId 支持、上下文管理和自定义格式化功能。
Latest version: 0.2.0

# @nest-packages/nestjs-trace-logger

一个功能强大的 NestJS 日志追踪包，提供完整的 traceId 支持、上下文管理和自定义格式化功能。

## 特性

- ✅ **完全继承 NestJS Logger** - 保持所有原生功能，API 完全兼容
- ✅ **自动 traceId 注入** - 使用 AsyncLocalStorage 自动在异步调用链中传递 traceId
- ✅ **支持 LogLevel 配置** - 兼容 `getLogLevels` 函数，支持生产/开发环境不同日志级别
- ✅ **自定义格式化器** - 支持默认、SLS、JSON 等多种格式化方式
- ✅ **中间件和拦截器** - 开箱即用的 TraceMiddleware 和 TraceInterceptor
- ✅ **类型安全** - 完整的 TypeScript 类型定义
- ✅ **零配置** - 默认配置即可使用，也支持深度自定义

## 安装

```bash
npm install @nest-packages/nestjs-trace-logger
# 或
pnpm add @nest-packages/nestjs-trace-logger
# 或
yarn add @nest-packages/nestjs-trace-logger
```

### 依赖要求

- `@nestjs/common`: ^11.0.0
- `@nestjs/core`: ^11.0.0
- `uuid`: ^9.0.0
- `fast-safe-stringify`: ^2.1.0

## 快速开始

### 1. 在 main.ts 中配置

```typescript
import { NestFactory } from '@nestjs/core';
import {
  TraceConsoleLogger,
  TraceMiddleware,
  TraceInterceptor,
} from '@nest-packages/nestjs-trace-logger';
import { AppModule } from './app.module';

function getLogLevels(isProduction: boolean): LogLevel[] {
  if (isProduction) {
    return ['warn', 'error', 'log'];
  }
  return ['error', 'warn', 'log', 'verbose', 'debug'];
}

async function bootstrap() {
  const app = await NestFactory.create(AppModule, {
    logger: new TraceConsoleLogger({
      logLevels: getLogLevels(process.env.NODE_ENV === 'production'),
      compact: true,
      json: false,
      colors: true,
    }),
  });

  // 注册 Trace 中间件（在健康检查之后）
  const traceMiddleware = new TraceMiddleware();
  app.use((req, res, next) => traceMiddleware.use(req, res, next));

  // 注册 Trace 拦截器
  app.useGlobalInterceptors(new TraceInterceptor());

  await app.listen(3000);
}
bootstrap();
```

### 2. 在服务中使用

```typescript
import { Injectable } from '@nestjs/common';
import { TraceLogger } from '@nest-packages/nestjs-trace-logger';

@Injectable()
export class MyService {
  private readonly logger = new TraceLogger(MyService.name);

  async doSomething() {
    // 自动注入 traceId，支持对象上下文
    this.logger.log('操作完成', { userId: 123, action: 'create' });

    // 支持 NestJS Logger 的所有方法
    this.logger.debug('调试信息');
    this.logger.warn('警告信息');
    this.logger.error('错误信息', 'stack trace');
  }
}
```

## API 文档

### TraceContextService

用于管理请求上下文和 traceId 的服务类。

```typescript
import { TraceContextService } from '@nest-packages/nestjs-trace-logger';

// 获取当前 traceId
const traceId = TraceContextService.getTraceId();

// 运行函数并设置 traceId（同步）
TraceContextService.run('trace-id-123', () => {
  // 在这个函数内部，traceId 自动可用
  const id = TraceContextService.getTraceId(); // 'trace-id-123'
});

// 运行函数并设置 traceId（异步）
await TraceContextService.runAsync('trace-id-123', async () => {
  // 异步函数内部，traceId 自动可用
  const id = TraceContextService.getTraceId(); // 'trace-id-123'
});

// 设置自定义上下文数据
TraceContextService.set('userId', 123);
const userId = TraceContextService.get<number>('userId'); // 123

// 获取完整上下文
const context = TraceContextService.getContext();
```

### TraceLogger

完全继承 NestJS Logger 的日志类，自动注入 traceId。

```typescript
import { TraceLogger } from '@nest-packages/nestjs-trace-logger';

// 创建实例
const logger = new TraceLogger('MyService');

// 使用默认格式化器
logger.log('消息', { key: 'value' });
// 输出: [traceId] 消息 | {"traceId":"abc123","key":"value"}

// 使用自定义格式化器
import { JsonFormatter } from '@nest-packages/nestjs-trace-logger';
logger.setFormatter(new JsonFormatter());
logger.log('消息', { key: 'value' });
// 输出: {"message":"消息","timestamp":"2024-01-01T00:00:00.000Z","traceId":"abc123","key":"value"}
```

### TraceConsoleLogger

类似 ConsoleLogger，支持 LogLevel 配置。

```typescript
import { TraceConsoleLogger, LogLevel } from '@nest-packages/nestjs-trace-logger';

const logger = new TraceConsoleLogger({
  logLevels: ['error', 'warn', 'log'] as LogLevel[],
  compact: true,
  json: false,
  colors: true,
  formatter: new SlsFormatter(), // 可选：自定义格式化器
});
```

### TraceMiddleware

自动从请求头获取或生成 traceId 的中间件。

```typescript
import { TraceMiddleware } from '@nest-packages/nestjs-trace-logger';

// 在 main.ts 中注册
const traceMiddleware = new TraceMiddleware();
app.use((req, res, next) => traceMiddleware.use(req, res, next));
```

**功能：**
- 从 `x-request-id` 请求头获取 traceId
- 如果没有，自动生成 UUID 并截取前 8 位
- 在响应头中设置 `X-Request-ID`
- 使用 AsyncLocalStorage 存储上下文

### TraceInterceptor

确保 NestJS 执行上下文中 traceId 可用的拦截器。

```typescript
import { TraceInterceptor } from '@nest-packages/nestjs-trace-logger';

// 在 main.ts 中注册
app.useGlobalInterceptors(new TraceInterceptor());
```

## 格式化器

### DefaultFormatter（默认）

格式：`[traceId] message | {context}`

```typescript
import { DefaultFormatter } from '@nest-packages/nestjs-trace-logger';

const logger = new TraceLogger('MyService', new DefaultFormatter());
logger.log('操作完成', { userId: 123 });
// 输出: [abc123] 操作完成 | {"traceId":"abc123","userId":123}
```

### SlsFormatter（阿里云 SLS）

适配阿里云 SLS 日志格式，traceId 包含在 context 中。

```typescript
import { SlsFormatter } from '@nest-packages/nestjs-trace-logger';

const logger = new TraceLogger('MyService', new SlsFormatter());
logger.log('操作完成', { userId: 123 });
// 输出: 操作完成 | {"traceId":"abc123","userId":123}
```

### JsonFormatter（JSON 格式）

输出完整的 JSON 格式日志。

```typescript
import { JsonFormatter } from '@nest-packages/nestjs-trace-logger';

const logger = new TraceLogger('MyService', new JsonFormatter());
logger.log('操作完成', { userId: 123 });
// 输出: {"message":"操作完成","timestamp":"2024-01-01T00:00:00.000Z","traceId":"abc123","userId":123}
```

### 自定义格式化器

```typescript
import { IFormatter, LogContext } from '@nest-packages/nestjs-trace-logger';

class CustomFormatter implements IFormatter {
  format(message: string, traceId?: string, context?: LogContext): string {
    return `[${traceId || 'N/A'}] ${message} - ${JSON.stringify(context || {})}`;
  }
}

const logger = new TraceLogger('MyService', new CustomFormatter());
```

## 高级用法

### 在队列任务中使用

```typescript
import { TraceContextService } from '@nest-packages/nestjs-trace-logger';

@Processor('my-queue')
export class MyProcessor {
  @Process()
  async handle(job: Job) {
    const traceId = job.data.traceId || 'generated-id';
    
    await TraceContextService.runAsync(traceId, async () => {
      // 在这个异步函数中，traceId 自动可用
      const logger = new TraceLogger(MyProcessor.name);
      logger.log('处理任务', { jobId: job.id });
    });
  }
}
```

### 继承 TraceLogger 创建自定义 Logger

```typescript
import { TraceLogger, LogContext } from '@nest-packages/nestjs-trace-logger';

export class AlarmLogger extends TraceLogger {
  constructor(context: string) {
    super(context);
  }

  log(message: string, context?: LogContext | string): void {
    if (context && typeof context === 'object') {
      super.log(message, context as LogContext);
    } else {
      super.log(message, context);
    }
  }
}
```

### 使用 LoggerManager

```typescript
import { LoggerManager, TraceLogger } from '@nest-packages/nestjs-trace-logger';

// 设置自定义 Logger 工厂
LoggerManager.setLoggerFactory((context: string) => {
  return new TraceLogger(context, new SlsFormatter());
});

// 创建 Logger
const logger = LoggerManager.createLogger('MyService');
```

### 在模块配置中使用

```typescript
import { TraceLogger } from '@nest-packages/nestjs-trace-logger';

@Module({
  imports: [
    SomeModule.forRootAsync({
      useFactory: () => ({
        loggerFactory: (context: string) => new TraceLogger(context),
      }),
    }),
  ],
})
export class AppModule {}
```

## 配置选项

### TraceConsoleLoggerOptions

```typescript
interface TraceConsoleLoggerOptions {
  /**
   * 日志级别数组
   * @example ['error', 'warn', 'log', 'verbose', 'debug']
   */
  logLevels?: LogLevel[];

  /**
   * 是否使用紧凑格式
   * @default false
   */
  compact?: boolean;

  /**
   * 是否输出 JSON 格式
   * @default false
   */
  json?: boolean;

  /**
   * 是否使用颜色
   * @default true
   */
  colors?: boolean;

  /**
   * 自定义格式化器
   */
  formatter?: IFormatter;
}
```

## 最佳实践

### 1. 日志级别配置

根据环境配置不同的日志级别：

```typescript
function getLogLevels(isProduction: boolean): LogLevel[] {
  if (isProduction) {
    return ['warn', 'error', 'log'];
  }
  return ['error', 'warn', 'log', 'verbose', 'debug'];
}
```

### 2. 在异步操作中保持 traceId

使用 `TraceContextService.runAsync` 确保异步操作中 traceId 可用：

```typescript
await TraceContextService.runAsync(traceId, async () => {
  // 所有异步操作都会自动包含 traceId
  await someAsyncOperation();
  await anotherAsyncOperation();
});
```

### 3. 使用对象上下文

传递结构化数据而不是字符串拼接：

```typescript
// ✅ 推荐
logger.log('用户登录', { userId: 123, ip: '192.168.1.1' });

// ❌ 不推荐
logger.log(`用户登录: userId=${userId}, ip=${ip}`);
```

### 4. 错误日志记录

```typescript
try {
  // 业务逻辑
} catch (error) {
  logger.error('操作失败', { 
    error: error.message,
    stack: error.stack,
    userId: 123 
  });
}
```

## 类型定义

```typescript
// TraceContext
interface TraceContext {
  traceId: string;
  startTime: number;
  [key: string]: any;
}

// LogContext
type LogContext = Record<string, unknown>;

// ILogger
interface ILogger {
  log(message: string, ...context: any[]): void;
  debug(message: string, ...context: any[]): void;
  warn(message: string, ...context: any[]): void;
  error(message: string, ...context: any[]): void;
}

// IFormatter
interface IFormatter {
  format(message: string, traceId?: string, context?: LogContext): string;
}
```

## 许可证

MIT

## 贡献

欢迎提交 Issue 和 Pull Request！

## 相关链接

- [NestJS 官方文档](https://docs.nestjs.com/)
- [AsyncLocalStorage 文档](https://nodejs.org/api/async_hooks.html#async_hooks_class_asynclocalstorage)