Урок 07

Мониторинг и логирование

В продакшене нужно знать, что происходит.

Sentry

Стандарт для отслеживания ошибок.

npm install @sentry/nextjs
npx @sentry/wizard@latest -i nextjs

Автоматически создаёт конфиги:

  • sentry.client.config.ts
  • sentry.server.config.ts
  • sentry.edge.config.ts

Использование:

import * as Sentry from '@sentry/nextjs';

Sentry.captureException(new Error('Something broke'));

Sentry.setUser({ id: user.id, email: user.email });

Sentry.addBreadcrumb({
    category: 'auth',
    message: 'User logged in',
});

В error.tsx:

'use client';

import { useEffect } from 'react';
import * as Sentry from '@sentry/nextjs';

export default function Error({ error, reset }) {
    useEffect(() => {
        Sentry.captureException(error);
    }, [error]);

    return (
        <div>
            <h2>Что-то пошло не так</h2>
            <button onClick={reset}>Попробовать снова</button>
        </div>
    );
}

Логирование

Структурированные логи

console.log(JSON.stringify({
    level: 'info',
    message: 'User created',
    userId: user.id,
    timestamp: new Date().toISOString(),
}));

Парсеры лучше работают с JSON.

Библиотека Pino

npm install pino
import pino from 'pino';

export const logger = pino({
    level: process.env.LOG_LEVEL ?? 'info',
});

logger.info({ userId: user.id }, 'User created');
logger.error({ err: error }, 'Failed to create user');

Vercel Analytics

npm install @vercel/analytics
// app/layout.tsx
import { Analytics } from '@vercel/analytics/react';
import { SpeedInsights } from '@vercel/speed-insights/next';

export default function RootLayout({ children }) {
    return (
        <html>
            <body>
                {children}
                <Analytics />
                <SpeedInsights />
            </body>
        </html>
    );
}

Показывает:

  • Посещаемость
  • Core Web Vitals
  • Медленные страницы

Health check

// app/api/health/route.ts
export async function GET() {
    try {
        await db.$queryRaw`SELECT 1`;
        return Response.json({ status: 'ok', timestamp: Date.now() });
    } catch (error) {
        return Response.json({ status: 'error' }, { status: 503 });
    }
}

Uptime-сервисы проверяют этот эндпоинт.

Uptime мониторинг

  • UptimeRobot — бесплатно, проверяет каждые 5 минут
  • Better Stack — статус-страница
  • Pingdom
  • Checkly

Настрой проверку /api/health и уведомления.

Метрики

Web Vitals

'use client';

import { useReportWebVitals } from 'next/web-vitals';

export function WebVitals() {
    useReportWebVitals((metric) => {
        console.log(metric);
        // отправить в аналитику
    });

    return null;
}

Кастомные метрики

import { trace } from '@opentelemetry/api';

const tracer = trace.getTracer('my-app');

await tracer.startActiveSpan('db.query', async (span) => {
    const result = await db.user.findMany();
    span.end();
    return result;
});

Алерты

Настрой уведомления:

  • Sentry — при новых ошибках
  • UptimeRobot — при падении
  • Vercel — при неудачном деплое
  • Slack/Telegram — общий канал

Дашборды

  • Grafana — метрики из Prometheus
  • Vercel Dashboard — базовые
  • Sentry — ошибки
  • Axiom/Datadog — логи

Что логировать

  • Ошибки — всегда
  • Медленные запросы — > 1 сек
  • Аутентификация — успешные и неудачные попытки
  • Платежи — все транзакции
  • Изменения данных — кто, что, когда

Что НЕ логировать

  • Пароли
  • Токены
  • Номера карт
  • Персональные данные (если не нужно)

Retention

Не храни логи вечно. Политики:

  • 7 дней — debug
  • 30 дней — info
  • 1 год — ошибки
  • 7 лет — финансовые (по требованиям)

Итоги

  • Sentry для ошибок
  • Структурированные логи
  • Vercel Analytics
  • /api/health для uptime
  • Алерты в Slack/Telegram
  • Не логируй секреты