引言:为什么监控对 TypeScript 应用至关重要
TypeScript 是构建可扩展 Web 应用的强大工具,但即使是最优质的代码也无法避免生产环境中的故障。没有监控系统,您将面临从用户而非自动告警中得知问题的风险。在本文中,我们将探讨监控配置的完整流程:从指标收集到通知发送。
我们将讨论可观测性的三大支柱:指标(系统的数值指标)、日志(事件的详细记录)和链路追踪(请求的跟踪)。特别关注与流行工具——Prometheus、Grafana 和 Sentry 的集成。
1. TypeScript 应用的核心指标
在配置告警之前,需要确定哪些指标对您的应用至关重要。我们将它们分为三组:
1.1 业务指标
从用户角度反映应用的健康状况:
- 每秒请求数 (RPS) — 显示服务器负载
- 响应时间 (延迟) — p50、p95、p99 百分位数
- 错误数量 — 4xx 和 5xx 状态码
- 活跃用户 — 会话、WebSocket 连接数
1.2 技术指标
显示基础设施状态:
- CPU 和内存 — 处理器负载和内存泄漏
- 事件循环延迟 — Node.js 事件循环中的延迟
- 垃圾回收 — 垃圾回收的频率和持续时间
- HTTP 连接池 — 打开的连接数
1.3 示例:在 TypeScript 中使用 Prometheus 收集指标
为 Node.js 安装 prom-client 库:
npm install prom-client @types/prom-client创建 metrics.ts 文件:
import client from 'prom-client';import express, { Request, Response } from 'express';
// 创建指标注册表const register = new client.Registry();client.collectDefaultMetrics({ register });
// 自定义指标:HTTP 请求计数const httpRequestCounter = new client.Counter({ name: 'http_requests_total', help: 'Total number of HTTP requests', labelNames: ['method', 'route', 'status_code'], registers: [register],});
// 响应时间直方图const httpRequestDuration = new client.Histogram({ name: 'http_request_duration_seconds', help: 'Duration of HTTP requests in seconds', labelNames: ['method', 'route', 'status_code'], buckets: [0.1, 0.5, 1, 2, 5], registers: [register],});
// 用于收集指标的中间件export function metricsMiddleware(req: Request, res: Response, next: Function) { const end = httpRequestDuration.startTimer(); res.on('finish', () => { const labels = { method: req.method, route: req.route?.path || 'unknown', status_code: res.statusCode.toString(), }; httpRequestCounter.inc(labels); end(labels); }); next();}
// Prometheus 端点export function metricsEndpoint(req: Request, res: Response) { res.set('Content-Type', register.contentType); res.send(register.metrics());}2. 配置告警:从理论到实践
告警应该是智能的——过多的误报会让团队疲惫不堪。我们使用“三西格玛”规则处理异常,并为关键指标设置阈值。
2.1 Prometheus 中的告警规则
创建 alerts.yml 文件:
groups: - name: typescript-app rules: - alert: HighErrorRate expr: | rate(http_requests_total{status_code=~"5.."}[5m]) / rate(http_requests_total[5m]) > 0.05 for: 2m labels: severity: critical annotations: