Что показал Sentry: наблюдаемость, стабильность и цена контроля собственного кода
Ошибки в рабочей среде выявили несоответствие схемы, сбой восстановления транзакции и бесполезные журналы. Как небольшая команда исправила ошибки backend с помощью Sentry, подготовила мониторинг браузера и ограничила шум оповещений.
Раньше инженерные команды либо чрезмерно вкладывались в наблюдаемость — целые отделы SRE настраивали панели, которые никто не читал, — либо вовсе её игнорировали и узнавали о падении сервиса из письма клиента. В 2026 году ни одна крайность неприемлема. Нужно знать, что ломается, не оплачивая при этом корпоративные тарифы для небольшого независимого продукта.
В этом разборе показано, как наша интеграция с Sentry обнаружила ошибки в рабочей среде, что мы исправили и как настроили мониторинг, чтобы контролировать шум и расход квоты. Также рассмотрим, как развиваются инструменты наблюдаемости для небольших инженерных команд.
Почему оповещения не показывали ошибки браузера
С марта наш backend был подключён к Sentry. DSN хранится в Google Secret Manager, секрет монтируется в Cloud Run, а sentry_sdk.init запускается при каждом старте. Оповещения по электронной почте приходили. Со стороны всё выглядело исправным.
Но внутри картина была другой. Frontend вообще не был подключён к Sentry. Исключения в браузере, ошибки гидратации и сбои загрузки частей приложения оставались невидимыми. А backend отправлял ошибки Python в проект с названием javascript-nextjs, потому что это был единственный проект в организации. Трассировки стеков копились не там, группировка была бесполезной, а панель превратилась в поток событий на разных языках.
Прежде чем разбираться с отдельными ошибками, нужно было разделить сбои браузера и ошибки backend.
Что показали данные
Мы выгрузили события ошибок за последние девяносто дней. Выделилось несколько закономерностей.
Исторический инцидент, который сам себя исправил
Самой частой ошибкой за этот период была ошибка Postgres StringDataRightTruncation — шестнадцать событий за двадцать две секунды — на endpoint регистрации через социальную сеть. Причина была типичной для расхождения схем: модель допускала биографию длиной 800 символов, а столбец рабочей базы всё ещё имел тип VARCHAR(500) после предыдущей миграции. Пользователь отправил биографию чуть длиннее 500 символов, слой Pydantic её принял, а операция INSERT завершилась ошибкой.
Миграцию, расширяющую столбец до 800 символов, уже подготовили и выполнили на следующее утро. Но основная проблема — модель и схема базы могут расходиться незаметно, пока это не обнаружит пользователь, — оставалась.
Мы сделали две вещи. Во-первых, ужесточили схему запроса регистрации через социальную сеть: задали явный max_length для электронной почты, отображаемого имени и токена, чтобы патологические значения возвращали 422, не доходя до базы. Во-вторых, расширили скрипт проверки целостности БД: он сравнивает information_schema.columns.character_maximum_length с длинами, которых ожидает приложение. Теперь, если будущая миграция укоротит столбец, следующий выпуск не пройдёт проверку целостности.
Сеанс, который не удавалось откатить
Ниже в списке шла цепочка: одна ошибка OperationalError: server closed the connection unexpectedly на POST /v1/upload, за которой последовал поток PendingRollbackError из того же участка кода. Postgres разорвал соединение во время запроса, сеанс SQLAlchemy оказался в недопустимом состоянии, а служба загрузки попыталась сохранить частичный результат поверх него. Все последующие операции в этом сеансе тоже завершались ошибкой.
Исправление небольшое, но его легко реализовать неправильно. Когда конвейер загрузки перехватывает исключение, первым делом он теперь вызывает db.rollback() — в отдельном try/except, чтобы неудачный откат не скрыл исходную ошибку. После этого логика частичного сохранения работает с чистым сеансом.
Журналы, которые стирали сами себя
Обработчик завершения WebSocket записывал пойманное исключение через err=%s. Для большинства исключений это выдаёт полезное описание. Но у некоторых типов исключений метод __str__ возвращает пустую строку, и в журнал попадало err= без пояснений. События Sentry сообщали о неудачном сохранении, но не объясняли почему.
Переход на logger.exception(...) и err=%r ничего не стоил и сделал каждое будущее событие самодостаточным.
За шум тоже не хотелось платить
Остальные элементы очереди не были ошибками продукта. Uvloop иногда выдаёт RuntimeError: unable to perform operation on <TCPTransport closed=True>, когда клиент отключается во время SSL. Это нормальное поведение, которое нельзя исправить; при квоте бесплатного тарифа 5 000 ошибок в месяц оно лишь расходует бюджет. Мы добавили фильтр before_send, отбрасывающий события с такими конкретными шаблонами исключений и значений. Аналогично на frontend мы отфильтровали ResizeObserver loop limit exceeded и похожий браузерный шум.
Как настроить бесплатный тариф
По состоянию на 13 октября 2026 года бесплатный план Sentry Developer включает 5 000 ошибок, 5 миллионов трассировочных span-ов и 50 воспроизведений в месяц. Трассировка измеряется в span-ах, а не в прежних единицах производительности. Перед выбором частоты семплирования проверьте текущие лимиты плана: лимит ошибок не является бюджетом на все сигналы, которые может отправлять SDK.
Наши настройки:
tracesSampleRate: 0на backend и frontend. Распределённая трассировка действительно полезна, но при 10 тыс. единиц производительности в месяц одна неудачная половина дня может исчерпать квоту. При необходимости её можно включить с низкой частотой выборки для конкретного расследования.profilesSampleRate: 0на backend. По той же причине.- Session Replay отключён на frontend. Код интеграции оставлен, но обе частоты выборки равны нулю. Если для диагностики критической ошибки понадобится запись сессии, можно на день установить
replaysOnErrorSampleRateв0.05, а затем снова отключить. - Фильтры
before_sendв обеих средах отбрасывают события, которые заведомо не требуют действий.
Изменения backend снизили шум от значимых ошибок, а конфигурация браузерного SDK была подготовлена к активации. Это разные этапы: наличие кода и настроек выборки само по себе не доказывает, что события браузера поступают в нужный проект.
Что меняется на рынке наблюдаемости
Мы настроились на бесплатный тариф, потому что он для размещённого сервиса необычно щедрый. Но полезно видеть более широкую картину: экономика мониторинга меняется.
За последние двенадцать-восемнадцать месяцев произошли несколько сдвигов:
- Открытые стандарты уменьшают объём миграции, но не устраняют его. Инструментирование с поддержкой OTLP снижает зависимость от backend мониторинга. Запросы конкретного поставщика, панели, правила оповещений и функции SDK всё равно нужно планировать и тестировать при переходе.
- Самостоятельное размещение меняет расчёт стоимости. Варианты вроде GlitchTip и стеков на основе OTLP дают другой путь мониторинга. Сравнивайте хранение, резервное копирование, обновления и инженерное время с размещённым тарифом, а не только стоимость виртуальной машины с ценой подписки.
- Отладка с помощью ИИ расширяет рабочий процесс. Seer от Sentry предлагает первопричины и исправления, а авторизованная интеграция MCP может передать контекст ошибок помощнику для разработки. Перед выпуском предложенное исправление всё равно нужно воспроизвести и проверить регрессионными тестами.
- За лимитами тарифа нужно следить так же внимательно, как за функциями. Объём ошибок, срок хранения, выборка и доступ команды влияют на счёт. Начните с необходимых сигналов и измеренного бюджета событий, затем сравните тарифы с этой нагрузкой.
На момент снимка этого выпуска Sentry покрывал наши текущие потребности в мониторинге ошибок. Открытые интерфейсы оставляют команде больше возможностей на будущее, но смена поставщика всё равно потребует проверить маршрутизацию проектов, оповещения, сохранённые данные и функции конкретного провайдера.
Проверки развёртывания завершают настройку мониторинга
На дату этого снимка, 17 мая 2026 года, оставались две задачи развёртывания:
- Создать отдельный проект Sentry для Python, чтобы ошибки backend перестали попадать в
javascript-nextjs. DSN заменяется в той же записи Secret Manager, которую уже читает backend. - Добавить DSN frontend в настройки проекта Vercel, чтобы начали поступать клиентские ошибки. Код уже есть и запускается при наличии настройки; не хватает только переменной среды.
При любом запуске мониторинга отправьте контролируемое тестовое событие из каждой среды и проверьте проект, окружение, группировку и контекст, прежде чем считать интеграцию завершённой. Отдельные проекты и переменная среды — это шаги настройки, а не доказательство доставки событий.
Почему это важно
Когда не видно, что ломается, приходится либо чрезмерно вкладываться в защитный код, либо недостаточно проверять продукт и выпускать ошибки. Оба подхода дороги. Доступная и надёжная наблюдаемость помогает небольшой команде работать как более крупной: замечать регрессии до жалоб клиентов, исправлять их без догадок и тратить инженерные часы на новые функции.
Главный урок — проверять обе стороны: исправления в приложении и путь мониторинга, который должен обнаружить следующую регрессию.