Pierwsze kroki z Tracy

Biblioteka Tracy to przydatny codzienny pomocnik programisty PHP. Pomaga Ci:

  • szybko wykrywać i poprawiać błędy
  • logować błędy
  • dumpować zmienne
  • mierzyć czas wykonywania skryptów/zapytań
  • widzieć zużycie pamięci

PHP to język idealnie nadający się do tworzenia trudnych do wykrycia błędów, bo daje programistom sporą swobodę. Tym cenniejsze jest narzędzie debugujące takie jak Tracy. Reprezentuje absolutny szczyt wśród narzędzi diagnostycznych dla PHP.

Jeśli spotykasz się z Tracy dziś po raz pierwszy, uwierz, że Twoje życie zacznie dzielić się na czas przed Tracy i czas z nią. Witaj w tej lepszej części!

Instalacja

Najlepszym sposobem instalacji Tracy jest pobranie najnowszego pakietu albo użycie Composera:

composer require tracy/tracy

Alternatywnie możesz pobrać cały pakiet albo plik tracy.phar.

Użycie

Tracy aktywuje się wywołaniem metody Tracy\Debugger::enable() możliwie jak najwcześniej na początku programu, przed wysłaniem jakiegokolwiek wyjścia:

use Tracy\Debugger;

require 'vendor/autoload.php'; // ewentualnie tracy.phar

Debugger::enable();

Pierwszą rzeczą, którą zauważysz na stronie, jest Tracy Bar w prawym dolnym rogu. Jeśli go nie widzisz, może to oznaczać, że Tracy działa w trybie produkcyjnym. Tracy jest bowiem ze względów bezpieczeństwa widoczna tylko na localhoście. Żeby sprawdzić, czy działa, możesz tymczasowo przełączyć ją w tryb deweloperski parametrem Debugger::enable(Debugger::Development).

Tracy Bar

Tracy Bar to pływający panel wyświetlany w prawym dolnym rogu strony. Możesz go przesuwać myszą, a po przeładowaniu strony zapamięta swoją pozycję.

Do Tracy Bara możesz dodawać kolejne przydatne panele. Ciekawe znajdziesz w dodatkach albo możesz utworzyć własne.

Jeśli nie chcesz wyświetlać Tracy Bara, ustaw:

Debugger::$showBar = false;

Wizualizacja błędów i wyjątków

Na pewno wiesz, jak PHP zgłasza błędy: wypisuje do kodu źródłowego strony coś takiego:

Parse error:  syntax error, unexpected '}' in HomePresenter.php on line 15

albo nieprzechwycony wyjątek:

Fatal error:  Uncaught Nette\MemberAccessException: Call to undefined method Nette\Application\UI\Form::addTest()? in /sandbox/vendor/nette/utils/src/Utils/ObjectMixin.php:100
Stack trace:
#0 /sandbox/vendor/nette/utils/src/Utils/Object.php(75): Nette\Utils\ObjectMixin::call(Object(Nette\Application\UI\Form), 'addTest', Array)
#1 /sandbox/app/Forms/SignFormFactory.php(32): Nette\Object->__call('addTest', Array)
#2 /sandbox/app/Presentation/Sign/SignPresenter.php(21): App\Forms\SignFormFactory->create()
#3 /sandbox/vendor/nette/component-model/src/ComponentModel/Container.php(181): App\Presentation\Sign\SignPresenter->createComponentSignInForm('signInForm')
#4 /sandbox/vendor/nette/component-model/src/ComponentModel/Container.php(139): Nette\ComponentModel\Container->createComponent('signInForm')
#5 /sandbox/temp/cache/latte/15206b353f351f6bfca2c36cc.php(17): Nette\ComponentModel\Co in /sandbox/vendor/nette/utils/src/Utils/ObjectMixin.php on line 100

Poruszanie się po takim wyjściu nie jest łatwe. Jeśli włączysz Tracy, błędy i wyjątki wyświetlają się w zupełnie innej postaci:

Komunikat o błędzie dosłownie krzyczy. Widzisz fragment kodu źródłowego z podświetloną linią, w której doszło do błędu. Komunikat Call to undefined method Nette\Http\User::isLogedIn() jasno wyjaśnia błąd. Cała strona jest interaktywna, możesz doklikać się do szczegółów. Wypróbuj.

