Пошук уроків, статей та іншого контенту
Інтегруєте систему збору винятків і налаштуєте сповіщення про помилки в production.
У production помилка може виникнути лише для окремого запиту, користувача або набору даних. Логів сервера часто недостатньо, щоб швидко зрозуміти:
який виняток виник;
у якому endpoint це сталося;
як часто проблема повторюється;
які користувачі або середовища зачеплені;
коли помилка з’явилася вперше.
Система моніторингу помилок збирає винятки, групує однакові проблеми та надсилає сповіщення команді. У цьому уроці використаємо Sentry як приклад зовнішнього сервісу.
Загальна схема виглядає так:
застосунок NestJS перехоплює необроблений виняток;
виняток передається до Sentry;
NestJS формує звичайну HTTP-відповідь для клієнта;
Sentry групує подію з іншими подібними помилками;
налаштоване правило надсилає сповіщення команді.
Створіть проєкт у Sentry та виберіть платформу Node.js. Після цього сервіс надасть DSN — адресу, за якою SDK надсилатиме події.
Встановіть SDK у NestJS-застосунок:
npm install @sentry/nodeDSN не варто зберігати безпосередньо у вихідному коді. Додайте його до змінних середовища:
NODE_ENV=production
SENTRY_DSN=https://examplePublicKey@o0.ingest.sentry.io/0
APP_VERSION=2026.09.01Значення DSN у прикладі умовне. Для реального застосунку використовуйте DSN зі свого проєкту.
Sentry потрібно ініціалізувати якомога раніше — до створення NestJS-застосунку. Зазвичай це роблять у main.ts.
import * as Sentry from '@sentry/node';
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { SentryExceptionFilter } from './common/filters/sentry-exception.filter';
async function bootstrap(): Promise<void> {
Sentry.init({
dsn: process.env.SENTRY_DSN,
environment: process.env.NODE_ENV ?? 'development',
release: process.env.APP_VERSION,
});
const app = await NestFactory.create(AppModule);
app.useGlobalFilters(new SentryExceptionFilter());
await app.listen(process.env.PORT ?? 3000);
}
void bootstrap();Основні параметри:
dsn визначає, до якого проєкту надсилати події;
environment розділяє помилки з development, staging і production;
release допомагає визначити версію застосунку, у якій виникла проблема.
Якщо SENTRY_DSN не задано, SDK не зможе надіслати подію. Це зручно для локальної розробки: застосунок продовжить працювати, але події не потраплятимуть до Sentry.
NestJS має глобальний механізм обробки винятків. Створимо власний фільтр, який:
передає несподівані помилки до Sentry;
додає до події HTTP-метод і шлях запиту;
не змінює стандартну відповідь NestJS.
Створіть файл src/common/filters/sentry-exception.filter.ts:
import {
ArgumentsHost,
Catch,
ExceptionFilter,
HttpException,
HttpStatus,
} from '@nestjs/common';
import type { Request } from 'express';
import * as Sentry from '@sentry/node';
@Catch()
export class SentryExceptionFilter implements ExceptionFilter {
catch(exception: unknown, host: ArgumentsHost): void {
const context = host.switchToHttp();
const request = context.getRequest<Request>();
const response = context.getResponse();
const status =
exception instanceof HttpException
? exception.getStatus()
: HttpStatus.INTERNAL_SERVER_ERROR;
// Не надсилаємо до моніторингу очікувані помилки клієнта.
if (status >= HttpStatus.INTERNAL_SERVER_ERROR) {
Sentry.withScope((scope) => {
scope.setTag('http.method', request.method);
scope.setTag('http.status_code', String(status));
scope.setContext('request', {
method: request.method,
url: request.originalUrl,
userAgent: request.get('user-agent'),
});
Sentry.captureException(exception);
});
}
if (exception instanceof HttpException) {
const exceptionResponse = exception.getResponse();
response.status(status).json(
typeof exceptionResponse === 'string'
? { statusCode: status, message: exceptionResponse }
: exceptionResponse,
);
return;
}
response.status(HttpStatus.INTERNAL_SERVER_ERROR).json({
statusCode: HttpStatus.INTERNAL_SERVER_ERROR,
message: 'Internal server error',
});
}
}Декоратор @Catch() без параметрів означає, що фільтр може обробляти будь-який виняток, а не лише HttpException.
Помилки з кодами 4xx часто є очікуваною частиною роботи API:
400 Bad Request — клієнт надіслав неправильні дані;
401 Unauthorized — користувач не автентифікований;
403 Forbidden — недостатньо прав;
404 Not Found — ресурс не знайдено.
Якщо надсилати кожну таку відповідь у систему моніторингу, команда швидко отримає багато шуму. Необроблені помилки сервера з кодами 5xx зазвичай мають вищий пріоритет.
Це правило залежить від конкретного продукту. Наприклад, системні 400 можуть бути важливими для окремого endpoint. У такому разі фільтр можна налаштувати так, щоб надсилати лише вибрані типи помилок.
Сам текст винятку часто недостатній для діагностики. Контекст допомагає відповісти на запитання:
який endpoint викликав помилку;
яким був HTTP-метод;
яка версія застосунку працювала;
у якому середовищі виникла проблема.
У прикладі до Sentry додаються:
http.method як тег;
http.status_code як тег;
метод, URL і User-Agent у контексті request.
Теги можна використовувати для пошуку та фільтрації подій. До контексту варто додавати лише безпечні дані.
Не додавайте до події:
паролі;
токени доступу;
заголовок Authorization;
повні дані платіжних карток;
інші секрети;
зайві персональні дані.
Якщо потрібно ідентифікувати користувача, передавайте мінімально необхідну інформацію, наприклад внутрішній ідентифікатор без пароля чи токена.
Користувач не повинен отримувати stack trace або внутрішні деталі помилки. Для необробленого винятку API має повертати загальне повідомлення:
{
"statusCode": 500,
"message": "Internal server error"
}Деталі помилки при цьому зберігаються у Sentry і доступні команді розробки.
Розділяйте середовища за допомогою environment:
development — локальна розробка;
staging — тестове середовище;
production — реальний трафік.
Це дає змогу не змішувати локальні помилки з production-помилками та створювати сповіщення лише для потрібного середовища.
Збір помилок сам по собі не гарантує, що команда вчасно їх помітить. У Sentry потрібно створити правило сповіщень для проєкту.
Практична базова конфігурація може містити такі умови:
сповіщати, коли з’явилася нова помилка;
сповіщати, коли помилка повторилася певну кількість разів;
сповіщати, коли кількість помилок перевищила поріг;
враховувати лише середовище production.
Як канал сповіщень можна використовувати доступний у вашій команді сервіс, наприклад:
електронну пошту;
Slack;
Microsoft Teams;
інший інтегрований канал.
Для критичних помилок краще налаштувати негайне сповіщення. Для менш важливих проблем зручно використовувати групування або періодичні зведення, щоб не створювати зайвий шум.
Хороше сповіщення повинно допомогти швидко оцінити проблему. Зазвичай у ньому важливі:
назва або тип помилки;
кількість виникнень;
час першої та останньої появи;
середовище;
версія застосунку;
endpoint;
кількість зачеплених користувачів.
Не кожна помилка повинна створювати терміновий виклик. Важливо розділити помилки за пріоритетом і не перетворити моніторинг на постійний потік неважливих повідомлень.
Для перевірки створіть тимчасовий endpoint, який навмисно генерує помилку:
import { Controller, Get } from '@nestjs/common';
@Controller('debug')
export class DebugController {
@Get('error')
throwError(): never {
throw new Error('Тестова помилка моніторингу');
}
}Після запуску застосунку виконайте запит:
curl -i http://localhost:3000/debug/errorОчікуваний результат для клієнта:
{
"statusCode": 500,
"message": "Internal server error"
}У Sentry має з’явитися подія з:
повідомленням Тестова помилка моніторингу;
HTTP-методом GET;
шляхом /debug/error;
статусом 500;
відповідним середовищем.
Після перевірки видаліть або захистіть цей endpoint. Навмисне генерування помилок не повинно залишатися доступним у production.
Після надходження події до Sentry команда зазвичай працює з нею так:
переглядає stack trace;
перевіряє endpoint і контекст запиту;
визначає, у якій версії з’явилася помилка;
оцінює кількість affected users;
виправляє проблему;
публікує нову версію;
перевіряє, що помилка більше не виникає;
позначає проблему як вирішену.
Групування подій важливе: одна й та сама помилка для тисячі запитів має залишатися однією проблемою, а не створювати тисячі окремих сповіщень.
Якщо Sentry ініціалізувати занадто пізно, частина помилок може виникнути до готовності SDK і не буде відправлена.
Ініціалізуйте його до NestFactory.create().
Самого створення класу фільтра недостатньо. Його потрібно зареєструвати:
app.useGlobalFilters(new SentryExceptionFilter());Це може створити багато шуму та приховати справді критичні проблеми. Почніть із необроблених помилок 5xx, а винятки для окремих 4xx додайте за потреби.
Stack trace та текст внутрішнього винятку не повинні повертатися клієнту. Клієнт отримує загальне повідомлення, а розробники переглядають деталі в Sentry.
Не передавайте в контекст повний об’єкт запиту без перевірки. Він може містити токени, cookies або персональні дані.
Без environment помилки з локального запуску, staging і production можуть змішуватися. Завжди передавайте середовище через змінну конфігурації.
Надмірні сповіщення призводять до того, що команда перестає на них реагувати. Використовуйте групування, пороги та різні рівні важливості.
Глобальний exception filter дає змогу централізовано перехоплювати помилки NestJS.
Sentry зберігає винятки, контекст запиту, середовище та версію застосунку.
Ініціалізуйте SDK до створення NestJS-застосунку.
Не змінюйте без потреби стандартну HTTP-відповідь для клієнта.
Для початку надсилайте до моніторингу необроблені помилки 5xx.
Не передавайте в подіях паролі, токени та інші секрети.
Налаштуйте production-сповіщення з порогами, групуванням і правильним рівнем пріоритету.
Перевірте інтеграцію навмисною тестовою помилкою до розгортання.