Профилирование

Профиль — это снимок того, куда уходит процессорное время (CPU) или память (alloc/heap) внутри вашего приложения, собранный по реальным стекам вызовов во время настоящих запросов — не синтетический бенчмарк, а то, что действительно происходило в продакшене. Профили визуализируются как флеймограф: чем шире блок функции, тем больше времени/памяти она заняла относительно всего профиля.

Как отправлять профили

Gotcha принимает профили двумя разными путями.

1. Через обычный SDK (вместе с трейсингом)

Если ваш Sentry SDK поддерживает профилирование, профиль присылается как часть обычного envelope рядом с транзакцией — отдельно ничего подключать не нужно, кроме того же трейсинга, что и для Производительности. Доступность и включение профилирования зависят от конкретного SDK — см. SDK и интеграции и документацию SDK вашего языка.

2. Через прямой pprof-эндпойнт

Для Go-приложений (например, через встроенный net/http/pprof) или любого инструмента continuous profiling, который умеет отдавать стандартный формат Go pprof, есть отдельный эндпойнт приёма:

POST /api/v1/profiles/pprof?service=<имя_сервиса>&type=<sample_type>&environment=<окружение>&transaction=<транзакция>
Authorization: Bearer <публичный ключ DSN>
  • Аутентификация — заголовок Authorization: Bearer <ключ>, где <ключ> — это публичная часть DSN проекта (та же строка, что стоит перед @ в DSN вида https://<public_key>@<адрес>/<id_проекта>). Ключу нужен тип server (или ключ без типа, legacy) — профили не входят в допуск браузерного ключа; ключ не того типа получает 403, см. Ключи приёма.
  • Тело запроса — pprof-профиль (protobuf), обязательно сжатый gzip клиентом. Это конвенция самого pprof-формата (сжатие внутри тела, а не HTTP Content-Encoding), сервер разжимает его сам с ограничением размера.
  • service — произвольное имя сервиса/приложения, под которым профиль сгруппируется в списке.
  • type — имя sample type из pprof-профиля, который нужно записать (например, cpu/samples для CPU-профиля, alloc_space/inuse_space для профиля памяти). Если параметр не указан или такого типа в профиле нет, берётся последний sample type профиля.
  • transaction, environment, trace_id — необязательные метаданные: транзакция и окружение, к которым относится снятие профиля, и trace_id, если профиль нужно привязать к конкретному трейсу (см. ниже).

Пример — снять 10-секундный CPU-профиль стандартным инструментом Go и отправить его в Gotcha:

curl -s "http://localhost:6060/debug/pprof/profile?seconds=10" -o cpu.pprof
gzip -c cpu.pprof | curl -X POST \
  "https://<адрес_gotcha>/api/v1/profiles/pprof?service=my-service&type=cpu&environment=production" \
  -H "Authorization: Bearer <публичный_ключ_DSN>" \
  --data-binary @-

Успешный приём отвечает 202 Accepted. Если профили выключены на инстансе, запись молча пропускается, но ответ всё равно 202. Если квота организации на профили исчерпана, приём отвечает 429.

Переход с /profiles/pprof. Раньше приём pprof-профилей жил в корне, по адресу POST /profiles/pprof. Этот путь продолжает работать и ведёт себя точно так же — та же аутентификация, тот же лимит частоты, та же квота, — но объявлен устаревшим: ответы на нём несут заголовки Deprecation и Link; rel="deprecation", и в 2.0 он будет удалён. Переведите отправителей на /api/v1/profiles/pprof. Если вы держите gotcha сами, счётчик gotcha_ingest_deprecated_path_total{path="/profiles/pprof"} покажет, ходит ли кто-то ещё по старому пути.

Список профилей

Раздел открывается по ссылке «Профили» в подменю «Производительность» — /projects/<id>/profiles. Сверху — общий контрол окна времени (пресеты 1ч / 24ч / 7д / 30д или произвольный диапазон, по умолчанию 24ч). Таблица группирует профили по (сервис, тип, транзакция) и показывает число сэмплов в каждой группе; клик по строке открывает флеймограф этой группы за выбранный период. Сверху есть ссылка на «Регрессии профилей» (см. ниже).

Флеймограф

Флеймограф в Gotcha рисуется как icicle-диаграмма (сверху вниз): корень («all») — верхняя полоса на всю ширину, под ним — его непосредственные вызовы, и так глубже с каждым уровнем стека. Правила чтения:

  • Ширина блока — доля времени/сэмплов этой функции относительно общего числа сэмплов профиля (у корня — 100%).
  • Глубина (номер строки сверху) — глубина вызова: чем ниже блок, тем глубже он в стеке вызовов.
  • Наведение мышью на блок показывает всплывающую подсказку с именем функции и точным процентом.
  • Цвет блока — детерминированный по имени функции (для визуального различения соседних вызовов), он не кодирует «плохо/хорошо» и не отличает ваш код от кода библиотек.
  • Зум по клику. Каждый сегмент — ссылка: клик разворачивает его на всю ширину, и под ним показывается только его поддерево, а предки остаются сверху узкой «лесенкой» пути. Строка «all» (корень) возвращает полный профиль. Зум живёт в адресе страницы (параметр focus= — путь по именам функций от верхнего уровня), поэтому увеличенный вид можно передать ссылкой; если такого пути в профиле за выбранный период уже нет, страница показывает полный профиль. Сегменты доступны с клавиатуры, подсказка о жесте — под диаграммой. Начинать разбор всё равно стоит с самой широкой ветки на любом уровне — это самый тяжёлый путь выполнения.

Связь с транзакциями (профилирование в контексте трейса)

Если профиль был снят с trace_id, привязанным к конкретному трейсу (либо это pprof-профиль с явным параметром trace_id, либо профиль от SDK, отправленный вместе с транзакцией), на странице waterfall этого трейса (/traces/<trace_id>, см. Производительность) появляется ссылка «Смотреть флеймограф» — переход от «какой спан долгий» прямо к «что внутри него исполнялось на уровне функций».

Регрессии профилей

Регрессия профиля — это значимый рост self-доли конкретной функции (доли сэмплов, где именно эта функция находится на вершине стека, то есть её собственное время, без учёта того, что она вызывает) относительно базовой линии. Механизм тот же принцип «порог + гистерезис», что и у регрессий производительности, но считается отдельно, по профилям:

  • Фоновый оценщик проверяет топ функций по self-доле (по умолчанию 20 функций на сервис/тип) за свежее окно (по умолчанию 60 минут) для каждого (сервис, тип профиля) с профилями за это окно.
  • База — медиана дневных self-долей функции за последние 7 дней (по умолчанию).
  • Открытие: доля в свежем окне выросла больше чем на 50% от базы (recent > base × 1.5) и осталась не ниже шумового пола 5% — функции с долей меньше 5% не рассматриваются вовсе, слишком шумно.
  • Закрытие (гистерезис): доля опустилась до базы + 20% или ниже (recent ≤ base × 1.2) — более мягкий порог, чем открытие, чтобы регрессия не мигала на границе.
  • Решение принимается только при достаточном числе сэмплов в окне (по умолчанию 100), иначе оценщик ничего не делает в этот тик.

Список открытых/закрытых регрессий — в разделе «Регрессии профилей» (/projects/<id>/profile-regressions), с вкладками «Открыто / Решено / Все». Таблица: функция, сервис · тип, рост в процентах, диапазон долей «база → пик», статус, когда началась, длительность.