NestJS-otel指标监控实战:7步掌握自定义Metric与Prometheus集成

NestJS-otel指标监控实战:7步掌握自定义Metric与Prometheus集成
NestJS-otel指标监控实战7步掌握自定义Metric与Prometheus集成【免费下载链接】nestjs-otelOpenTelemetry (Tracing Metrics) module for Nest framework (node.js) 项目地址: https://gitcode.com/gh_mirrors/ne/nestjs-otel在微服务架构中监控系统的健康状态至关重要。nestjs-otel作为NestJS的OpenTelemetry模块为开发者提供了强大的指标监控能力让您能够轻松收集应用指标并与Prometheus无缝集成。本文将带您深入了解nestjs-otel的指标监控功能掌握自定义Metric的创建与Prometheus集成的完整实战方案。 为什么选择nestjs-otel进行指标监控nestjs-otel是一个专为NestJS框架设计的OpenTelemetry模块它简化了在Node.js应用中实现可观测性的复杂度。通过nestjs-otel您可以一站式解决方案集成追踪、指标和宽事件功能标准化输出遵循OpenTelemetry标准兼容多种后端系统低侵入性通过装饰器和服务注入不影响业务逻辑Prometheus原生支持内置Prometheus导出器轻松对接监控系统 核心指标类型详解nestjs-otel支持OpenTelemetry API定义的所有核心指标类型每种类型都有特定的应用场景1. 计数器Counter计数器是只能递增的指标适用于统计请求次数、成功/失败操作数量等场景。例如您可以使用计数器来监控API调用次数// 在服务类中定义计数器 private requestCounter this.metricService.getCounter(api_requests_total, { description: Total number of API requests });2. 直方图Histogram直方图用于记录数值分布特别适合测量响应时间、请求大小等连续值。它会自动计算平均值、百分位数等统计信息// 监控响应时间分布 private responseTimeHistogram this.metricService.getHistogram(api_response_time_ms, { description: API response time distribution, unit: milliseconds });3. 仪表Gauge仪表表示可以上下浮动的当前值适用于监控内存使用量、连接数等瞬时状态// 监控活跃用户数 private activeUsersGauge this.metricService.getGauge(active_users, { description: Number of currently active users });4. 可观测计数器ObservableCounter可观测计数器允许您通过回调函数提供指标值适合监控系统级别的指标// 监控系统内存使用 this.metricService.getObservableCounter(system_memory_usage, { description: System memory usage in bytes }); 实战自定义业务指标监控让我们通过一个电商系统的实际案例看看如何实现完整的业务指标监控步骤1初始化MetricService首先在您的服务类中注入MetricServiceimport { Injectable } from nestjs/common; import { MetricService } from nestjs-otel; import { Counter, Histogram, Gauge } from opentelemetry/api; Injectable() export class OrderService { private orderCounter: Counter; private orderValueHistogram: Histogram; private processingOrdersGauge: Gauge; constructor(private readonly metricService: MetricService) { // 初始化订单计数器 this.orderCounter this.metricService.getCounter(orders_total, { description: Total number of orders processed }); // 初始化订单金额直方图 this.orderValueHistogram this.metricService.getHistogram(order_value_usd, { description: Distribution of order values in USD, unit: usd }); // 初始化处理中订单仪表 this.processingOrdersGauge this.metricService.getGauge(orders_processing, { description: Number of orders currently being processed }); } }步骤2在业务逻辑中记录指标在业务方法中根据操作结果记录相应的指标async processOrder(orderData: OrderData): PromiseOrder { // 开始处理时增加处理中订单数 this.processingOrdersGauge.add(1); try { // 记录订单金额分布 this.orderValueHistogram.record(orderData.amount); // 处理订单业务逻辑 const order await this.createOrder(orderData); // 订单处理成功增加总订单数 this.orderCounter.add(1); return order; } catch (error) { // 记录失败订单指标 this.metricService.getCounter(orders_failed_total).add(1); throw error; } finally { // 订单处理完成减少处理中订单数 this.processingOrdersGauge.add(-1); } }步骤3使用装饰器简化指标记录nestjs-otel提供了便捷的装饰器来进一步简化指标记录import { Controller, Get } from nestjs/common; import { OtelCounter, OtelHistogram } from nestjs-otel; import { Counter, Histogram } from opentelemetry/api; Controller(products) export class ProductsController { Get() OtelCounter(products_viewed_total, { description: Total product page views }) getProducts( OtelHistogram(products_load_time_ms) loadTimeHistogram: Histogram ) { const startTime Date.now(); // 业务逻辑... // 记录页面加载时间 const loadTime Date.now() - startTime; loadTimeHistogram.record(loadTime); return products; } } 与Prometheus集成配置Prometheus导出器设置要在nestjs-otel中启用Prometheus指标导出需要在OpenTelemetry SDK配置中添加PrometheusExporter// tracing.ts - OpenTelemetry SDK配置 import { PrometheusExporter } from opentelemetry/exporter-prometheus; import { NodeSDK } from opentelemetry/sdk-node; const otelSDK new NodeSDK({ metricReader: new PrometheusExporter({ port: 8081, // Prometheus指标暴露端口 }), // 其他配置... }); export default otelSDK;应用启动配置确保在NestJS应用启动前初始化OpenTelemetry SDK// main.ts import otelSDK from ./tracing; async function bootstrap() { // 必须先启动OpenTelemetry SDK await otelSDK.start(); const app await NestFactory.create(AppModule); await app.listen(3000); }Prometheus抓取配置在Prometheus的配置文件中添加抓取目标# prometheus.yml scrape_configs: - job_name: nestjs-app static_configs: - targets: [localhost:8081] scrape_interval: 15s 高级监控场景实践场景1监控API性能指标Injectable() export class ApiMetricsService { private requestDuration: Histogram; private requestSize: Histogram; private errorCounter: Counter; constructor(private metricService: MetricService) { this.requestDuration metricService.getHistogram(http_request_duration_seconds, { description: HTTP request duration in seconds, buckets: [0.1, 0.5, 1, 2, 5] // 自定义分桶 }); this.requestSize metricService.getHistogram(http_request_size_bytes, { description: HTTP request size in bytes }); this.errorCounter metricService.getCounter(http_errors_total, { description: Total HTTP errors by status code }); } recordRequest(duration: number, size: number, statusCode: number) { this.requestDuration.record(duration); this.requestSize.record(size); if (statusCode 400) { this.errorCounter.add(1, { status_code: statusCode.toString() }); } } }场景2数据库连接池监控Injectable() export class DatabaseMetricsService { private connectionPoolSize: Gauge; private activeConnections: Gauge; private queryDuration: Histogram; constructor(private metricService: MetricService) { this.connectionPoolSize metricService.getGauge(db_connection_pool_size); this.activeConnections metricService.getGauge(db_active_connections); this.queryDuration metricService.getHistogram(db_query_duration_ms); } async monitorQueryT(queryFn: () PromiseT): PromiseT { this.activeConnections.add(1); const startTime Date.now(); try { const result await queryFn(); const duration Date.now() - startTime; this.queryDuration.record(duration); return result; } finally { this.activeConnections.add(-1); } } }场景3自定义业务健康检查指标Injectable() export class HealthMetricsService { private serviceHealth: Gauge; private dependencyHealth: Gauge; constructor(private metricService: MetricService) { this.serviceHealth metricService.getGauge(service_health_score, { description: Overall service health score (0-100) }); this.dependencyHealth metricService.getGauge(dependency_health, { description: Dependency health status, unit: 1 // 1健康, 0不健康 }); } Cron(*/30 * * * * *) // 每30秒执行一次 async updateHealthMetrics() { // 检查数据库连接 const dbHealth await this.checkDatabase(); this.dependencyHealth.set(dbHealth ? 1 : 0, { dependency: database }); // 检查外部API const apiHealth await this.checkExternalApi(); this.dependencyHealth.set(apiHealth ? 1 : 0, { dependency: external_api }); // 计算总体健康分数 const overallHealth this.calculateOverallHealth(dbHealth, apiHealth); this.serviceHealth.set(overallHealth); } } 可视化与告警配置Grafana仪表板配置将Prometheus作为数据源添加到Grafana后可以创建丰富的监控仪表板API性能仪表板展示请求率、错误率、响应时间百分位数业务指标仪表板显示订单量、用户活跃度、转化率等业务指标系统资源仪表板监控CPU、内存、磁盘使用情况Prometheus告警规则在Prometheus中配置告警规则及时发现系统异常# alert.rules.yml groups: - name: nestjs_alerts rules: - alert: HighErrorRate expr: rate(http_errors_total[5m]) 0.05 for: 2m labels: severity: warning annotations: summary: High error rate detected description: Error rate is {{ $value }} per second - alert: SlowResponseTime expr: histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m])) 2 for: 5m labels: severity: critical annotations: summary: Slow response time detected description: 95th percentile response time is {{ $value }} seconds 调试与问题排查常见问题及解决方案指标未显示在Prometheus中检查PrometheusExporter端口是否正确暴露验证Prometheus配置中的目标地址确认OpenTelemetry SDK已正确启动指标值异常检查指标名称是否重复定义验证指标类型是否与使用方式匹配确认指标标签的正确性性能影响使用异步方式记录指标避免阻塞主线程合理设置指标采样率定期清理不再使用的指标调试技巧// 启用调试日志 import { diag, DiagConsoleLogger, DiagLogLevel } from opentelemetry/api; diag.setLogger(new DiagConsoleLogger(), DiagLogLevel.DEBUG); 最佳实践总结命名规范使用_total后缀表示计数器使用描述性名称标签使用合理使用标签进行维度划分但避免标签基数爆炸指标设计优先使用直方图记录延迟计数器记录事件资源管理及时清理不再使用的指标实例测试验证为关键业务指标编写测试用例 下一步行动建议逐步实施从核心业务指标开始逐步扩展到全系统监控团队培训确保团队成员理解指标的含义和使用方式监控告警建立完整的监控-告警-响应闭环持续优化定期审查指标设计优化监控体系通过nestjs-otel的指标监控功能您可以为NestJS应用构建一个强大、灵活且标准化的监控系统。无论是业务指标还是系统指标都能通过统一的接口进行收集和导出大大简化了微服务架构下的监控复杂度。记住好的监控系统不仅能够帮助您发现问题更能帮助您预防问题。从今天开始为您的NestJS应用构建专业的指标监控体系吧 ✨【免费下载链接】nestjs-otelOpenTelemetry (Tracing Metrics) module for Nest framework (node.js) 项目地址: https://gitcode.com/gh_mirrors/ne/nestjs-otel创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考