Создание расширений Tracy
*************************
<div class=perex>
Tracy - отличный инструмент для отладки вашего приложения. Однако иногда вам может понадобиться, чтобы под рукой была и другая информация. Мы покажем, как написать собственные расширения для Tracy Bar, чтобы разработка стала ещё приятнее.
- Создание собственной панели Tracy Bar
- Создание собственного расширения для красного экрана
</div>
.[tip]
Хранилище готовых расширений для Tracy вы найдёте на "Componette":https://componette.org/search/tracy.
Расширения Tracy Bar
====================
Создать новое расширение для Tracy Bar просто. Создайте объект, реализующий интерфейс `Tracy\IBarPanel`, у которого есть два метода: `getTab()` и `getPanel()`. Эти методы должны вернуть HTML-код вкладки (небольшой ярлык, отображаемый прямо на панели Bar) и панели (всплывающее окно, отображаемое после щелчка по вкладке). Если `getPanel()` ничего не вернёт, отобразится только сама вкладка. Если ничего не вернёт `getTab()`, не отобразится ничего вообще, и `getPanel()` вызван не будет.
```php
class ExamplePanel implements Tracy\IBarPanel
{
public function getTab()
{
return /* ... */;
}
public function getPanel()
{
return /* ... */;
}
}
```
Регистрация
-----------
Регистрация выполняется вызовом `Tracy\Debugger::getBar()->addPanel()`:
```php
Tracy\Debugger::getBar()->addPanel(new ExamplePanel);
```
Как вариант, панель можно зарегистрировать прямо в конфигурации приложения:
```neon
tracy:
bar:
- ExamplePanel
```
HTML-код вкладки
----------------
Должен выглядеть примерно так:
```latte
<span title="Поясняющая подсказка">
<svg>...</svg>
<span class="tracy-label">Заголовок</span>
</span>
```
Изображение должно быть в формате SVG. Если поясняющая подсказка не нужна, внешний `<span>` можно опустить.
HTML-код панели
---------------
Должен выглядеть примерно так:
```latte
<h1>Заголовок</h1>
<div class="tracy-inner">
<div class="tracy-inner-container">
... содержимое ...
</div>
</div>
```
Заголовок должен либо совпадать с заголовком вкладки, либо содержать дополнительные сведения.
Помните, что одно расширение может быть зарегистрировано несколько раз, возможно с разными настройками. Поэтому для оформления нельзя использовать CSS-идентификаторы, только классы, желательно в формате `tracy-addons-<ИмяКласса>[-<необязательное>]`. Добавьте этот класс к div вместе с классом `tracy-inner`. При написании CSS полезно предварять селекторы `#tracy-debug .ваш-класс`, потому что так правило получает более высокую специфичность, чем сбрасывающие стили.
Стили по умолчанию
------------------
В панели у элементов `<a>`, `<table>`, `<pre>` и `<code>` есть заранее заданные стили. Если вы хотите сделать ссылку, скрывающую и показывающую другой элемент, свяжите их атрибутами `href` и `id` и классом `tracy-toggle`:
```latte
<a href="#tracy-addons-ClassName-{$counter}" class="tracy-toggle">Подробности</a>
<div id="tracy-addons-ClassName-{$counter}">...</div>
```
Если состояние по умолчанию - свёрнутое, добавьте обоим элементам класс `tracy-collapsed`.
Используйте статический счётчик, чтобы на одной странице не появились одинаковые идентификаторы.
Собственные ресурсы
-------------------
Если вашей панели нужны собственные стили или скрипт, вы можете попросить Tracy загрузить дополнительные файлы вместе с её собственными ресурсами:
```php
Tracy\Debugger::$customCssFiles[] = __DIR__ . '/panel.css';
Tracy\Debugger::$customJsFiles[] = __DIR__ . '/panel.js';
```
Поддержка AI-агентов .{data-version:2.12.0}
-------------------------------------------
Когда браузером управляет AI-агент, Tracy отправляет в JS-консоль markdown-сводку панели Tracy Bar. Собственные панели могут предоставить свой markdown, добавив в свою реализацию `IBarPanel` метод `getAgentInfo(): ?string`:
```php
class DatabasePanel implements Tracy\IBarPanel
{
public function getTab(): string { /* ... */ }
public function getPanel(): string { /* ... */ }
public function getAgentInfo(): ?string
{
return "## Database\n\n- Queries: {$this->count}\n- Total time: {$this->time} ms\n";
}
}
```
Возвращённый markdown включается в markdown-сводку панели. Если метода нет или он возвращает `null`, панель в сводку не попадает.
Полную картину смотрите в разделе [Интеграция Tracy с AI-агентами |guide#Поддержка AI-агентов].
Расширения красного экрана
==========================
Таким образом вы можете добавить собственные способы отображения исключений или панели, которые появятся на красном экране.
Расширение создаётся так:
```php
Tracy\Debugger::getBlueScreen()->addPanel(function (?Throwable $e) { // перехваченное исключение
return [
'tab' => '...Заголовок...',
'panel' => '...HTML-содержимое панели...',
];
});
```
Функция вызывается дважды. Сначала в параметре `$e` передаётся само исключение (если оно произошло), и возвращённая панель отрисовывается в начале страницы. Если она вернёт `null` или пустой массив, панель не отрисовывается. Затем функция вызывается с `$e = null`, и возвращённая панель отрисовывается под стеком вызовов. Если функция вернёт в массиве `'bottom' => true`, панель отрисуется в самом низу.
Кроме панелей, через `addAction()` можно добавить и **действия** - кликабельные ссылки или кнопки, которые появятся в шапке страницы с ошибкой рядом со встроенными (например, *search*):
```php
Tracy\Debugger::getBlueScreen()->addAction(function (Throwable $e): ?array {
if ($e instanceof MyException) {
return [
'link' => 'https://example.com/help?code=' . $e->getCode(),
'label' => 'посмотреть справку',
];
}
return null;
});
```
Callback получает перехваченное исключение и возвращает массив с ключами `link` и `label` либо `null`, если для данного исключения не хочет добавлять действие.
Действие create file .{data-version:2.9.0}
------------------------------------------
Когда вы на странице с ошибкой щёлкнете по файлу, которого ещё нет, Tracy предложит его создать (действие *create file*). Начальное содержимое такого файла можно задать, зарегистрировав генератор:
```php
Tracy\Debugger::getBlueScreen()->addFileGenerator(function (string $file, ?string $class): ?string {
if (str_ends_with($file, 'Test.php')) {
return "<?php\n\nclass $class extends Tester\\TestCase\n{\n\t\$END\$\n}\n";
}
return null;
});
```
Callback получает путь к целевому файлу и, если оно известно, имя класса, который в нём должен быть определён. Он возвращает начальное содержимое (маркер `$END$` обозначает место, куда встанет курсор, и из вывода удаляется) либо `null`, чтобы оставить решение другому генератору. Генераторы пробуются начиная с зарегистрированного последним; встроенный генератор порождает простой каркас PHP.
Файберы и генераторы .{data-version:2.9.2}
------------------------------------------
Если исключение выброшено в момент, когда файбер или генератор приостановлен, его стек не входит в обычный стек вызовов. Tracy автоматически показывает стек файберов и генераторов, достижимых из исключения, но тот, который работает независимо, остался бы без внимания. Вы можете добавить его в BlueScreen вручную:
```php
Tracy\Debugger::getBlueScreen()->addFiber($fiber);
```
Создание расширений Tracy
Tracy – отличный инструмент для отладки вашего приложения. Однако
иногда вам может понадобиться, чтобы под рукой была и другая
информация. Мы покажем, как написать собственные расширения для Tracy Bar,
чтобы разработка стала ещё приятнее.
- Создание собственной панели Tracy Bar
- Создание собственного расширения для красного экрана
Хранилище готовых расширений для Tracy вы найдёте на Componette.
Расширения Tracy Bar
Создать новое расширение для Tracy Bar просто. Создайте объект,
реализующий интерфейс Tracy\IBarPanel, у которого есть два метода:
getTab() и getPanel(). Эти методы должны вернуть HTML-код вкладки
(небольшой ярлык, отображаемый прямо на панели Bar) и панели (всплывающее
окно, отображаемое после щелчка по вкладке). Если getPanel() ничего
не вернёт, отобразится только сама вкладка. Если ничего не вернёт
getTab(), не отобразится ничего вообще, и getPanel() вызван
не будет.
class ExamplePanel implements Tracy\IBarPanel
{
public function getTab()
{
return /* ... */;
}
public function getPanel()
{
return /* ... */;
}
}
Регистрация
Регистрация выполняется вызовом Tracy\Debugger::getBar()->addPanel():
Tracy\Debugger::getBar()->addPanel(new ExamplePanel);
Как вариант, панель можно зарегистрировать прямо в конфигурации
приложения:
tracy:
bar:
- ExamplePanel
HTML-код вкладки
Должен выглядеть примерно так:
<span title="Поясняющая подсказка">
<svg>...</svg>
<span class="tracy-label">Заголовок</span>
</span>
Изображение должно быть в формате SVG. Если поясняющая подсказка не
нужна, внешний <span> можно опустить.
HTML-код панели
Должен выглядеть примерно так:
<h1>Заголовок</h1>
<div class="tracy-inner">
<div class="tracy-inner-container">
... содержимое ...
</div>
</div>
Заголовок должен либо совпадать с заголовком вкладки, либо содержать
дополнительные сведения.
Помните, что одно расширение может быть зарегистрировано несколько
раз, возможно с разными настройками. Поэтому для оформления нельзя
использовать CSS-идентификаторы, только классы, желательно в формате
tracy-addons-<ИмяКласса>[-<необязательное>]. Добавьте этот класс
к div вместе с классом tracy-inner. При написании CSS полезно предварять
селекторы #tracy-debug .ваш-класс, потому что так правило получает
более высокую специфичность, чем сбрасывающие стили.
Стили по умолчанию
В панели у элементов <a>, <table>, <pre> и
<code> есть заранее заданные стили. Если вы хотите сделать
ссылку, скрывающую и показывающую другой элемент, свяжите их
атрибутами href и id и классом tracy-toggle:
<a href="#tracy-addons-ClassName-{$counter}" class="tracy-toggle">Подробности</a>
<div id="tracy-addons-ClassName-{$counter}">...</div>
Если состояние по умолчанию – свёрнутое, добавьте обоим элементам
класс tracy-collapsed.
Используйте статический счётчик, чтобы на одной странице не
появились одинаковые идентификаторы.
Собственные ресурсы
Если вашей панели нужны собственные стили или скрипт, вы можете
попросить Tracy загрузить дополнительные файлы вместе с её собственными
ресурсами:
Tracy\Debugger::$customCssFiles[] = __DIR__ . '/panel.css';
Tracy\Debugger::$customJsFiles[] = __DIR__ . '/panel.js';
Поддержка AI-агентов
Когда браузером управляет AI-агент, Tracy отправляет в JS-консоль
markdown-сводку панели Tracy Bar. Собственные панели могут предоставить свой
markdown, добавив в свою реализацию IBarPanel метод
getAgentInfo(): ?string:
class DatabasePanel implements Tracy\IBarPanel
{
public function getTab(): string { /* ... */ }
public function getPanel(): string { /* ... */ }
public function getAgentInfo(): ?string
{
return "## Database\n\n- Queries: {$this->count}\n- Total time: {$this->time} ms\n";
}
}
Возвращённый markdown включается в markdown-сводку панели. Если метода нет
или он возвращает null, панель в сводку не попадает.
Полную картину смотрите в разделе Интеграция Tracy с AI-агентами.
Расширения красного экрана
Таким образом вы можете добавить собственные способы отображения
исключений или панели, которые появятся на красном экране.
Расширение создаётся так:
Tracy\Debugger::getBlueScreen()->addPanel(function (?Throwable $e) { // перехваченное исключение
return [
'tab' => '...Заголовок...',
'panel' => '...HTML-содержимое панели...',
];
});
Функция вызывается дважды. Сначала в параметре $e передаётся
само исключение (если оно произошло), и возвращённая панель
отрисовывается в начале страницы. Если она вернёт null или пустой
массив, панель не отрисовывается. Затем функция вызывается с
$e = null, и возвращённая панель отрисовывается под стеком вызовов.
Если функция вернёт в массиве 'bottom' => true, панель отрисуется в
самом низу.
Кроме панелей, через addAction() можно добавить и действия –
кликабельные ссылки или кнопки, которые появятся в шапке страницы с
ошибкой рядом со встроенными (например, search):
Tracy\Debugger::getBlueScreen()->addAction(function (Throwable $e): ?array {
if ($e instanceof MyException) {
return [
'link' => 'https://example.com/help?code=' . $e->getCode(),
'label' => 'посмотреть справку',
];
}
return null;
});
Callback получает перехваченное исключение и возвращает массив с
ключами link и label либо null, если для данного
исключения не хочет добавлять действие.
Действие create file
Когда вы на странице с ошибкой щёлкнете по файлу, которого ещё нет, Tracy
предложит его создать (действие create file). Начальное содержимое
такого файла можно задать, зарегистрировав генератор:
Tracy\Debugger::getBlueScreen()->addFileGenerator(function (string $file, ?string $class): ?string {
if (str_ends_with($file, 'Test.php')) {
return "<?php\n\nclass $class extends Tester\\TestCase\n{\n\t\$END\$\n}\n";
}
return null;
});
Callback получает путь к целевому файлу и, если оно известно, имя класса,
который в нём должен быть определён. Он возвращает начальное
содержимое (маркер $END$ обозначает место, куда встанет курсор, и
из вывода удаляется) либо null, чтобы оставить решение другому
генератору. Генераторы пробуются начиная с зарегистрированного
последним; встроенный генератор порождает простой каркас PHP.
Файберы и генераторы
Если исключение выброшено в момент, когда файбер или генератор
приостановлен, его стек не входит в обычный стек вызовов. Tracy
автоматически показывает стек файберов и генераторов, достижимых из
исключения, но тот, который работает независимо, остался бы без
внимания. Вы можете добавить его в BlueScreen вручную:
Tracy\Debugger::getBlueScreen()->addFiber($fiber);