Nestjs教程使用Prometheus进行监控与报警
最近在Nestjs项目中集成Prometheus时遇到一些问题,想请教大家:
- 如何在Nestjs中正确配置Prometheus的metrics端点?官方文档的示例不太清晰,尝试后/metrics返回404
- 自定义业务指标(比如API调用次数)应该怎样注入到Prometheus中?是否需要额外的装饰器或中间件?
- 报警规则配置有什么最佳实践?比如针对HTTP 5xx错误或响应延迟的阈值设置
- 本地开发时一切正常,但部署到Kubernetes后Prometheus无法抓取数据,是否和service mesh的sidecar有关?
- 有没有开箱即用的Nestjs+Prometheus监控面板模板推荐?Grafana官方库没找到适配的仪表盘
项目中用的是@nestjs/prometheus包,但感觉文档太少,社区案例基本都是Java/Go的,求大佬分享实战经验!
3 回复
在NestJS中使用Prometheus进行监控和报警的步骤如下:
-
安装依赖
首先需要安装[@willsoto](/user/willsoto)/nestjs-prometheus
包来集成Prometheus。npm install [@willsoto](/user/willsoto)/nestjs-prometheus
-
配置模块
在你的NestJS项目中引入PrometheusModule
并配置它。import { Module } from '[@nestjs](/user/nestjs)/common'; import { PrometheusModule } from '[@willsoto](/user/willsoto)/nestjs-prometheus'; [@Module](/user/Module)({ imports: [ PrometheusModule.register({ defaultLabels: { app: 'my-app' }, }), ], }) export class AppModule {}
-
创建指标
使用装饰器定义监控指标。import { Controller, Get, MetricsController, promMetrics } from '[@willsoto](/user/willsoto)/nestjs-prometheus'; import { Counter } from '[@willsoto](/user/willsoto)/nestjs-prometheus/build/src/prom.types'; [@Controller](/user/Controller)() export class AppController { @Counter({ name: 'http_requests_total', help: 'Total number of HTTP requests' }) private readonly httpRequests; constructor() { this.httpRequests = promMetrics().getCounter('http_requests_total'); } @Get() root() { this.httpRequests.inc(); return { message: 'Hello World!' }; } }
-
启动服务
启动NestJS应用后,访问/metrics
即可获取Prometheus格式的数据。 -
设置报警规则
在Prometheus配置文件中添加报警规则,例如:groups: - name: example rules: - alert: HighRequestRate expr: increase(http_requests_total[5m]) > 100 for: 1m labels: severity: warning annotations: summary: "High request rate detected"
通过以上步骤,你可以实现NestJS应用的监控和报警功能。
要使用Prometheus监控NestJS应用,首先安装@nestjs/microservices
和prom-client
库。创建一个服务,用于暴露监控指标。
- 安装依赖:
npm install @nestjs/microservices prom-client
- 创建监控服务:
import { Injectable } from '@nestjs/common';
import { Counter, Gauge, Histogram, Registry } from 'prom-client';
@Injectable()
export class MetricsService {
private readonly _requestCounter = new Counter({
name: 'http_requests_total',
help: 'Total HTTP requests',
labelNames: ['method', 'endpoint', 'status_code'],
});
private readonly _responseTimeHistogram = Histogram.build({
name: 'http_response_time_ms',
help: 'HTTP response time in milliseconds',
labelNames: ['method', 'endpoint'],
buckets: [50, 100, 200, 300, 400, 500],
});
constructor() {
// 注册到全局Registry
Registry.setDefaultLabels({ app: 'my-nest-app' });
Registry.register(this._requestCounter);
Registry.register(this._responseTimeHistogram);
}
// 在请求处理时更新计数器
trackRequest(method: string, endpoint: string, statusCode: number) {
this._requestCounter.inc({ method, endpoint, status_code: statusCode.toString() });
}
// 在响应时记录耗时
recordResponseTime(method: string, endpoint: string, durationMs: number) {
this._responseTimeHistogram.observe({ method, endpoint }, durationMs);
}
}
- 在全局拦截器中使用该服务记录数据:
import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
import { Observable } from 'rxjs';
import { finalize } from 'rxjs/operators';
import { MetricsService } from './metrics.service';
@Injectable()
export class MetricsInterceptor implements NestInterceptor {
constructor(private readonly metricsService: MetricsService) {}
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
const request = context.switchToHttp().getRequest();
const { method, url } = request;
const start = Date.now();
return next.handle().pipe(
finalize(() => {
const duration = Date.now() - start;
const statusCode = request.res.statusCode;
this.metricsService.trackRequest(method, url, statusCode);
this.metricsService.recordResponseTime(method, url, duration);
}),
);
}
}
- 在
AppModule
中注册拦截器:
import { Module, MiddlewareConsumer, RequestMethod } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { MetricsInterceptor } from './metrics.interceptor';
@Module({
imports: [],
controllers: [AppController],
providers: [AppService, MetricsService],
})
export class AppModule {
configure(consumer: MiddlewareConsumer) {
consumer
.apply(MetricsInterceptor)
.exclude({ path: '*', method: RequestMethod.GET })
.forRoutes('*');
}
}
- 启动NestJS应用后,Prometheus可以通过抓取
/metrics
路径获取数据。配置Prometheus Job来抓取你的应用数据,并设置警报规则。
NestJS集成Prometheus进行监控和报警的简明教程:
- 首先安装必要依赖:
npm install @willsoto/nestjs-prometheus prom-client
- 在AppModule中导入Prometheus模块:
import { Module } from '@nestjs/common';
import { PrometheusModule } from '@willsoto/nestjs-prometheus';
@Module({
imports: [
PrometheusModule.register({
defaultMetrics: {
enabled: true,
},
}),
],
})
export class AppModule {}
- 创建自定义指标(示例计数器):
import { Injectable } from '@nestjs/common';
import { Counter } from 'prom-client';
import { InjectMetric } from '@willsoto/nestjs-prometheus';
@Injectable()
export class AppService {
constructor(
@InjectMetric('http_requests_total')
private counter: Counter<string>,
) {}
getHello() {
this.counter.inc(); // 每次调用增加计数器
return 'Hello World!';
}
}
-
设置/metrics端点: 默认会暴露在
/metrics
路径,可直接访问获取指标数据。 -
报警配置建议:
- 使用Prometheus Alertmanager设置规则
- 常见报警规则示例:
groups:
- name: example
rules:
- alert: HighRequestRate
expr: rate(http_requests_total[1m]) > 100
for: 5m
labels:
severity: warning
annotations:
summary: "High request rate on {{ $labels.instance }}"
- 可视化: 推荐使用Grafana连接到Prometheus数据源,创建监控仪表板。
注意:生产环境应考虑添加认证中间件保护/metrics端点,防止敏感指标信息暴露。