Skip to content

ТЗ — Отладка/профилирование (cms/debug)

Слой: 🔵 инфра-модуль · Зрелость доноров: ★★ · Донор: — Статус: ТЗ к разработке

Назначение и возможности

Модуль отладки и профилирования для разработчиков и studio-инженеров: журналирование SQL-запросов, детект N+1 в реальном времени, интеграция с инструментами трассировки. Активен только вне production либо по явной studio-роли.

  • Query-log с подсветкой медленных запросов (порог из настроек)
  • Детект N+1 (повторяющиеся запросы в рамках одного запроса/джобы)
  • Интеграция с Laravel Telescope (детальная трассировка)
  • Интеграция с Laravel Pail (стрим логов в реальном времени)
  • Панель профилирования запроса (время, память, число SQL)
  • Дамп контекста джобы при падении в очереди
  • Экспорт снятого профиля для приложения к тикету
  • Жёсткое отключение в production без studio-роли
  • Маскирование чувствительных значений в query-log перед записью (пароли/токены/email)
  • Настраиваемый порог детекта N+1 (число одинаковых запросов подряд)

Зависимости и выключение

requires: ядро (Логирование)

Поведение при выключении: панель профилирования и query-log недоступны, ошибки логируются штатным логом ядра без деталей SQL — деградация, не поломка.

Стоимость внешних API (матрица v2.2): не применимо — Telescope и Pail интеграции локальные (внутри инфраструктуры проекта), модуль не вызывает платных внешних сервисов и не тратит чужую квоту.

Модель данных

Своих таблиц нет — использует хранилище Telescope (telescope_entries) при включённой интеграции, иначе только файловые логи; снимки cms:debug:snapshot — файлы на диске с собственным ретеншном debug.snapshot_retention_days. Отдельного индексирования модуль не вносит — ретеншн Telescope управляется его штатной командой очистки по debug.retention_days. Полный ПДн-паспорт (что может временно попасть в query-log/снимки и как гейтится доступ к ним) — см. «Безопасность».

Входные и выходные данные

Входы

ИсточникДанные/поляЧем валидируется
Query listener ядра (внутренний перехват)SQL, bindings, длительность, контекст запроса/джобыне пользовательский ввод; bindings не логируются, если содержат отмеченные конфигом чувствительные поля
GET /api/v1/admin/debug/profileзаголовок текущего запроса (для профилирования)permission debug.view/studio-роль, гейт по окружению
cms:debug:snapshot (CLI)без пользовательского вводадоступ на уровне сервера
Filament: экспорт снятого профиляsnapshot_idpermission debug.export; snapshot_id — существующий снимок

Выходы

ПотребительДанныеФормат
Filament-панель профилированиявремя, память, число SQL, query-logBlade через сервис модуля
Экспорт для тикетаснятый профиль (запросы, N+1-паттерны, память)файл (JSON/HTML), скачивается администратором
Telescope (если включён)детальная трассировкаtelescope_entries (сторонний пакет)
Laravel Pail (если включён)стрим логов в реальном временистандартный вывод/лог-канал

Настройки (группа debug)

КлючТипДефолтaffectsPageCacheОписание
debug.enabledboolfalseнетГлобальный включатель модуля
debug.slow_query_msint200нетПорог медленного запроса в мс
debug.n1_detectionbooltrueнетВключить детект N+1
debug.telescope_enabledboolfalseнетВключить интеграцию Telescope
debug.allowed_rolesarray["studio"]нетРоли с доступом к панели вне local
debug.retention_daysint3нетХранение записей Telescope
debug.scrub_bindings_enabledbooltrueнетМаскирование чувствительных значений (password, token, email) в query-log перед записью
debug.n1_thresholdint5нетЧисло одинаковых запросов подряд для срабатывания N1PatternDetected
debug.snapshot_retention_daysint14нетХранение файлов cms:debug:snapshot на диске

Лимиты и квоты (матрица v2.2): debug.slow_query_ms и debug.n1_threshold — пороги чувствительности детекта, оба с дефолтом выше; debug.retention_days и debug.snapshot_retention_days — ретеншн накопленных диагностических данных. Превышение порогов не роняет модуль и не режет данные молча — только меняет объём того, что попадает в лог/детект, либо (для ретеншна) удаляется штатной очисткой по расписанию.

Kill-switch (матрица v2.2): debug.enabled и есть аварийный выключатель модуля — перевод в false мгновенно останавливает query-listener и скрывает панель без полного disable пакета через менеджер модулей; отдельный флаг не заводится, это одна из трёх частей гейта из «Безопасность».