I wiesz co? Błędy krytyczne są przechwytywane i wyświetlane w ten sam sposób. Bez potrzeby instalowania jakichkolwiek rozszerzeń.

Błędy takie jak literówka w nazwie zmiennej albo próba otwarcia nieistniejącego pliku generują zgłoszenia na poziomie E_NOTICE albo E_WARNING. Łatwo je przeoczyć w graficznym layoucie strony, a nawet mogą być całkowicie niewidoczne (chyba że zajrzysz do kodu źródłowego). Pozwól, żeby zajęła się nimi Tracy:

Albo mogą wyświetlać się jak błędy:

Debugger::$strictMode = true; // wyświetla wszystkie błędy
Debugger::$strictMode = E_ALL & ~E_DEPRECATED & ~E_USER_DEPRECATED; // wszystkie błędy oprócz notic o przestarzałości

Uwaga: Tracy po aktywacji zmienia poziom raportowania błędów na E_ALL. Jeśli chcesz to zmienić, zrób to po wywołaniu enable().

Tryb deweloperski a produkcyjny

Jak widzisz, Tracy jest dość rozmowna, co można docenić w środowisku deweloperskim, podczas gdy na serwerze produkcyjnym spowodowałoby to katastrofę. Nie powinny się tam bowiem wyświetlać żadne informacje debugujące. Tracy ma dlatego autodetekcję środowiska. Jeśli przykład zostanie uruchomiony na serwerze produkcyjnym, błąd zostanie zalogowany zamiast wyświetlony, a odwiedzający zobaczy tylko przyjazny komunikat:

Tryb produkcyjny wyłącza wyświetlanie wszystkich informacji debugujących wysyłanych przez dump(), a oczywiście także wszystkich komunikatów o błędach generowanych przez PHP. Jeśli więc zapomniałeś w kodzie jakiegoś dump($obj), nie musisz się martwić, na serwerze produkcyjnym nic się nie wyświetli.

Jak działa autodetekcja trybu? Tryb jest deweloperski, jeśli aplikacja działa na localhoście (czyli pod adresem IP 127.0.0.1 albo ::1) i nie ma proxy (czyli jego nagłówek HTTP nie jest obecny). W przeciwnym razie działa w trybie produkcyjnym.

Jeśli chcesz włączyć tryb deweloperski także w innych przypadkach, na przykład dla programistów łączących się z konkretnego adresu IP, możesz podać go jako parametr metody enable():

Debugger::enable('23.75.345.200'); // możesz podać też tablicę adresów IP

Zdecydowanie zalecamy łączenie adresu IP z cookie. Zapisz do cookie tracy-debug tajny token, np. secret1234, i w ten sposób aktywuj tryb deweloperski tylko dla programistów łączących się z konkretnego adresu IP, którzy mają wspomniany token w cookie:

Debugger::enable('secret1234@23.75.345.200');

Tryb deweloperski/produkcyjny możesz też ustawić bezpośrednio, używając stałych Debugger::Development albo Debugger::Production jako parametru metody enable().

Jeśli używasz Nette Framework, zobacz, jak ustawić tryb dla niego, a zostanie on użyty również dla Tracy.

Logowanie błędów

W trybie produkcyjnym Tracy automatycznie loguje wszystkie błędy i przechwycone wyjątki do logu tekstowego. Żeby logowanie działało, musisz ustawić absolutną ścieżkę do katalogu logów w zmiennej $logDirectory albo przekazać ją jako drugi parametr metody enable():

Debugger::$logDirectory = __DIR__ . '/log';

Logowanie błędów jest niezwykle przydatne. Wyobraź sobie, że wszyscy użytkownicy Twojej aplikacji to w rzeczywistości beta testerzy, którzy za darmo wykonują pierwszorzędną pracę przy znajdowaniu błędów, a Ty byłbyś głupi, wyrzucając ich cenne zgłoszenia niezauważone do kosza.

Jeśli potrzebujesz logować własne komunikaty albo przechwycone wyjątki, użyj metody log():

Debugger::log('Unexpected error'); // komunikat tekstowy

try {
	criticalOperation();
} catch (Exception $e) {
	Debugger::log($e); // logowanie wyjątku
	// albo
	Debugger::log($e, Debugger::ERROR); // wysyła też powiadomienie e-mailem
}

