Tworzenie rozszerzeń dla Tracy

Tracy to świetne narzędzie do debugowania Twojej aplikacji. Czasem jednak możesz chcieć mieć pod ręką dodatkowe informacje. Pokażemy Ci, jak napisać własne rozszerzenia dla Tracy Bara, żeby tworzenie było jeszcze przyjemniejsze.

  • Tworzenie własnego panelu Tracy Bara
  • Tworzenie własnego rozszerzenia Bluescreenu

Repozytorium gotowych rozszerzeń dla Tracy znajdziesz na Componette.

Rozszerzenia Tracy Bara

Utworzenie nowego rozszerzenia dla Tracy Bara jest proste. Utwórz obiekt implementujący interfejs Tracy\IBarPanel, który ma dwie metody: getTab() i getPanel(). Metody te muszą zwracać kod HTML zakładki (małej etykiety wyświetlanej bezpośrednio na Barze) i panelu (wyskakującego okna wyświetlanego po kliknięciu w zakładkę). Jeśli getPanel() nic nie zwróci, wyświetli się tylko sama zakładka. Jeśli getTab() nic nie zwróci, nie wyświetli się nic, a getPanel() nie zostanie wywołane.

class ExamplePanel implements Tracy\IBarPanel
{
	public function getTab()
	{
		return /* ... */;
	}

	public function getPanel()
	{
		return /* ... */;
	}
}

Rejestracja

Rejestrację przeprowadza się wywołaniem Tracy\Debugger::getBar()->addPanel():

Tracy\Debugger::getBar()->addPanel(new ExamplePanel);

Alternatywnie możesz zarejestrować panel bezpośrednio w konfiguracji aplikacji:

tracy:
	bar:
		- ExamplePanel

Kod HTML zakładki

Powinien wyglądać mniej więcej tak:

<span title="Objaśniający tooltip">
	<svg>...</svg>
	<span class="tracy-label">Tytuł</span>
</span>

Obrazek powinien być w formacie SVG. Jeśli objaśniający tooltip nie jest potrzebny, zewnętrzny <span> można pominąć.

Kod HTML panelu

Powinien wyglądać mniej więcej tak:

<h1>Tytuł</h1>

<div class="tracy-inner">
<div class="tracy-inner-container">
	... treść ...
</div>
</div>

Tytuł powinien być albo taki sam jak tytuł zakładki, albo zawierać dodatkowe informacje.

Miej na uwadze, że jedno rozszerzenie może być zarejestrowane wielokrotnie, na przykład z różnymi ustawieniami. Dlatego do stylowania nie możesz używać ID w CSS, tylko klas, najlepiej w formacie tracy-addons-<NazwaKlasy>[-<opcjonalne>]. Dodaj tę klasę do diva razem z klasą tracy-inner. Przy pisaniu CSS przydaje się poprzedzać selektory #tracy-debug .twoja-klasa, bo daje to regule wyższą specyficzność niż stylom resetującym.

Style domyślne

W panelu elementy <a>, <table>, <pre> i <code> mają predefiniowane style. Jeśli chcesz utworzyć odnośnik ukrywający i pokazujący inny element, połącz je atrybutami href i id oraz klasą tracy-toggle:

<a href="#tracy-addons-ClassName-{$counter}" class="tracy-toggle">Szczegóły</a>

<div id="tracy-addons-ClassName-{$counter}">...</div>

Jeśli stanem domyślnym jest zwinięcie, dodaj obu elementom klasę tracy-collapsed.

Użyj statycznego licznika, żeby zapobiec duplikowaniu ID na jednej stronie.

Własne zasoby

Jeśli Twój panel potrzebuje własnego arkusza stylów albo skryptu, możesz sprawić, żeby Tracy wczytała dodatkowe pliki razem ze swoimi zasobami:

Tracy\Debugger::$customCssFiles[] = __DIR__ . '/panel.css';
Tracy\Debugger::$customJsFiles[] = __DIR__ . '/panel.js';

Wsparcie dla agentów AI

Gdy przeglądarką steruje agent AI, Tracy wysyła do konsoli JS podsumowanie Tracy Bara w markdownie. Własne panele mogą dostarczyć swój markdown, dodając do swojej implementacji IBarPanel metodę 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";
	}
}

Zwrócony markdown włączany jest do markdownowego podsumowania bara. Gdy metody brakuje albo zwraca null, panel jest z podsumowania pomijany.

Pełny obraz znajdziesz w integracji Tracy z agentami AI.

Rozszerzenia Bluescreenu

W ten sposób możesz dodać własne wizualizacje wyjątków albo panele, które pojawią się na bluescreenie.

Rozszerzenie tworzy się tak:

Tracy\Debugger::getBlueScreen()->addPanel(function (?Throwable $e) { // przechwycony wyjątek
	return [
		'tab' => '...Tytuł...',
		'panel' => '...Treść HTML panelu...',
	];
});

Funkcja wywoływana jest dwa razy. Najpierw w parametrze $e przekazywany jest sam wyjątek (jeśli wyjątek wystąpił), a zwrócony panel renderowany jest na początku strony. Jeśli zwróci null albo pustą tablicę, panel nie jest renderowany. Następnie wywoływana jest z $e = null, a zwrócony panel renderowany jest pod stosem wywołań. Jeśli funkcja zwróci w tablicy 'bottom' => true, panel renderowany jest na samym dole.

Oprócz paneli możesz też dodawać akcje metodą addAction(): klikalne odnośniki albo przyciski pojawiające się w nagłówku strony błędu obok wbudowanych (jak search):

Tracy\Debugger::getBlueScreen()->addAction(function (Throwable $e): ?array {
	if ($e instanceof MyException) {
		return [
			'link' => 'https://example.com/help?code=' . $e->getCode(),
			'label' => 'zobacz pomoc',
		];
	}
	return null;
});

Callback otrzymuje przechwycony wyjątek i zwraca tablicę z kluczami link i label albo null, jeśli nie chce dodawać akcji dla danego wyjątku.

Akcja tworzenia pliku

Gdy na stronie błędu klikniesz w plik, który jeszcze nie istnieje, Tracy zaoferuje jego utworzenie (akcja create file). Możesz sterować początkową zawartością takiego pliku, rejestrując generator:

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 otrzymuje ścieżkę pliku docelowego, a gdy jest znana, także nazwę klasy, która ma być w nim zdefiniowana. Zwraca początkową zawartość (token $END$ oznacza miejsce, w którym zostanie umieszczony kursor, i jest z wyjścia usuwany) albo null, żeby zostawić decyzję innemu generatorowi. Generatory próbowane są od ostatnio zarejestrowanego; generator wbudowany tworzy zwykły szkielet PHP.

Fibery i generatory

Jeśli wyjątek zostanie rzucony, gdy fiber albo generator jest wstrzymany, jego stos nie jest częścią zwykłego stosu wywołań. Tracy automatycznie pokazuje stos fiberów i generatorów osiągalnych z wyjątku, ale taki działający niezależnie zostałby pominięty. Możesz dodać go do BlueScreenu ręcznie:

Tracy\Debugger::getBlueScreen()->addFiber($fiber);