nest-winston错误处理:如何优雅记录和追踪应用异常 [特殊字符]
nest-winston错误处理:如何优雅记录和追踪应用异常 🐛
【免费下载链接】nest-winstonA Nest module wrapper form winston logger项目地址: https://gitcode.com/gh_mirrors/ne/nest-winston
在构建NestJS应用时,优雅的错误处理和日志记录是确保应用稳定性的关键环节。nest-winston作为NestJS的Winston日志模块包装器,为开发者提供了强大的错误追踪能力。本文将为你揭示如何使用nest-winston进行专业的错误处理,让你的应用异常无处遁形!
为什么选择nest-winston进行错误处理? 🤔
nest-winston不仅仅是一个日志记录工具,它是专为NestJS设计的日志解决方案。与原生console.log相比,nest-winston提供了结构化日志、多传输目标、上下文感知等高级功能。对于错误处理而言,这意味着:
- 结构化错误信息:将错误堆栈、上下文、时间戳等信息统一格式
- 多目标输出:同时记录到控制台、文件、数据库等不同目标
- 性能优化:异步日志记录不影响应用性能
- 与NestJS生态完美集成:无缝替换NestJS内置日志系统
快速配置nest-winston错误日志记录 🚀
首先,在你的NestJS项目中安装nest-winston:
npm install nest-winston winston然后配置基础的错误日志记录:
import { Module } from '@nestjs/common'; import { WinstonModule } from 'nest-winston'; import * as winston from 'winston'; import { utilities as nestWinstonModuleUtilities } from 'nest-winston'; @Module({ imports: [ WinstonModule.forRoot({ transports: [ new winston.transports.Console({ level: 'error', // 只记录错误级别日志 format: winston.format.combine( winston.format.timestamp(), winston.format.errors({ stack: true }), // 捕获错误堆栈 nestWinstonModuleUtilities.format.nestLike('MyApp', { colors: true, prettyPrint: true, }), ), }), new winston.transports.File({ filename: 'logs/error.log', level: 'error', format: winston.format.combine( winston.format.timestamp(), winston.format.json(), // JSON格式便于分析 ), }), ], }), ], }) export class AppModule {}三种错误记录方式对比 📊
nest-winston提供了三种不同的错误记录方式,每种方式都有其适用场景:
1. 基础Winston记录器(仅应用日志)
使用WINSTON_MODULE_PROVIDER注入令牌,适合只需要记录应用业务日志的场景:
import { Controller, Get, Inject } from '@nestjs/common'; import { WINSTON_MODULE_PROVIDER } from 'nest-winston'; import { Logger } from 'winston'; @Controller('users') export class UsersController { constructor( @Inject(WINSTON_MODULE_PROVIDER) private readonly logger: Logger, ) {} @Get() async findAll() { try { // 业务逻辑 return await this.userService.findAll(); } catch (error) { // 记录详细错误信息 this.logger.error('获取用户列表失败', { error: error.message, stack: error.stack, timestamp: new Date().toISOString(), context: 'UsersController', }); throw error; // 重新抛出,让全局过滤器处理 } } }2. NestJS系统日志替换(推荐)
使用WINSTON_MODULE_NEST_PROVIDER替换NestJS内置日志系统,统一应用和系统日志:
// main.ts import { WINSTON_MODULE_NEST_PROVIDER } from 'nest-winston'; async function bootstrap() { const app = await NestFactory.create(AppModule); app.useLogger(app.get(WINSTON_MODULE_NEST_PROVIDER)); await app.listen(3000); } bootstrap(); // 控制器中使用 import { Controller, Get, Inject, LoggerService } from '@nestjs/common'; import { WINSTON_MODULE_NEST_PROVIDER } from 'nest-winston'; @Controller('products') export class ProductsController { constructor( @Inject(WINSTON_MODULE_NEST_PROVIDER) private readonly logger: LoggerService, ) {} @Get() async findAll() { this.logger.log('开始查询产品列表', ProductsController.name); try { const result = await this.productService.findAll(); this.logger.log('产品查询成功', ProductsController.name); return result; } catch (error) { this.logger.error( '产品查询失败', error.stack, // 错误堆栈 ProductsController.name, // 上下文 ); throw error; } } }3. 完全替换NestJS日志(包含启动日志)
使用WinstonModule.createLogger()在应用启动时完全替换NestJS日志系统:
// main.ts import { WinstonModule } from 'nest-winston'; import * as winston from 'winston'; async function bootstrap() { const app = await NestFactory.create(AppModule, { logger: WinstonModule.createLogger({ transports: [ new winston.transports.Console({ format: winston.format.combine( winston.format.timestamp(), winston.format.errors({ stack: true }), winston.format.simple(), ), }), new winston.transports.File({ filename: 'logs/combined.log', level: 'info', }), new winston.transports.File({ filename: 'logs/errors.log', level: 'error', }), ], }), }); await app.listen(3000); } bootstrap();高级错误处理技巧 🔧
1. 自定义错误格式化
通过创建自定义格式化器,你可以为错误信息添加更多上下文:
const errorFormatter = winston.format((info) => { if (info instanceof Error) { return { ...info, message: info.message, stack: info.stack, type: info.constructor.name, }; } return info; }); // 在配置中使用 WinstonModule.forRoot({ format: winston.format.combine( errorFormatter(), winston.format.json(), ), transports: [/* ... */], })2. 错误分类与过滤
根据错误类型进行不同的处理:
// 创建不同级别的错误处理器 const errorTransports = [ new winston.transports.File({ filename: 'logs/database-errors.log', level: 'error', filter: (info) => info.context?.includes('Database'), }), new winston.transports.File({ filename: 'logs/validation-errors.log', level: 'error', filter: (info) => info.context?.includes('Validation'), }), new winston.transports.File({ filename: 'logs/http-errors.log', level: 'error', filter: (info) => info.context?.includes('Http'), }), ];3. 异步错误处理
对于异步操作,确保错误被正确捕获:
@Injectable() export class UserService { constructor( @Inject(WINSTON_MODULE_PROVIDER) private readonly logger: Logger, ) {} async createUser(userData: CreateUserDto) { try { // 异步数据库操作 const user = await this.userRepository.save(userData); this.logger.log(`用户创建成功: ${user.id}`, 'UserService'); return user; } catch (error) { this.logger.error('用户创建失败', { error: error.message, stack: error.stack, userData, timestamp: new Date().toISOString(), }); // 根据错误类型返回不同的响应 if (error.code === '23505') { throw new ConflictException('用户已存在'); } throw new InternalServerErrorException('创建用户时发生错误'); } } }错误监控与告警集成 📈
1. 集成Sentry等错误监控平台
import * as Sentry from '@sentry/node'; import { Logger } from 'winston'; class SentryTransport extends winston.Transport { log(info: any, callback: Function) { if (info.level === 'error') { Sentry.captureException(info.error || new Error(info.message), { extra: info, }); } callback(); } } // 添加到传输列表 transports: [ new winston.transports.Console(), new SentryTransport(), ]2. 性能监控与错误关联
@Injectable() export class PerformanceMonitorInterceptor implements NestInterceptor { constructor( @Inject(WINSTON_MODULE_PROVIDER) private readonly logger: Logger, ) {} intercept(context: ExecutionContext, next: CallHandler): Observable<any> { const startTime = Date.now(); const request = context.switchToHttp().getRequest(); return next.handle().pipe( tap(() => { const duration = Date.now() - startTime; this.logger.info(`请求完成`, { method: request.method, url: request.url, duration: `${duration}ms`, status: 'success', }); }), catchError((error) => { const duration = Date.now() - startTime; this.logger.error(`请求失败`, { method: request.method, url: request.url, duration: `${duration}ms`, error: error.message, stack: error.stack, status: 'error', }); return throwError(() => error); }), ); } }最佳实践总结 ✅
- 统一错误格式:确保所有错误都包含时间戳、上下文、错误信息和堆栈跟踪
- 分级处理:根据错误严重程度使用不同的日志级别(error、warn、info)
- 上下文丰富:在错误日志中包含请求ID、用户ID等上下文信息
- 敏感信息过滤:避免在日志中记录密码、令牌等敏感信息
- 定期清理:设置日志轮转策略,避免日志文件过大
- 监控集成:将错误日志与监控系统集成,实现实时告警
常见问题解答 ❓
Q: 如何在生产环境中配置nest-winston?A: 在生产环境中,建议禁用控制台颜色,使用JSON格式,并配置日志轮转:
WinstonModule.forRoot({ format: winston.format.combine( winston.format.timestamp(), winston.format.json(), ), transports: [ new winston.transports.File({ filename: 'logs/error-%DATE%.log', datePattern: 'YYYY-MM-DD', maxSize: '20m', maxFiles: '30d', level: 'error', }), new winston.transports.File({ filename: 'logs/combined-%DATE%.log', datePattern: 'YYYY-MM-DD', maxSize: '20m', maxFiles: '7d', }), ], })Q: 如何处理未捕获的异常?A: 使用NestJS的异常过滤器结合nest-winston:
@Catch() export class AllExceptionsFilter implements ExceptionFilter { constructor( @Inject(WINSTON_MODULE_PROVIDER) private readonly logger: Logger, ) {} catch(exception: unknown, host: ArgumentsHost) { const ctx = host.switchToHttp(); const response = ctx.getResponse<Response>(); const request = ctx.getRequest<Request>(); const status = exception instanceof HttpException ? exception.getStatus() : HttpStatus.INTERNAL_SERVER_ERROR; this.logger.error('未捕获的异常', { statusCode: status, timestamp: new Date().toISOString(), path: request.url, method: request.method, exception: exception, }); response.status(status).json({ statusCode: status, timestamp: new Date().toISOString(), path: request.url, message: '内部服务器错误', }); } }结语 🎯
通过nest-winston的强大功能,你可以构建出专业级的错误处理系统。记住,好的错误处理不仅仅是记录错误,更是为了快速定位问题、分析原因并预防未来类似问题的发生。现在就开始使用nest-winston,让你的NestJS应用更加健壮可靠吧!
想要了解更多高级用法?查看项目中的示例代码:sample/quick-start/src/app.controller.ts 和 sample/replace-nest-logger/src/app.controller.ts 获取更多灵感!
【免费下载链接】nest-winstonA Nest module wrapper form winston logger项目地址: https://gitcode.com/gh_mirrors/ne/nest-winston
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