API

Отдельного публичного API нет — админ-CRUD через Filament. Панель профилирования — служебный роут /api/v1/admin/debug/profile под studio-ролью.

Компоненты

Виджеты: Filament-виджет «Последние медленные запросы» (с индикатором «нормально/ медленно/критично» по slow_query_ms). Filament: страница профилирования запроса (время, память, число SQL, группировка повторяющихся запросов). Команды: cms:debug:snapshot --json (снять срез логов в файл, готовый к приложению к тикету), cms:debug:clear --json (очистка накопленных логов/снимков), cms:debug:doctor --json (включён/выключен, активность Telescope, согласованность allowed_roles с реальным доступом).

Демо-сидеры (матрица v2.2): не применимо — модуль не работает с контентными данными, галерея блоков и playground его не касаются; диагностическая ценность видна только на реальном трафике или в тестовом сценарии с сознательно медленным/повторяющимся запросом, не на demo-сидере с фиктивными данными.

События и обмен

СобытиеКогдаPayload
SlowQueryDetectedзапрос превысил порогsql, bindings, duration_ms, context
N1PatternDetectedобнаружен повторяющийся паттерн запросовmodel, count, trace

FilterBus и provides-контракты не используются. Слушает: манифест не декларирует зависимостей от событий других модулей — источник данных внутренний (query listener ядра).

Таблица взаимодействий

Сущность/модульКаналНаправлениеЧто происходит
Query listener ядравнутренний перехват (вне пяти каналов, hook на уровне DB-соединения)inИсточник данных для query-log и детекта N+1
Все модули (косвенно, через их SQL-запросы)пассивное наблюдение, не активный обменinМедленные/N+1-запросы любого модуля попадают в лог debug без участия модуля-источника
Telescope (сторонний пакет, если включён)прямая интеграция пакета, не канал CMSoutДетальная трассировка складывается в telescope_entries
Laravel Pail (сторонний пакет, если включён)прямая интеграция пакета, не канал CMSoutСтрим текущего лог-канала в реальном времени

Фоновая работа

Своих очередей и джобов нет: query-listener и детект N+1 работают синхронно в рамках текущего запроса/джобы (лёгкий инструмент, без внешних вызовов). Ретеншн Telescope выполняется штатной командой пакета по расписанию через ScheduleRegistrar ядра.

Метрики и алерты (§15)

Минимальный набор — диагностический инструмент, не источник алертов сам по себе: число SlowQueryDetected за период, число N1PatternDetected за период, оверхед query-listener (среднее время перехвата на SQL-запрос — рост означает, что инструмент сам стал источником замедления). Оба события можно агрегировать в Pulse как сигнал деградации производительности других модулей; отдельного алертинга debug не заводит — решает cms/health, если оба события молчат при заведомо медленном трафике.

Мини-ранбук

СимптомЧто проверитьКоманда
Всплеск SlowQueryDetectedнагрузка БД, не занижен ли debug.slow_query_mscms:debug:snapshot --json — снять срез для анализа
Ложные N1PatternDetected на легитимный батч похожих запросовэвристика детекта не различает похожие-но-разные запросыскорректировать debug.n1_threshold
debug.telescope_enabled=true, но данных в Telescope нетпакет установлен как dev-зависимость?cms:debug:doctor --json
telescope_entries разрослась на stagingприменяется ли debug.retention_dayscms:debug:clear --json
Снимки cms:debug:snapshot копятся на дискеприменяется ли debug.snapshot_retention_dayscms:debug:clear --json

Восстановительные команды (cms:debug:clear, cms:debug:snapshot) идемпотентны и безопасны на живом сайте, без даунтайма.

Бэкап/рестор: модуль не вносит данных, подлежащих обязательному бэкапу — снимки на диске и файловые логи диагностические и одноразовые, их отсутствие после рестора не считается потерей; при включённом Telescope telescope_entries бэкапится/восстанавливается в рамках политики самого пакета Telescope, не этого модуля.

Производительность и кеш

Объёмы: query-log — весь SQL текущего запроса/джобы, живёт только в памяти процесса (не персистится, кроме явного cms:debug:snapshot); при включённом Telescope — telescope_entries растёт пропорционально трафику dev/staging-окружения (там модуль и должен быть активен), ретеншн debug.retention_days обязателен, иначе таблица растёт неограниченно на активно используемом staging. Горячий путь самого модуля — оверхед query-listener на каждый SQL-запрос обязан быть минимальным (микросекунды на запрос), иначе инструмент диагностики сам становится источником замедления, которое он должен обнаруживать у других; детект N+1 не должен вести собственный N+1 (например, отдельный запрос в БД на каждый перехваченный SQL для классификации). Собственных тегов page-cache нет — участвует только косвенно (модуль отключён в production, где живёт page-cache).

