Мониторинг TypeScript приложений: от метрик до умных алертов
В современной разработке написать код — лишь половина дела. Критически важно понимать, как приложение ведёт себя в production. Для TypeScript-проектов, будь то сервер на Node.js или клиент на React, проактивный мониторинг становится обязательным требованием. В этой статье мы разберём продвинутые техники сбора метрик, настройки алертов и построения системы observability, которая позволит вам спать спокойно.
1. Ключевые метрики для TypeScript-приложений
Прежде чем настраивать алерты, нужно определить, что именно мы измеряем. Разделим метрики на три группы: инфраструктурные, бизнесовые и пользовательские.
Инфраструктурные метрики (RED-методология):
- Rate — количество запросов в секунду (RPS).
- Errors — процент ошибок (5xx, 4xx, unhandled rejections).
- Duration — время ответа (p50, p95, p99).
Бизнесовые метрики:
- Количество успешных транзакций.
- Время выполнения критических операций (например, генерация отчёта).
- Активные пользователи (DAU/MAU).
Пользовательские метрики (для клиентских приложений):
- LCP (Largest Contentful Paint) — скорость загрузки основного контента.
- FID (First Input Delay) — задержка первого взаимодействия.
- CLS (Cumulative Layout Shift) — стабильность визуального макета.
Для сбора этих метрик в TypeScript мы будем использовать библиотеку prom-client (для Node.js) и @opentelemetry/instrumentation-http.
2. Сбор метрик с помощью Prometheus и OpenTelemetry
Рассмотрим пример настройки метрик для Express-приложения на TypeScript. Установим необходимые пакеты:
npm install prom-client @opentelemetry/api @opentelemetry/sdk-node @opentelemetry/instrumentation-http @opentelemetry/instrumentation-express
Создадим файл metrics.ts для регистрации метрик:
import client from 'prom-client';
const collectDefaultMetrics = client.collectDefaultMetrics;
collectDefaultMetrics({ timeout: 5000 });
export const httpRequestDuration = new client.Histogram({
name: 'http_request_duration_seconds',
help: 'Duration of HTTP requests in seconds',
labelNames: ['method', 'route', 'status_code'],
buckets: [0.01, 0.05, 0.1, 0.5, 1, 2, 5],
});
export const errorCounter = new client.Counter({
name: 'http_errors_total',
help: 'Total number of HTTP errors',
labelNames: ['method', 'route', 'status_code'],
});
Теперь интегрируем метрики в middleware:
import { Request, Response, NextFunction } from 'express';
export function metricsMiddleware(req: Request, res: Response, next: NextFunction) {
const end = httpRequestDuration.startTimer();
res.on('finish', () => {
end({ method: req.method, route: req.route?.path || 'unknown', status_code: res.statusCode.toString() });
if (res.statusCode >= 500) {
errorCounter.inc({ method: req.method, route: req.route?.path || 'unknown', status_code: res.statusCode.toString() });
}
});
next();
}
Добавим эндпоинт для сбора метрик Prometheus:
import { Router } from 'express';
import client from 'prom-client';
const router = Router();
router.get('/metrics', async (req, res) => {
res.set('Content-Type', client.register.contentType);
res.end(await client.register.metrics());
});
export default router;
Для клиентских приложений (React) используем @opentelemetry/instrumentation-document-load для автоматического сбора Web Vitals.
3. Настройка продвинутых алертов
Алерты должны быть умными, чтобы не генерировать шум. Рассмотрим типовые сценарии.
Правило 1: Алерт на высокую латентность (p99 > 1 секунды в течение 5 минут):
- alert: HighLatencyP99
expr: histogram_quantile(0.99, sum(rate(http_request_duration_seconds_bucket[5m])) by (le)) > 1
for: 5m
labels:
severity: critical
annotations:
summary: "P99 latency is above 1s for 5 minutes"
Правило 2: Алерт на резкий рост ошибок (5xx errors rate > 1% от общего трафика):
- alert: HighErrorRate
expr: (sum(rate(http_errors_total{status_code=~"5.."}[5m])) / sum(rate(http_request_duration_seconds_count[5m]))) > 0.01
for: 2m
labels:
severity: warning
annotations:
summary: "Error rate is above 1%"
Правило 3: Алерт на отсутствие данных (dead man's switch):
- alert: NoMetrics
expr: absent(up{job="typescript-app"}) == 1
for: 1m
labels:
severity: critical
annotations:
summary: "No metrics received from TypeScript app"
Для бизнесовых алертов используйте синтетические мониторинги (например, проверка, что количество заказов в минуту не упало ниже порога).
4. Интеграция с Sentry и Grafana
Prometheus отлично хранит метрики, но для трейсинга и логов нужны другие инструменты. Sentry — идеальный выбор для отслеживания ошибок в TypeScript.
Подключение Sentry к Express:
import * as Sentry from '@sentry/node';
import { ProfilingIntegration } from '@sentry/profiling-node';
Sentry.init({
dsn: process.env.SENTRY_DSN,
integrations: [new ProfilingIntegration()],
tracesSampleRate: 1.0,
profilesSampleRate: 1.0,
});
app.use(Sentry.Handlers.requestHandler());
app.use(Sentry.Handlers.tracingHandler());
Grafana служит единой панелью для визуализации. Создайте дашборд с ключевыми панелями:
- График RPS по маршрутам (rate).
- Тепловая кар