告别崩溃:Nest.js全链路错误追踪与告警实战指南
你是否遇到过生产环境突然崩溃却找不到根源?用户投诉服务异常却无法复现问题?本文将带你从零构建Nest.js应用的错误追踪体系,通过异常监控、日志聚合和智能告警三大模块,让80%的线上问题在用户察觉前被解决。读完你将掌握:
- 自定义ExceptionFilter捕获全量错误
- 结构化日志与错误上下文收集技巧
- 企业级告警系统集成方案
- 生产环境错误调试与快速恢复方法
异常捕获:构建Nest.js错误拦截网
Nest.js提供了强大的异常处理机制,核心在于ExceptionFilter(异常过滤器)接口。框架默认的基础过滤器实现了HTTP异常的标准化响应,你可以在packages/core/exceptions/base-exception-filter.ts查看完整源码。
全局异常过滤器实现
创建全局异常过滤器是捕获所有错误的第一步。以下是生产级实现示例,包含错误分类、上下文收集和日志记录:
import { ExceptionFilter, Catch, ArgumentsHost, Logger } from '@nestjs/common';
import { Response, Request } from 'express';
import { HttpAdapterHost } from '@nestjs/core';
@Catch()
export class AllExceptionsFilter implements ExceptionFilter {
private readonly logger = new Logger(AllExceptionsFilter.name);
constructor(private readonly httpAdapterHost: HttpAdapterHost) {}
catch(exception: unknown, host: ArgumentsHost) {
const { httpAdapter } = this.httpAdapterHost;
const ctx = host.switchToHttp();
const request = ctx.getRequest<Request>();
const response = ctx.getResponse<Response>();
// 错误分类处理
const statusCode = this.getStatusCode(exception);
const errorResponse = this.formatError(exception, request);
// 记录错误日志(包含请求上下文)
this.logger.error({
message: errorResponse.message,
stack: exception instanceof Error ? exception.stack : undefined,
path: request.url,
method: request.method,
ip: request.ip,
userId: request.user?.id,
timestamp: new Date().toISOString()
});
// 发送响应
httpAdapter.reply(response, errorResponse, statusCode);
}
private getStatusCode(exception: unknown): number {
if (exception instanceof HttpException) {
return exception.getStatus();
}
return HttpStatus.INTERNAL_SERVER_ERROR;
}
private formatError(exception: unknown, request: Request): object {
// 格式化不同类型异常的响应结构
// ...实现代码
}
}
过滤器注册与作用域控制
在应用根模块注册全局过滤器:
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { AllExceptionsFilter } from './filters/all-exceptions.filter';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
// 注册全局异常过滤器
app.useGlobalFilters(new AllExceptionsFilter(
app.get(HttpAdapterHost)
));
await app.listen(3000);
}
bootstrap();
Nest.js的异常过滤器支持三种作用域:
- 全局作用域:捕获整个应用的异常
- 控制器作用域:通过
@UseFilters()装饰器应用于控制器 - 路由作用域:仅对特定路由生效
日志聚合:错误数据的标准化存储
结构化日志配置
使用@nestjs/common的Logger模块配合Winston实现结构化日志:
// src/utils/logger.ts
import { createLogger, transports, format } from 'winston';
export const logger = createLogger({
level: process.env.LOG_LEVEL || 'info',
format: format.combine(
format.timestamp(),
format.json()
),
defaultMeta: { service: 'user-service' },
transports: [
new transports.File({ filename: 'error.log', level: 'error' }),
new transports.File({ filename: 'combined.log' }),
],
});
// 开发环境控制台输出
if (process.env.NODE_ENV !== 'production') {
logger.add(new transports.Console({
format: format.combine(
format.colorize(),
format.simple()
),
}));
}
日志数据收集关键点
有效的错误日志应包含:
- 错误唯一ID(便于追踪)
- 时间戳(精确到毫秒)
- 请求上下文(URL、方法、IP等)
- 用户信息(已认证用户)
- 错误堆栈(开发/测试环境)
- 业务标签(模块、功能等)
告警系统:异常监控与即时响应
告警触发机制
实现基于错误频率和严重级别的告警阈值:
// src/services/alert.service.ts
import { Injectable } from '@nestjs/common';
import { logger } from '../utils/logger';
@Injectable()
export class AlertService {
private errorCounter = new Map<string, number>();
private alertThreshold = 5; // 5分钟内超过5次相同错误触发告警
async checkAndSendAlert(error: Error, context: object) {
const errorKey = this.generateErrorKey(error);
const currentCount = (this.errorCounter.get(errorKey) || 0) + 1;
this.errorCounter.set(errorKey, currentCount);
// 检查是否达到告警阈值
if (currentCount >= this.alertThreshold) {
await this.sendAlert(error, context, currentCount);
// 重置计数器
this.errorCounter.set(errorKey, 0);
}
// 设置定期清理计数器
setTimeout(() => {
this.errorCounter.set(errorKey, Math.max(0, currentCount - 1));
}, 5 * 60 * 1000); // 5分钟后递减
}
private generateErrorKey(error: Error): string {
// 生成唯一错误标识
return error.name + ':' + error.message.substring(0, 100);
}
private async sendAlert(error: Error, context: object, count: number) {
// 实现告警发送逻辑(邮件、Slack、短信等)
logger.error('Alert triggered', {
error: error.message,
count,
context
});
// 调用外部告警API
// ...
}
}
主流监控平台集成
Nest.js应用可通过以下方式集成监控平台:
-
Prometheus + Grafana:指标监控与可视化
// src/modules/metrics/metrics.module.ts import { Module } from '@nestjs/common'; import { PrometheusModule } from '@willsoto/nestjs-prometheus'; @Module({ imports: [ PrometheusModule.register({ path: '/metrics', }), ], }) export class MetricsModule {} -
Sentry:错误跟踪与性能监控
// main.ts import * as Sentry from '@sentry/node'; import { Integrations } from '@sentry/tracing'; Sentry.init({ dsn: "YOUR_SENTRY_DSN", integrations: [ new Integrations.Http({ tracing: true }), new Integrations.Express({ app }), ], tracesSampleRate: 1.0, });
实战案例:从错误发生到解决的全流程
案例1:数据库连接失败处理
// src/exceptions/database.exception.ts
import { HttpException, HttpStatus } from '@nestjs/common';
export class DatabaseConnectionException extends HttpException {
constructor(message: string, error?: Error) {
super({
statusCode: HttpStatus.SERVICE_UNAVAILABLE,
message: 'Database connection failed',
details: message,
errorId: Date.now().toString()
}, HttpStatus.SERVICE_UNAVAILABLE);
// 记录原始错误堆栈
if (error) {
this.stack = error.stack;
}
}
}
对应的异常过滤器:
// src/filters/database-exception.filter.ts
import { Catch, ArgumentsHost, Logger } from '@nestjs/common';
import { BaseExceptionFilter } from '@nestjs/core';
import { DatabaseConnectionException } from '../exceptions/database.exception';
import { AlertService } from '../services/alert.service';
@Catch(DatabaseConnectionException)
export class DatabaseExceptionFilter extends BaseExceptionFilter {
private readonly logger = new Logger(DatabaseExceptionFilter.name);
constructor(
private readonly alertService: AlertService,
httpAdapterHost: HttpAdapterHost
) {
super(httpAdapterHost);
}
async catch(exception: DatabaseConnectionException, host: ArgumentsHost) {
// 发送紧急告警
await this.alertService.sendAlert(exception, {
type: 'database',
severity: 'critical',
action: 'restart-service'
});
// 调用父类方法发送响应
super.catch(exception, host);
}
}
案例2:用户认证错误处理
使用Nest.js内置的异常机制处理认证错误:
// src/auth/auth.service.ts
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { UsersService } from '../users/users.service';
@Injectable()
export class AuthService {
constructor(
private usersService: UsersService,
private jwtService: JwtService,
) {}
async validateUser(username: string, pass: string): Promise<any> {
const user = await this.usersService.findOne(username);
if (!user || !(await user.comparePassword(pass))) {
// 抛出标准认证异常
throw new UnauthorizedException({
message: 'Invalid credentials',
errorId: this.generateErrorId()
});
}
return user;
}
private generateErrorId(): string {
return Math.random().toString(36).substring(2, 10);
}
}
最佳实践与工具推荐
错误处理 checklist
- 前端错误边界:配合后端提供友好错误页面
- 错误重试机制:对 transient 错误实现自动恢复
- 降级策略:核心功能不可用时的替代方案
- 定期演练:模拟常见错误场景测试响应流程
推荐工具链
- 监控系统:Prometheus + Grafana
- 日志管理:ELK Stack (Elasticsearch, Logstash, Kibana)
- 错误跟踪:Sentry, Datadog
- 告警渠道:Slack, Email, SMS, PagerDuty
总结与展望
构建健壮的错误追踪系统是企业级Nest.js应用的必备能力。通过本文介绍的异常过滤、日志聚合和告警集成方案,你可以:
- 将错误检测时间从小时级降至分钟级
- 减少80%的问题排查时间
- 建立可追溯的错误解决流程
- 提升系统整体可用性和用户满意度
随着微服务架构的普及,分布式追踪将成为错误处理的下一个重点。Nest.js与OpenTelemetry的集成将是值得关注的方向。
记住:优秀的错误处理不是等到问题发生后才去解决,而是在设计阶段就预见可能的故障点,并建立完善的防御机制。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