Jeśli chcesz, żeby Tracy logowała błędy PHP jak E_NOTICE czy E_WARNING ze szczegółowymi informacjami (raport HTML), ustaw Debugger::$logSeverity:

Debugger::$logSeverity = E_NOTICE | E_WARNING;

Dla prawdziwego profesjonalisty log błędów jest kluczowym źródłem informacji i chce być natychmiast informowany o każdym nowym błędzie. Tracy wychodzi temu naprzeciw, potrafiąc wysyłać powiadomienia e-mailem o nowych wpisach w logu. Zmienna $email określa, gdzie te e-maile wysyłać:

Debugger::$email = 'admin@example.com';

Jeśli używasz całego Nette Framework, możesz ustawić to i inne rzeczy w pliku konfiguracyjnym.

Żeby chronić Twoją skrzynkę przed zalaniem, Tracy wysyła tylko jedną wiadomość i tworzy plik email-sent. Gdy programista otrzyma powiadomienie e-mailem, sprawdza log, poprawia aplikację i usuwa plik monitorujący email-sent. Reaktywuje to wysyłanie e-maili.

Raporty w markdownie

Obok każdego log/exception-*.html Tracy zapisuje bliźniaczy plik .md z tą samą treścią w markdownie: komunikat, stos wywołań i wycinki kodu źródłowego. Pliki te powstają bezwarunkowo, niezależnie od tego, czy z aplikacją pracuje agent AI.

Ich celem jest przetwarzanie wsadowe. Zamiast przeklikiwać się przez setki raportów HTML po kolei, możesz przekazać agentowi AI cały katalog logów i pozwolić mu porównać każdy raport z bieżącym stanem kodu oraz zaproponować poprawki.

Wsparcie dla agentów AI

Gdy agent AI steruje Twoją aplikacją przez przeglądarkę (Chrome DevTools MCP, Playwright, Puppeteer), Tracy wykrywa go przez JavaScriptową właściwość navigator.webdriver i wysyła do konsoli przeglądarki markdownową wersję kluczowej diagnostyki obok standardowego UI:

  • BlueScreen – wyjątek, stos wywołań i wartości zmiennych wysyłane do console.error() obok czerwonego ekranu, zarówno przy renderowaniu synchronicznym, jak i przy błędach AJAX.
  • Tracy Bar – markdownowe podsumowanie głównych paneli (SQL, Errors, Dumps) wysyłane do console.log().
  • Debugger::dump() – wariant zwykłym tekstem obok zwykłego wyjścia HTML, żeby dumpy nie ginęły w stronie.
  • Produkcyjna strona 500 – console.error() informuje agenta, że doszło do błędu i że szczegóły zostały zalogowane na serwerze.

Wykrycie ustawia cookie tracy-webdriver=1; możesz ustawić je ręcznie w DevTools, żeby włączyć wyjście markdownowe ze zwykłej przeglądarki. Aktywacja agenta nie wpływa na bliźniacze pliki .md zapisywane obok każdego log/exception-*.html – te powstają bezwarunkowo i stanowią podstawę wsadowego przetwarzania logów produkcyjnych.

Własne panele Tracy Bara mogą dostarczyć swój markdown, implementując getAgentInfo(). Dla użytkowników Claude Code plugin Nette zawiera skill tracy-debugging, który uczy agenta, jak czytać wyjście Tracy z list_console_messages().

Otwieranie plików w edytorze

Gdy wyświetli się strona błędu, możesz kliknąć w nazwy plików, a otworzą się w Twoim edytorze z kursorem na odpowiedniej linii. Pliki można też tworzyć (akcja create file) albo naprawiać w nich błędy (akcja fix it). Żeby to działało, trzeba skonfigurować przeglądarkę i system.

Wspierane wersje PHP

Tracy Kompatybilna z PHP
Tracy 2.10 – 3.0 PHP 8.0 – 8.4
Tracy 2.9 PHP 7.2 – 8.2
Tracy 2.8 PHP 7.2 – 8.1
Tracy 2.6 – 2.7 PHP 7.1 – 8.0
Tracy 2.5 PHP 5.4 – 7.4
Tracy 2.4 PHP 5.4 – 7.2

Dotyczy najnowszych wersji patch.

Porty

Oto lista nieoficjalnych portów do innych frameworków i CMS-ów: