refactor:完善日志系统代码注释规范
- 添加完整的模块级、类级、方法级注释 - 优化类型定义和接口注释说明 - 增加详细的业务逻辑说明和使用示例 - 符合后端开发规范指南要求
This commit is contained in:
81
src/core/utils/logger/logger.module.ts
Normal file
81
src/core/utils/logger/logger.module.ts
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
/**
|
||||||
|
* 日志模块
|
||||||
|
*
|
||||||
|
* 功能描述:
|
||||||
|
* - 配置和提供全局日志服务
|
||||||
|
* - 集成 Pino 高性能日志库
|
||||||
|
* - 支持不同环境的日志配置
|
||||||
|
* - 提供统一的日志记录接口
|
||||||
|
*
|
||||||
|
* 依赖模块:
|
||||||
|
* - ConfigModule: 环境配置模块
|
||||||
|
* - PinoLoggerModule: Pino 日志模块
|
||||||
|
* - AppLoggerService: 应用日志服务
|
||||||
|
*
|
||||||
|
* @author 开发团队
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 2024-12-13
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Module } from '@nestjs/common';
|
||||||
|
import { ConfigModule } from '@nestjs/config';
|
||||||
|
import { LoggerModule as PinoLoggerModule } from 'nestjs-pino';
|
||||||
|
import { AppLoggerService } from './logger.service';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 日志模块类
|
||||||
|
*
|
||||||
|
* 职责:
|
||||||
|
* - 配置 Pino 日志库的各种选项
|
||||||
|
* - 根据环境变量调整日志输出格式和级别
|
||||||
|
* - 提供全局可用的日志服务
|
||||||
|
* - 管理日志相关的依赖注入
|
||||||
|
*
|
||||||
|
* 配置说明:
|
||||||
|
* - 开发环境:使用 pino-pretty 美化输出,日志级别为 debug
|
||||||
|
* - 生产环境:使用 JSON 格式输出,日志级别为 info
|
||||||
|
* - 自动过滤请求和响应中的敏感信息
|
||||||
|
*
|
||||||
|
* 使用场景:
|
||||||
|
* - 在 AppModule 中导入,提供全局日志服务
|
||||||
|
* - 在其他模块中注入 AppLoggerService 使用
|
||||||
|
*/
|
||||||
|
@Module({
|
||||||
|
imports: [
|
||||||
|
ConfigModule,
|
||||||
|
PinoLoggerModule.forRootAsync({
|
||||||
|
imports: [ConfigModule],
|
||||||
|
useFactory: () => ({
|
||||||
|
pinoHttp: {
|
||||||
|
// 根据环境设置日志级别
|
||||||
|
level: process.env.NODE_ENV === 'production' ? 'info' : 'debug',
|
||||||
|
|
||||||
|
// 开发环境使用美化输出
|
||||||
|
transport: process.env.NODE_ENV !== 'production' ? {
|
||||||
|
target: 'pino-pretty',
|
||||||
|
options: {
|
||||||
|
colorize: true,
|
||||||
|
translateTime: 'SYS:standard',
|
||||||
|
ignore: 'pid,hostname',
|
||||||
|
},
|
||||||
|
} : undefined,
|
||||||
|
|
||||||
|
// 自定义序列化器,过滤敏感信息
|
||||||
|
serializers: {
|
||||||
|
req: (req) => ({
|
||||||
|
method: req.method,
|
||||||
|
url: req.url,
|
||||||
|
headers: req.headers,
|
||||||
|
}),
|
||||||
|
res: (res) => ({
|
||||||
|
statusCode: res.statusCode,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
providers: [AppLoggerService],
|
||||||
|
exports: [AppLoggerService],
|
||||||
|
})
|
||||||
|
export class LoggerModule {}
|
||||||
132
src/core/utils/logger/logger.service.spec.ts
Normal file
132
src/core/utils/logger/logger.service.spec.ts
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
/**
|
||||||
|
* 应用日志服务测试
|
||||||
|
*
|
||||||
|
* 功能描述:
|
||||||
|
* - 测试日志服务的核心功能
|
||||||
|
* - 验证不同日志级别的正确性
|
||||||
|
* - 测试敏感信息过滤功能
|
||||||
|
* - 验证请求上下文绑定功能
|
||||||
|
*
|
||||||
|
* 测试覆盖:
|
||||||
|
* - 服务实例化
|
||||||
|
* - 日志方法调用
|
||||||
|
* - 敏感数据过滤
|
||||||
|
* - 请求上下文绑定
|
||||||
|
*
|
||||||
|
* @author moyin
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 2024-12-13
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
|
import { ConfigService } from '@nestjs/config';
|
||||||
|
import { AppLoggerService } from './logger.service';
|
||||||
|
|
||||||
|
describe('AppLoggerService', () => {
|
||||||
|
let service: AppLoggerService;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
|
providers: [
|
||||||
|
AppLoggerService,
|
||||||
|
{
|
||||||
|
provide: ConfigService,
|
||||||
|
useValue: {
|
||||||
|
get: jest.fn((key: string, defaultValue?: any) => {
|
||||||
|
const config: Record<string, any> = {
|
||||||
|
NODE_ENV: 'test',
|
||||||
|
APP_NAME: 'test-app',
|
||||||
|
};
|
||||||
|
return config[key] || defaultValue;
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}).compile();
|
||||||
|
|
||||||
|
service = module.get<AppLoggerService>(AppLoggerService);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be defined', () => {
|
||||||
|
expect(service).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 测试信息日志记录功能
|
||||||
|
*
|
||||||
|
* 验证点:
|
||||||
|
* - info 方法能够正确调用内部 log 方法
|
||||||
|
* - 传递的参数格式正确
|
||||||
|
* - 日志级别设置正确
|
||||||
|
*/
|
||||||
|
it('should log info messages', () => {
|
||||||
|
// 监听内部 log 方法调用
|
||||||
|
const logSpy = jest.spyOn(service as any, 'log').mockImplementation();
|
||||||
|
|
||||||
|
// 调用 info 方法
|
||||||
|
service.info('Test message', { module: 'TestModule' });
|
||||||
|
|
||||||
|
// 验证调用参数
|
||||||
|
expect(logSpy).toHaveBeenCalledWith('info', {
|
||||||
|
message: 'Test message',
|
||||||
|
context: { module: 'TestModule' }
|
||||||
|
});
|
||||||
|
|
||||||
|
logSpy.mockRestore();
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 测试敏感信息过滤功能
|
||||||
|
*
|
||||||
|
* 验证点:
|
||||||
|
* - 敏感信息过滤方法被正确调用
|
||||||
|
* - 包含敏感字段的日志会触发过滤逻辑
|
||||||
|
* - 过滤功能不影响正常的日志记录流程
|
||||||
|
*/
|
||||||
|
it('should filter sensitive data', () => {
|
||||||
|
// 监听敏感信息过滤方法
|
||||||
|
const redactSpy = jest.spyOn(service as any, 'redactSensitiveData');
|
||||||
|
|
||||||
|
// 记录包含敏感信息的日志
|
||||||
|
service.info('Login attempt', {
|
||||||
|
module: 'AuthModule',
|
||||||
|
password: 'secret123',
|
||||||
|
token: 'jwt-token'
|
||||||
|
});
|
||||||
|
|
||||||
|
// 验证过滤方法被调用
|
||||||
|
expect(redactSpy).toHaveBeenCalled();
|
||||||
|
|
||||||
|
redactSpy.mockRestore();
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 测试请求上下文绑定功能
|
||||||
|
*
|
||||||
|
* 验证点:
|
||||||
|
* - bindRequest 方法返回正确的日志方法对象
|
||||||
|
* - 返回的对象包含所有必要的日志方法
|
||||||
|
* - 绑定的上下文信息能够正确传递
|
||||||
|
*/
|
||||||
|
it('should bind request context', () => {
|
||||||
|
// 模拟 HTTP 请求对象
|
||||||
|
const mockReq = {
|
||||||
|
id: 'req-123',
|
||||||
|
headers: {
|
||||||
|
'x-user-id': 'user-456'
|
||||||
|
},
|
||||||
|
ip: '127.0.0.1'
|
||||||
|
};
|
||||||
|
|
||||||
|
// 绑定请求上下文
|
||||||
|
const boundLogger = service.bindRequest(mockReq, 'TestController');
|
||||||
|
|
||||||
|
// 验证返回的日志方法对象
|
||||||
|
expect(boundLogger).toHaveProperty('info');
|
||||||
|
expect(boundLogger).toHaveProperty('error');
|
||||||
|
expect(boundLogger).toHaveProperty('warn');
|
||||||
|
expect(boundLogger).toHaveProperty('debug');
|
||||||
|
expect(boundLogger).toHaveProperty('fatal');
|
||||||
|
expect(boundLogger).toHaveProperty('trace');
|
||||||
|
});
|
||||||
|
});
|
||||||
487
src/core/utils/logger/logger.service.ts
Normal file
487
src/core/utils/logger/logger.service.ts
Normal file
@@ -0,0 +1,487 @@
|
|||||||
|
/**
|
||||||
|
* 日志系统模块
|
||||||
|
*
|
||||||
|
* 功能描述:
|
||||||
|
* - 提供统一的日志记录服务,支持多种日志级别
|
||||||
|
* - 集成 Pino 高性能日志库,支持降级到 NestJS 内置 Logger
|
||||||
|
* - 自动过滤敏感信息,保护系统安全
|
||||||
|
* - 支持请求上下文绑定,便于链路追踪
|
||||||
|
*
|
||||||
|
* 依赖模块:
|
||||||
|
* - ConfigService: 环境配置服务
|
||||||
|
* - PinoLogger: 高性能日志库(可选)
|
||||||
|
* - Logger: NestJS 内置日志服务(降级使用)
|
||||||
|
*
|
||||||
|
* @author moyin
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 2024-12-13
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Injectable, Logger, Inject, Optional } from '@nestjs/common';
|
||||||
|
import { PinoLogger } from 'nestjs-pino';
|
||||||
|
import { ConfigService } from '@nestjs/config';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 日志级别枚举
|
||||||
|
*
|
||||||
|
* 级别说明:
|
||||||
|
* - trace: 极细粒度调试信息
|
||||||
|
* - debug: 调试信息,开发环境使用
|
||||||
|
* - info: 重要业务操作记录
|
||||||
|
* - warn: 警告信息,需要关注但不影响正常流程
|
||||||
|
* - error: 错误信息,影响功能正常使用
|
||||||
|
* - fatal: 致命错误,可能导致系统不可用
|
||||||
|
*/
|
||||||
|
export type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'fatal' | 'trace';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 日志上下文接口
|
||||||
|
*
|
||||||
|
* 用于补充日志的上下文信息,便于问题排查和链路追踪
|
||||||
|
*/
|
||||||
|
export interface LogContext {
|
||||||
|
/** 请求 ID,用于链路追踪 */
|
||||||
|
reqId?: string;
|
||||||
|
/** 模块名称,标识日志来源 */
|
||||||
|
module?: string;
|
||||||
|
/** 用户 ID,关联用户行为 */
|
||||||
|
userId?: string;
|
||||||
|
/** 操作类型,描述具体操作 */
|
||||||
|
operation?: string;
|
||||||
|
/** 时间戳,记录操作时间 */
|
||||||
|
timestamp?: string;
|
||||||
|
/** 执行时长,性能监控 */
|
||||||
|
duration?: number;
|
||||||
|
/** 自定义扩展字段 */
|
||||||
|
[key: string]: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 日志选项接口
|
||||||
|
*
|
||||||
|
* 定义日志记录时的参数结构
|
||||||
|
*/
|
||||||
|
export interface LogOptions {
|
||||||
|
/** 日志消息内容 */
|
||||||
|
message: string;
|
||||||
|
/** 日志上下文信息 */
|
||||||
|
context?: LogContext;
|
||||||
|
/** 错误堆栈信息(仅用于 error/fatal 级别) */
|
||||||
|
stack?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 应用日志服务类
|
||||||
|
*
|
||||||
|
* 职责:
|
||||||
|
* - 提供统一的日志记录接口
|
||||||
|
* - 管理不同环境下的日志级别控制
|
||||||
|
* - 自动过滤敏感信息,防止数据泄露
|
||||||
|
* - 支持请求上下文绑定,便于问题追踪
|
||||||
|
*
|
||||||
|
* 主要方法:
|
||||||
|
* - debug(): 记录调试信息
|
||||||
|
* - info(): 记录重要业务操作
|
||||||
|
* - warn(): 记录警告信息
|
||||||
|
* - error(): 记录错误信息
|
||||||
|
* - fatal(): 记录致命错误
|
||||||
|
* - trace(): 记录追踪信息
|
||||||
|
* - bindRequest(): 绑定请求上下文
|
||||||
|
*
|
||||||
|
* 使用场景:
|
||||||
|
* - 业务操作日志记录
|
||||||
|
* - 系统异常监控
|
||||||
|
* - 性能监控和问题排查
|
||||||
|
* - 安全审计和行为追踪
|
||||||
|
*/
|
||||||
|
@Injectable()
|
||||||
|
export class AppLoggerService {
|
||||||
|
// 底层日志实例(优先 Pino,无则用内置 Logger)
|
||||||
|
private readonly logger: PinoLogger | Logger;
|
||||||
|
// 日志级别开关(生产环境可动态调整)
|
||||||
|
private readonly enableLevels: Record<LogLevel, boolean>;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
// 注入 Pino Logger(可选,无则降级到内置 Logger)
|
||||||
|
@Optional() @Inject(PinoLogger) private readonly pinoLogger: PinoLogger,
|
||||||
|
private readonly configService: ConfigService,
|
||||||
|
) {
|
||||||
|
// 初始化底层日志实例
|
||||||
|
this.logger = this.pinoLogger || new Logger('AppLogger');
|
||||||
|
|
||||||
|
// 从环境变量读取启用的日志级别(默认开发环境全开启,生产环境仅开启 warn/error/fatal)
|
||||||
|
const env = this.configService.get('NODE_ENV', 'development');
|
||||||
|
this.enableLevels = {
|
||||||
|
trace: env === 'development',
|
||||||
|
debug: env === 'development',
|
||||||
|
info: env !== 'production',
|
||||||
|
warn: true,
|
||||||
|
error: true,
|
||||||
|
fatal: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通用日志记录方法
|
||||||
|
*
|
||||||
|
* 功能描述:
|
||||||
|
* 封装所有日志级别的核心记录逻辑,统一处理日志格式化、上下文补充和敏感信息过滤
|
||||||
|
*
|
||||||
|
* 业务逻辑:
|
||||||
|
* 1. 检查日志级别是否启用
|
||||||
|
* 2. 补充默认上下文信息
|
||||||
|
* 3. 合并自定义上下文
|
||||||
|
* 4. 过滤敏感信息
|
||||||
|
* 5. 构造标准日志数据
|
||||||
|
* 6. 根据底层日志实例类型选择合适的输出方式
|
||||||
|
*
|
||||||
|
* @param level 日志级别,决定日志的重要程度和输出策略
|
||||||
|
* @param options 日志选项,包含消息内容、上下文信息等
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
private log(level: LogLevel, options: LogOptions): void {
|
||||||
|
// 过滤禁用的日志级别(生产环境不输出 debug/trace)
|
||||||
|
if (!this.enableLevels[level]) return;
|
||||||
|
|
||||||
|
// 1. 补充默认上下文
|
||||||
|
const defaultContext: LogContext = {
|
||||||
|
module: options.context?.module || 'Unknown',
|
||||||
|
reqId: options.context?.reqId || 'no-req-id',
|
||||||
|
userId: options.context?.userId || 'anonymous',
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
app: this.configService.get('APP_NAME', 'nest-app'),
|
||||||
|
};
|
||||||
|
|
||||||
|
// 2. 合并上下文(自定义上下文覆盖默认)
|
||||||
|
const context = { ...defaultContext, ...options.context };
|
||||||
|
|
||||||
|
// 3. 敏感信息过滤(避免日志泄露密码/Token)
|
||||||
|
this.redactSensitiveData(context);
|
||||||
|
|
||||||
|
// 4. 构造日志数据
|
||||||
|
const logData = {
|
||||||
|
message: options.message,
|
||||||
|
context,
|
||||||
|
...(options.stack ? { stack: options.stack } : {}), // 仅错误级别携带栈信息
|
||||||
|
};
|
||||||
|
|
||||||
|
// 5. 适配 Pino/内置 Logger 的调用方式
|
||||||
|
if (this.pinoLogger) {
|
||||||
|
// Pino 调用方式:直接使用 pinoLogger 实例
|
||||||
|
switch (level) {
|
||||||
|
case 'debug':
|
||||||
|
this.pinoLogger.debug(logData.message, logData);
|
||||||
|
break;
|
||||||
|
case 'info':
|
||||||
|
this.pinoLogger.info(logData.message, logData);
|
||||||
|
break;
|
||||||
|
case 'warn':
|
||||||
|
this.pinoLogger.warn(logData.message, logData);
|
||||||
|
break;
|
||||||
|
case 'error':
|
||||||
|
this.pinoLogger.error(logData.message, logData);
|
||||||
|
break;
|
||||||
|
case 'fatal':
|
||||||
|
this.pinoLogger.fatal(logData.message, logData);
|
||||||
|
break;
|
||||||
|
case 'trace':
|
||||||
|
this.pinoLogger.trace(logData.message, logData);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
this.pinoLogger.info(logData.message, logData);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 内置 Logger 降级调用:根据级别调用对应方法
|
||||||
|
const builtInLogger = this.logger as Logger;
|
||||||
|
const contextString = JSON.stringify(logData.context);
|
||||||
|
|
||||||
|
switch (level) {
|
||||||
|
case 'debug':
|
||||||
|
builtInLogger.debug(logData.message, contextString);
|
||||||
|
break;
|
||||||
|
case 'info':
|
||||||
|
builtInLogger.log(logData.message, contextString); // 内置 Logger 使用 log 方法代替 info
|
||||||
|
break;
|
||||||
|
case 'warn':
|
||||||
|
builtInLogger.warn(logData.message, contextString);
|
||||||
|
break;
|
||||||
|
case 'error':
|
||||||
|
case 'fatal': // fatal 级别降级为 error
|
||||||
|
builtInLogger.error(logData.message, options.stack || '', contextString);
|
||||||
|
break;
|
||||||
|
case 'trace':
|
||||||
|
builtInLogger.verbose(logData.message, contextString); // trace 级别降级为 verbose
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
builtInLogger.log(logData.message, contextString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 敏感信息过滤方法
|
||||||
|
*
|
||||||
|
* 功能描述:
|
||||||
|
* 递归扫描日志数据中的敏感字段,将其替换为占位符,防止敏感信息泄露
|
||||||
|
*
|
||||||
|
* 业务逻辑:
|
||||||
|
* 1. 定义敏感字段关键词列表
|
||||||
|
* 2. 遍历数据对象的所有键
|
||||||
|
* 3. 检查键名是否包含敏感关键词
|
||||||
|
* 4. 将敏感字段值替换为 [REDACTED]
|
||||||
|
* 5. 递归处理嵌套对象
|
||||||
|
*
|
||||||
|
* @param data 需要过滤的日志数据对象
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
private redactSensitiveData(data: Record<string, any>): void {
|
||||||
|
const sensitiveKeys = ['password', 'token', 'secret', 'authorization', 'cardNo'];
|
||||||
|
Object.keys(data).forEach((key) => {
|
||||||
|
if (sensitiveKeys.some((sk) => key.toLowerCase().includes(sk))) {
|
||||||
|
data[key] = '[REDACTED]'; // 替换为占位符,或直接删除
|
||||||
|
}
|
||||||
|
// 递归过滤嵌套对象
|
||||||
|
if (typeof data[key] === 'object' && data[key] !== null) {
|
||||||
|
this.redactSensitiveData(data[key]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========== 公共日志记录方法 ==========
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 记录调试日志
|
||||||
|
*
|
||||||
|
* 功能描述:
|
||||||
|
* 记录详细的调试信息,主要用于开发环境的问题排查
|
||||||
|
*
|
||||||
|
* 使用场景:
|
||||||
|
* - 方法调用参数记录
|
||||||
|
* - 中间计算结果输出
|
||||||
|
* - 详细的执行流程追踪
|
||||||
|
*
|
||||||
|
* 注意事项:
|
||||||
|
* - 仅在开发环境启用
|
||||||
|
* - 生产环境自动禁用以提高性能
|
||||||
|
*
|
||||||
|
* @param message 调试消息内容
|
||||||
|
* @param context 调试上下文信息
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```typescript
|
||||||
|
* this.logger.debug('开始处理用户请求', {
|
||||||
|
* module: 'UserService',
|
||||||
|
* operation: 'getUserInfo',
|
||||||
|
* userId: 'user123',
|
||||||
|
* params: { includeProfile: true }
|
||||||
|
* });
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
debug(message: string, context?: LogContext): void {
|
||||||
|
this.log('debug', { message, context });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 记录信息日志
|
||||||
|
*
|
||||||
|
* 功能描述:
|
||||||
|
* 记录重要的业务操作和系统状态变更,用于业务监控和审计
|
||||||
|
*
|
||||||
|
* 使用场景:
|
||||||
|
* - 用户登录成功
|
||||||
|
* - 重要业务操作完成
|
||||||
|
* - 系统状态变更
|
||||||
|
* - 关键流程节点记录
|
||||||
|
*
|
||||||
|
* @param message 信息消息内容
|
||||||
|
* @param context 操作上下文信息
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```typescript
|
||||||
|
* this.logger.info('用户登录成功', {
|
||||||
|
* module: 'AuthService',
|
||||||
|
* operation: 'userLogin',
|
||||||
|
* userId: 'user123',
|
||||||
|
* timestamp: new Date().toISOString()
|
||||||
|
* });
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
info(message: string, context?: LogContext): void {
|
||||||
|
this.log('info', { message, context });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 记录警告日志
|
||||||
|
*
|
||||||
|
* 功能描述:
|
||||||
|
* 记录需要关注但不影响正常业务流程的警告信息
|
||||||
|
*
|
||||||
|
* 使用场景:
|
||||||
|
* - 参数验证失败
|
||||||
|
* - 权限检查失败
|
||||||
|
* - 资源不存在
|
||||||
|
* - 业务规则违反
|
||||||
|
* - 性能指标异常
|
||||||
|
*
|
||||||
|
* @param message 警告消息内容
|
||||||
|
* @param context 警告上下文信息
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```typescript
|
||||||
|
* this.logger.warn('用户尝试访问不存在的资源', {
|
||||||
|
* module: 'ResourceService',
|
||||||
|
* operation: 'getResource',
|
||||||
|
* userId: 'user123',
|
||||||
|
* resourceId: 'res456',
|
||||||
|
* reason: 'resource_not_found'
|
||||||
|
* });
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
warn(message: string, context?: LogContext): void {
|
||||||
|
this.log('warn', { message, context });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 记录错误日志
|
||||||
|
*
|
||||||
|
* 功能描述:
|
||||||
|
* 记录影响业务功能正常使用的错误信息,包含详细的错误上下文和堆栈信息
|
||||||
|
*
|
||||||
|
* 使用场景:
|
||||||
|
* - 业务逻辑异常
|
||||||
|
* - 数据库操作失败
|
||||||
|
* - 第三方服务调用失败
|
||||||
|
* - 系统内部错误
|
||||||
|
*
|
||||||
|
* @param message 错误消息内容
|
||||||
|
* @param context 错误上下文信息
|
||||||
|
* @param stack 错误堆栈信息,用于问题定位
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```typescript
|
||||||
|
* this.logger.error('数据库连接失败', {
|
||||||
|
* module: 'DatabaseService',
|
||||||
|
* operation: 'connect',
|
||||||
|
* error: error.message,
|
||||||
|
* timestamp: new Date().toISOString()
|
||||||
|
* }, error.stack);
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
error(message: string, context?: LogContext, stack?: string): void {
|
||||||
|
this.log('error', { message, context, stack });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 记录致命错误日志
|
||||||
|
*
|
||||||
|
* 功能描述:
|
||||||
|
* 记录可能导致系统不可用的严重错误,需要立即处理
|
||||||
|
*
|
||||||
|
* 使用场景:
|
||||||
|
* - 数据库完全不可用
|
||||||
|
* - 关键服务宕机
|
||||||
|
* - 系统资源耗尽
|
||||||
|
* - 安全漏洞被利用
|
||||||
|
*
|
||||||
|
* @param message 致命错误消息内容
|
||||||
|
* @param context 错误上下文信息
|
||||||
|
* @param stack 错误堆栈信息
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```typescript
|
||||||
|
* this.logger.fatal('数据库连接池耗尽', {
|
||||||
|
* module: 'DatabaseService',
|
||||||
|
* operation: 'getConnection',
|
||||||
|
* activeConnections: 100,
|
||||||
|
* maxConnections: 100,
|
||||||
|
* timestamp: new Date().toISOString()
|
||||||
|
* }, error.stack);
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
fatal(message: string, context?: LogContext, stack?: string): void {
|
||||||
|
this.log('fatal', { message, context, stack });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 记录追踪日志
|
||||||
|
*
|
||||||
|
* 功能描述:
|
||||||
|
* 记录极细粒度的执行追踪信息,用于深度调试和性能分析
|
||||||
|
*
|
||||||
|
* 使用场景:
|
||||||
|
* - 循环内的变量状态
|
||||||
|
* - 算法执行步骤
|
||||||
|
* - 性能关键路径追踪
|
||||||
|
* - 复杂业务逻辑的详细执行流程
|
||||||
|
*
|
||||||
|
* 注意事项:
|
||||||
|
* - 仅在开发环境启用
|
||||||
|
* - 会产生大量日志,谨慎使用
|
||||||
|
*
|
||||||
|
* @param message 追踪消息内容
|
||||||
|
* @param context 追踪上下文信息
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```typescript
|
||||||
|
* this.logger.trace('处理数组元素', {
|
||||||
|
* module: 'DataProcessor',
|
||||||
|
* operation: 'processArray',
|
||||||
|
* currentIndex: i,
|
||||||
|
* elementValue: array[i],
|
||||||
|
* totalElements: array.length
|
||||||
|
* });
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
trace(message: string, context?: LogContext): void {
|
||||||
|
this.log('trace', { message, context });
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========== 便捷方法 ==========
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绑定请求上下文的日志记录器
|
||||||
|
*
|
||||||
|
* 功能描述:
|
||||||
|
* 创建一个绑定了特定请求上下文的日志记录器,自动携带请求相关信息
|
||||||
|
*
|
||||||
|
* 业务逻辑:
|
||||||
|
* 1. 从请求对象中提取关键信息
|
||||||
|
* 2. 构建基础上下文对象
|
||||||
|
* 3. 返回包装后的日志方法集合
|
||||||
|
* 4. 每次调用时自动合并基础上下文和额外上下文
|
||||||
|
*
|
||||||
|
* 使用场景:
|
||||||
|
* - HTTP 请求处理过程中的日志记录
|
||||||
|
* - WebSocket 连接的日志追踪
|
||||||
|
* - 需要关联用户行为的业务操作
|
||||||
|
*
|
||||||
|
* @param req HTTP 请求对象或类似的上下文对象
|
||||||
|
* @param module 模块名称,标识日志来源
|
||||||
|
* @returns 绑定了请求上下文的日志方法对象
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```typescript
|
||||||
|
* // 在 Controller 中使用
|
||||||
|
* const requestLogger = this.logger.bindRequest(req, 'UserController');
|
||||||
|
* requestLogger.info('开始处理用户请求', { action: 'getUserProfile' });
|
||||||
|
* requestLogger.error('处理失败', error.stack, { reason: 'database_error' });
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
bindRequest(req: any, module: string) {
|
||||||
|
const baseContext: LogContext = {
|
||||||
|
reqId: req.id || req.headers['x-request-id'],
|
||||||
|
userId: req.headers['x-user-id'] || 'anonymous',
|
||||||
|
ip: req.ip,
|
||||||
|
module,
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
debug: (message: string, extra?: LogContext) => this.debug(message, { ...baseContext, ...extra }),
|
||||||
|
info: (message: string, extra?: LogContext) => this.info(message, { ...baseContext, ...extra }),
|
||||||
|
warn: (message: string, extra?: LogContext) => this.warn(message, { ...baseContext, ...extra }),
|
||||||
|
error: (message: string, stack?: string, extra?: LogContext) => this.error(message, { ...baseContext, ...extra }, stack),
|
||||||
|
fatal: (message: string, stack?: string, extra?: LogContext) => this.fatal(message, { ...baseContext, ...extra }, stack),
|
||||||
|
trace: (message: string, extra?: LogContext) => this.trace(message, { ...baseContext, ...extra }),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user