Свежая установка Sentry на Next.js-приложение генерирует около 400 событий в день на сайте с 2K ежедневных посетителей. 390 из них — шум: гидрационные несовпадения, ошибки браузерных расширений, ResizeObserver-циклы и 404 от prefetch. 10 полезных тонут в потоке.
Я настраивал конфиги Sentry на 6 клиентских проектах. Вот сетап, который я копирую в каждый новый билд.
Шаг 1: Фильтруем шум на входе
Sentry берёт деньги за объём событий. Важнее: шум приучает мозг игнорировать алерты. Убиваем мусор до того, как он попадёт на дашборд.
// sentry.client.config.ts
import * as Sentry from '@sentry/nextjs'
Sentry.init({
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
tracesSampleRate: 0.1, // 10% транзакций — достаточно для перф-данных
replaysSessionSampleRate: 0,
replaysOnErrorSampleRate: 0.5, // реплей 50% ошибок
beforeSend(event) {
const message = event.exception?.values?.[0]?.value ?? ''
// Гидрационные несовпадения — проблема React, не твоя
if (message.includes('Hydration failed')) return null
if (message.includes('Text content does not match')) return null
// Браузерные расширения инжектят ошибки
if (message.includes('chrome-extension://')) return null
if (message.includes('moz-extension://')) return null
// ResizeObserver — безвредный, стреляет в каждом браузере
if (message.includes('ResizeObserver loop')) return null
// Сетевые ошибки от prefetch/preload — пользователь ушёл со страницы
if (
message.includes('Failed to fetch') &&
event.request?.url?.includes('_next/data')
) {
return null
}
return event
},
ignoreErrors: [
// Типичный браузерный шум
'AbortError',
'Network request failed',
'Load failed',
'cancelled',
// Боты и краулеры
'Non-Error promise rejection captured',
],
denyUrls: [
// Браузерные расширения
/extensions\//i,
/^chrome:\/\//i,
/^moz-extension:\/\//i,
// Google Translate инжектит сломанные скрипты
/translate\.googleapis\.com/,
],
})
Одно это снижает объём событий на ~85% на типичном Next.js-сайте.
Шаг 2: Серверная фильтрация
Серверный конфиг чище — нет шума от расширений. Но мусор всё равно есть:
// sentry.server.config.ts
import * as Sentry from '@sentry/nextjs'
Sentry.init({
dsn: process.env.SENTRY_DSN,
tracesSampleRate: 0.2,
beforeSend(event) {
const message = event.exception?.values?.[0]?.value ?? ''
// Next.js бросает NOT_FOUND как ошибку — это не ошибка
if (message.includes('NEXT_NOT_FOUND')) return null
// Next.js redirect() бросает — by design
if (message.includes('NEXT_REDIRECT')) return null
return event
},
})
NEXT_NOT_FOUND и NEXT_REDIRECT — это Next.js, использующий исключения для управления потоком. Это не баги в твоём коде. Фильтрация убирает ~30% серверных событий.
Шаг 3: Кастомные fingerprint-ы для полезной группировки
По умолчанию Sentry группирует ошибки по стэктрейсу. Один и тот же баг создаёт разные issues, если происходит в разных пользовательских флоу. Чиним кастомными fingerprint-ами:
// sentry.client.config.ts — добавляем в beforeSend
beforeSend(event) {
// ... фильтры шума выше ...
// Группируем API-ошибки по эндпоинту, не по стэктрейсу
const frames = event.exception?.values?.[0]?.stacktrace?.frames;
if (frames?.some(f => f.filename?.includes('/api/'))) {
const url = event.request?.url ?? 'unknown';
const path = new URL(url).pathname;
event.fingerprint = ['api-error', path];
}
// Группируем ошибки валидации формы вместе
if (event.tags?.component === 'ContactForm') {
event.fingerprint = ['form-error', 'contact'];
}
return event;
}
Кастомные fingerprint-ы сократили количество issues на ~40% — один и тот же баг группируется корректно, а не расщепляется на 12 issues.
Шаг 4: Осмысленный контекст на каждой ошибке
Разница между полезной ошибкой и бесполезной — контекст. Добавляем глобально:
// В корневом layout или обёртке приложения
Sentry.setContext('app', {
locale: currentLocale,
route: pathname,
deployment: process.env.VERCEL_GIT_COMMIT_SHA?.slice(0, 7),
})
// Для авторизованных зон
Sentry.setUser({
id: user.id,
// Никогда не отправляй PII — ни email, ни имя
})
Когда ошибка срабатывает, я сразу вижу: какая локаль, какой роут, какой деплой и какой пользователь (по ID, не по имени). Этого обычно достаточно, чтобы воспроизвести за 2 минуты вместо 20.
Шаг 5: Алерты, которые будят по делу
Дефолтные алерты Sentry стреляют на каждый новый issue. После деплоя получаешь 15 алертов на мелкие регрессии. Соотношение сигнал/шум обваливается.
Мои правила алертов:
Алерт 1: Обнаружение всплесков — срабатывает, когда количество ошибок превышает 5× скользящее среднее за любое 15-минутное окно. Это ловит реальные аутейджи, а не единичные ошибки.
Алерт 2: Новый issue в платежах — любая новая ошибка в файлах, совпадающих с */api/payment* или */stripe*. Платежи — единственная область, где одна ошибка имеет значение.
Алерт 3: Процент необработанных rejection — срабатывает, когда unhandled rejection превышают 1% сессий в часовом окне. Это ловит каскадные сбои.
Всё остальное идёт в еженедельный дайджест. Просматриваю в понедельник утром — 5 минут на просмотр, триаж всего, что стоит чинить.
Шаг 6: Source maps (то, что все забывают)
Без source maps стэктрейсы Sentry показывают минифицированные имена переменных. Бесполезно. Next.js + Vercel упрощают это, но не автоматически:
// next.config.js
const { withSentryConfig } = require('@sentry/nextjs')
module.exports = withSentryConfig(nextConfig, {
org: 'your-org',
project: 'your-project',
silent: true,
hideSourceMaps: true, // Не экспозим в браузерных devtools
widenClientFileUpload: true, // Загружаем все клиентские чанки
})
hideSourceMaps: true критичен — загружает source maps в Sentry при билде, но не раздаёт их публично. Пользователи не могут реверс-инжинирить твой код, но Sentry показывает чистые стэктрейсы.
Результат
До настройки: ~400 событий/день, 3 алерта/день, 95% шума. Я перестал проверять Sentry.
После настройки: ~40 событий/день, ~2 алерта/неделю, каждый actionable. Я снова проверяю Sentry.
Конфиг занял 2 часа на настройку — клиент + сервер + алерты. Копирую в каждый проект с тех пор. ROI не в том, чтобы ловить больше ошибок — а в том, чтобы ловить меньше, но нужных.
Хочешь, чтобы твой Sentry сообщал о том, что стоит знать, а не кричал впустую? Напиши — я настраиваю это для каждого клиентского проекта и могу проаудировать твой текущий конфиг за одну сессию.