Безопасность

Границы входа: панель профилирования — только служебный роут /api/v1/admin/debug/profile под тройным гейтом (ниже), входных форм с пользовательскими данными нет. Доступ к панели и экспорту — только через явные permissions, не по строке роли.

Тройной гейт от прода

По аналогии с cms/dev-panel (тот же принцип в парке инфра-модулей) доступ защищён тремя независимыми факторами, ни один из которых не даёт доступа сам по себе. Проверка — в middleware, до рендера панели и до активации query-listener на соединении БД:

#ФакторУсловиеГде проверяется
1envAPP_ENV не production, либо production с явным допускомmiddleware, на каждый запрос к панели/профилю
2настройкаdebug.enabled=true и debug.allowed_roles не пустmiddleware, чтение из кеша группы настроек (0 запросов на горячем пути)
3рольроль текущего пользователя входит в debug.allowed_rolesmiddleware, до рендера страницы и до подписки query-listener

Отсутствие любого одного фактора — отказ (403 до рендера), остальные два не спасают: APP_ENV=local без debug.enabled=true не активирует ни панель, ни перехват запросов (env один не открывает гейт); debug.enabled=true на production без нужной роли — 403 (настройка одна не открывает гейт); нужная роль при debug.enabled=false — 403 (роль одна не открывает гейт). Тот же гейт закрывает не только Filament-панель, но и активацию query-listener и Pail-стрим — перехват SQL не работает «в фоне», пока не пройдены все три фактора.

Специфичные векторы: query-log с bindings — прямой канал утечки ПДн и секретов (пароли в формах, токены в заголовках) в лог/Telescope/экспортируемый тикет — bindings обязаны проходить тот же скраббинг чувствительных полей, что и cms/sentry breadcrumbs, до записи, не после; экспорт профиля для тикета — файл может попасть во внешнюю систему (трекер) при вложении к тикету, поэтому маскирование обязательно даже строже, чем во внутреннем логе; Pail-стрим логов в реальном времени — доступен только под тем же тройным гейтом, что и панель, не отдельным незащищённым каналом.

ПДн-паспорт

Модуль не хранит ПДн как основную сущность. Query-log с SQL и bindings может временно содержать ПДн (email, пароли форм) до срабатывания скраббинга (debug.scrub_bindings_enabled); сам query-log живёт только в памяти процесса текущего запроса/джобы и не персистится, кроме явного cms:debug:snapshot (файл на диске) и включённого Telescope (telescope_entries). Ретеншн: снимки — debug.snapshot_retention_days, Telescope — debug.retention_days. Хуки ядра «выгрузить всё по субъекту»/«забыть по запросу» (152-ФЗ) — не применимы: диагностические данные не привязаны к конкретному ФЛ как основной сущности и не переживают собственный ретеншн; по истечении retention_days/ snapshot_retention_days данные удаляются штатной очисткой, отдельного per-субъект стирания не требуется.

Матрица ролей

Доступ к любому действию модуля — только роли из debug.allowed_roles (по умолчанию ["studio"], сам список — часть гейта, см. выше); остальные штатные роли парка (админ клиента, менеджер, редактор) доступа не получают ни при какой комбинации остальных настроек:

Permissionstudio (роль в debug.allowed_roles)админ/менеджер/редактор клиента
debug.view (панель, query-log)данет
debug.manage (изменение настроек группы debug)данет
debug.export (скачивание снятого профиля)данет

Права: debug.view, debug.manage, debug.export — все три проверяются поверх тройного гейта, а не вместо него.

UX-требования

Админ (разработчик/studio-инженер): пустое состояние «медленных запросов не было» на виджете вместо пустого списка; профилирование запроса — цифры (время, память, число SQL) сопровождаются понятной шкалой «нормально/медленно/критично», не голые числа без контекста; экспорт профиля — одна кнопка «Скачать для тикета», результат сразу готов к вложению, без ручной сборки; предупреждение при попытке включить модуль на production («вы уверены — на проде это может замедлить запросы») даже под studio-ролью, где это формально разрешено.

Посетитель: не применимо — модуль не должен быть виден и не должен влиять на поведение публичного сайта ни при каких условиях.

Крайние случаи и типовые баги

  • случайное включение на продеdebug.enabled=true в .env/настройках на проде без нужной роли не даёт доступа — тройной гейт (env, debug.enabled+debug.allowed_roles, роль пользователя) проверяется на уровне middleware одновременно, ни один из трёх факторов не достаточен сам по себе;
  • утечка ПДн/секретов через query-log → bindings со значениями из полей вроде password/token/email маскируются до попадания в лог/Telescope/экспорт — тест на утечку аналогичен тесту cms/sentry, но применяется к SQL-параметрам, не breadcrumbs;
  • детект N+1 ложно триггерится на легитимный паттерн (например, батч из нескольких похожих, но не идентичных запросов) → порог/эвристика детекта настраиваемы, событие N1PatternDetected включает достаточно контекста (модель, стек), чтобы разработчик быстро отличил реальный N+1 от совпадения;
  • query-listener сам создаёт нагрузку на нагруженном dev/staging → оверхед на запрос обязан быть измерен и минимален; включённый n1_detection не должен удваивать время ответа — если бюджет превышен, это баг модуля, не приемлемая цена диагностики;
  • выключение модуля посреди снятия snapshotcms:debug:snapshot — синхронная CLI-операция, не оставляющая промежуточного состояния: либо снимок создан целиком, либо не создан вовсе, отключение модуля между запуском и завершением команды не предусмотрено (команда выполняется в рамках одного процесса);
  • отсутствие Telescope при debug.telescope_enabled=true (пакет не установлен как dev-зависимость) → self-test enable обязан явно сообщить о несоответствии, не включать интеграцию молча в состояние «включена, но не работает»;
  • пустой query-log (запрос вообще не делал SQL) → панель показывает «0 запросов» — валидный результат, не ошибка рендера;
  • огромный query-log (сотни запросов на один тяжёлый экран/джобу) → UI обязан группировать повторяющиеся запросы (это и есть детект N+1), не выводить плоский список из сотен строк без агрегации;
  • измерения locale/city/site — модуль не работает с контентными данными и не несёт этих измерений; сам SQL, который он логирует, может относиться к любому из измерений — это не касается debug напрямую, разработчик видит измерение в контексте запроса (RequestContext), не в отдельном поле модуля;
  • противоречивая комбинация настроек: debug.enabled=true, но debug.allowed_roles пуст ([]) → эффективно никто не имеет доступа, при этом query-listener всё равно перехватывает запросы вхолостую — стоит явно указать в cms:debug:doctor, что включённый модуль без разрешённых ролей — это, вероятно, ошибка конфигурации, а не осознанное состояние.

Донорский код

Донор: — (новая разработка). Миграция legacy-данных (§16, матрица v2.2): не применимо — модуль не хранит собственных бизнес-данных, переносимых со старых платформ (диагностический инструмент без предметных сущностей), импорт-профиль cms:debug:import-legacy не нужен и не заводится.

Тесты и приёмка

  • [ ] Модуль недоступен в production без studio-роли (контрактный тест)
  • [ ] Health-чек модуля отражает включён/выключен и активность Telescope
  • [ ] При выключении модуля приложение работает штатно, ошибки идут в общий лог
  • [ ] Права debug.view/debug.manage разграничивают доступ к панели
  • [ ] Детект N+1 не создаёт собственных N+1 (сам инструмент лёгкий)
  • [ ] Ретеншн записей Telescope применяется автоматически по debug.retention_days
  • [ ] Bindings с чувствительными полями (password, token, email) маскируются в query-log, Telescope и экспорте
  • [ ] Контрактный тест env-only: APP_ENV не production, но debug.enabled=false — доступа нет (фактор env в одиночку гейт не открывает)
  • [ ] Контрактный тест setting-only: debug.enabled=true и debug.allowed_roles заполнен, но APP_ENV=production без явного допуска — доступа нет (фактор настройки в одиночку гейт не открывает)
  • [ ] Контрактный тест role-only: роль пользователя входит в debug.allowed_roles, но debug.enabled=false — доступа нет (фактор роли в одиночку гейт не открывает)
  • [ ] Включённый telescope_enabled без установленного пакета Telescope диагностируется cms:debug:doctor, не включается молча
  • [ ] Контрактный набор cms-testing пройден, пакет протестирован в testbench-изоляции
  • [ ] Feature-тест на каждый роут модуля; тестовая БД только debug_test, migrate:fresh запрещён

Внутренняя база знаний студии