Поток данных
На этой странице описано, как отладочные данные проходят от вашего приложения к панели ADP.
Обзор
Приложение → Адаптер → Прокси → Коллекторы → Debugger → Хранилище → API → ФронтендЖизненный цикл запроса
Фаза 1: Запуск
Когда приложение получает HTTP-запрос (или CLI-команду):
- Обработчик событий адаптера перехватывает событие запуска фреймворка
- Вызывается Debugger
AppDevPanel\Kernel\DebuggerClass Debugger.::startup(), который:- Регистрирует shutdown-функцию
- Проверяет, нужно ли игнорировать запрос/команду (через паттерны
$ignoredRequests/$ignoredCommands, заголовокX-Debug-Ignore) - Если не игнорируется: вызывает
startup()на всех зарегистрированных коллекторах
Фаза 2: Сбор данных
Во время обработки запроса прокси перехватывают вызовы и передают данные коллекторам:
Код приложения
│
├──▶ Logger::log() ──▶ LoggerInterfaceProxy ──▶ LogCollector
├──▶ EventDispatcher::dispatch() ──▶ EventDispatcherInterfaceProxy ──▶ EventCollector
├──▶ HttpClient::sendRequest() ──▶ HttpClientInterfaceProxy ──▶ HttpClientCollector
├──▶ Container::get() ──▶ ContainerInterfaceProxy ──▶ ServiceCollector
├──▶ VarDumper::dump() ──▶ VarDumperHandlerInterfaceProxy──▶ VarDumperCollector
└──▶ throw Exception ──▶ ExceptionHandler ──▶ ExceptionCollectorКаждый коллектор накапливает данные в памяти на протяжении запроса. Прокси записывают метаданные: временные метки, информацию файл:строка (через debug_backtrace()), уникальные ID для корреляции.
Фаза 3: Завершение и сброс
Когда запрос завершается (или консольная команда заканчивается), DebuggerAppDevPanel\Kernel\DebuggerClass Debugger. инициирует завершение:
- Вызывает
shutdown()на всех коллекторах (сбрасывает внутреннее состояние) - Вызывает
getCollected()для получения накопленных данных - Сериализует объекты через Dumper
AppDevPanel\Kernel\DumperClass Dumper. (ограничение глубины — 30 уровней, обнаружение циклических ссылок) - Вызывает
flush()на хранилище
FileStorageAppDevPanel\Kernel\Storage\FileStorageClass FileStorage. записывает три JSON-файла на каждую отладочную запись:
| Файл | Содержимое |
|---|---|
{id}/summary.json | Метаданные записи (время, URL, статус, сводки коллекторов) |
{id}/data.json | Полные данные коллекторов |
{id}/objects.json | Извлечённые уникальные PHP-объекты для глубокой инспекции |
Все записи используют file_put_contents() с LOCK_EX для атомарности.
Фаза 4: Сборка мусора
После каждого сброса хранилище запускает сборку мусора:
- Захватывает неблокирующую блокировку
.gc.lock(пропускает, если другой процесс удерживает) - Удаляет записи сверх
historySize(по умолчанию 50), отсортированные по времени модификации
Формат хранилища
runtime/debug/
├── YYYY-MM-DD/
│ ├── {entryId}/
│ │ ├── summary.json
│ │ ├── data.json
│ │ └── objects.json
│ ├── {entryId}/
│ │ └── ...
│ └── .gc.lock
└── .services.jsonФормат сводки
{
"id": "1710520800123456",
"collectors": ["LogCollector", "EventCollector", "RequestCollector"],
"logger": {"total": 5},
"event": {"total": 12},
"http": {"count": 2, "totalTime": 0.45},
"request": {"url": "/api/users", "method": "GET", "status": 200},
"exception": null
}Коллекторы, реализующие SummaryCollectorInterfaceAppDevPanel\Kernel\Collector\SummaryCollectorInterfaceSummary data collector responsibility is to collect summary data for a collector. Summary is used to display a list of previous requests and select one to display full info. Its data set is specific to the list and is reduced compared to full data collected in {@see CollectorInterface}., предоставляют свои ключи сводки (например, logger, event, http) для отображения в списке записей без загрузки полных данных.
Обслуживание API
API предоставляет сохранённые данные через цепочку middleware:
Запрос фронтенда
│
▼
Цепочка middleware API
┌────────────────────────────┐
│ 1. CorsAllowAll │
│ 2. IpFilter │
│ 3. TokenAuthMiddleware │
│ 4. FormatDataResponseAsJson│
│ 5. ResponseDataWrapper │
└────────────┬───────────────┘
│
▼
CollectorRepository
├── .getSummary() → summary.json
├── .getDetail(id) → data.json
└── .getObject(id) → objects.json
│
▼
JSON-ответ: {id, data, error, success, status}Обновления в реальном времени (SSE)
Фронтенд использует SSE (Server-Sent Events) для обнаружения новых записей в реальном времени:
- Фронтенд подписывается на
GET /debug/api/event-stream - API опрашивает хранилище каждую секунду, вычисляя MD5-хеш текущих сводок
- При появлении новой записи хеш меняется и отправляется событие:
{"type": "debug-updated"} - Фронтенд загружает обновлённый список записей
ServerSentEventsObserver на фронтенде использует экспоненциальную задержку при сбоях: базовая задержка 1с, удваивается с каждой попыткой, максимум 30с, сбрасывается при успешном подключении.
API приёма данных (внешние приложения)
Не-PHP приложения могут отправлять отладочные данные через Ingestion API, минуя пайплайн прокси/коллекторов. Данные записываются напрямую в хранилище и отображаются в панели наряду с PHP-записями.
| Эндпоинт | Описание |
|---|---|
POST /debug/api/ingest | Одна запись с коллекторами + опциональные context/summary |
POST /debug/api/ingest/batch | Несколько записей (макс. 100). Возвращает {ids: [...], count} |
POST /debug/api/ingest/log | Сокращение для одной лог-записи: {level, message, context?} |
GET /debug/api/openapi.json | OpenAPI-спецификация Ingestion API |
Формат тела запроса для одной записи:
{
"collectors": {
"LogCollector": [{"level": "info", "message": "Hello"}]
},
"summary": {},
"context": {}
}Прокси инспектора (мульти-приложения)
Прокси инспектора позволяет фронтенду инспектировать внешние приложения (Python, Node.js, Go и др.) через единый API.
Фронтенд: /inspect/api/routes?service=python-app
│
▼
InspectorProxyMiddleware
├── Извлекает имя сервиса из ?service=
├── Разрешает через ServiceRegistry → ServiceDescriptor
├── Проверяет онлайн-статус (lastSeenAt в пределах 60с)
├── Сопоставляет путь с capability (напр., /routes → "routes")
├── Проверяет поддержку capability сервисом
│
▼ (все проверки пройдены)
Проксирует запрос на: {inspectorUrl}/inspect/api/routesКарта capabilities
| Префикс пути | Capability |
|---|---|
/config, /params | config |
/routes, /route/check | routes |
/files | files |
/cache | cache |
/table | database |
/translations | translations |
/events | events |
/command | commands |
/git | git |
/composer | composer |
/phpinfo | phpinfo |
/opcache | opcache |
Ответы об ошибках
| Условие | Статус |
|---|---|
| Сервис не найден | 404 |
| Сервис офлайн (таймаут heartbeat) | 503 |
| Capability не поддерживается | 501 |
| URL инспектора не настроен | 502 |
| Отказ соединения / хост не найден | 502 |
| Таймаут запроса | 504 |
Реестр сервисов
Внешние приложения регистрируются в ADP и отправляют периодические heartbeat-запросы для отображения как онлайн:
Внешнее приложение ADP
│ │
│ POST /debug/api/services/register │
│ {service, language, inspectorUrl, │
│ capabilities} │
│ ──────────────────────────────────▶ │
│ │
│ POST /debug/api/services/heartbeat │
│ {service} (каждые <60с) │
│ ──────────────────────────────────▶ │
│ │
│ GET /debug/api/services/ │
│ ◀────────────────────────────────── │ (список с online/offline)ServiceDescriptorAppDevPanel\Kernel\Service\ServiceDescriptorClass ServiceDescriptor. содержит: service, language, inspectorUrl, capabilities[], registeredAt, lastSeenAt. Сервис считается онлайн, если now() - lastSeenAt < 60с.
Консольные команды
Консольные команды следуют тому же жизненному циклу, что и веб-запросы, с отличиями:
- ConsoleAppInfoCollector
AppDevPanel\Kernel\Collector\Console\ConsoleAppInfoCollectorCollects Console App Info data during application lifecycle. заменяет WebAppInfoCollectorAppDevPanel\Kernel\Collector\Web\WebAppInfoCollectorCollects Web App Info data during application lifecycle. - CommandCollector
AppDevPanel\Kernel\Collector\Console\CommandCollectorCollects Command data during application lifecycle. заменяет RequestCollectorAppDevPanel\Kernel\Collector\Web\RequestCollectorCollects Request data during application lifecycle. (оба отображаются в единой панели "Request" в UI) - Нет middleware, маршрутизатора или коллекторов ассетов
- События:
ConsoleCommandEventзапускает startup,ConsoleTerminateEventзапускает shutdown
Debug-сервер (UDP-сокет)
CLI-команда dev запускает UDP-сокет сервер для вывода логов/дампов в реальном времени в терминале:
php yii dev -a 0.0.0.0 -p 8890Когда приложение вызывает dump() или логирует сообщение, broadcaster:
- Обнаруживает запущенные серверные сокеты через glob (
/tmp/yii-dev-server-*.sock) - Отправляет данные как base64-кодированный JSON с 8-байтным заголовком длины
- Сервер отображает сообщение как форматированный блок в терминале
Типы сообщений: VarDumper, Logger и простой текст.