Debugování ve skriptovacích jazycích

K čemu slouží debugování a jak na něj vyzrát? Jeden z možných způsobů si popíšeme v dnešním článku.

Proč debugging?

Debugging jde ruku v ruce s programováním. Přesto, že někteří programátoři se nechávají slyšet, že píší takový kód, jenž není potřeba debugovat, existuje mnoho příležitostí, kdy dobrý (případně jakýkoli) debugovací nástroj může pomoci urychlit odhalení problému ve zdrojovém kódu. V praxi totiž programátor často upravuje cizí kód. Může se jednat o různé typy aplikací od jednodušších skriptů přes složitější aplikace až k rozsáhlým webovým systémům.

Ať už se potom jedná o jazyk PHP, Ruby nebo třeba Python, pro každý z nich je ve hře množství frameworků a odlišných programátorských přístupů. Pokud člověk vyvíjí v jednom jazyku, jeden projekt v daném frameworku, má debugging značně zpříjemněn. Problém však může nastat, když je programátor nucen čas od času přeskakovat mezi projekty různého stáří, kvality, struktury a rozsahu. Mezi aplikacemi, které programátor detailně nezná a jejichž fungování má prověřit a většinou upravit.

V tuto chvíli máme jako programátoři více variant. Zavrhněme strčit hlavu do písku a vezměme v potaz, že programátor je tvor líný a několikahodinové zírání do kódu bez napsání nové funkce jej zpravidla nebaví.

Jak debugovat v PHP?

Pokud bychom vybrali variantu, že se zabýváme nefunkčním, neznámým nebo složitým projektem v PHP, zřejmě by téměř každý začal více či méně chaoticky v kódu psát var_export() nebo print_r() různých proměnných, kombinovaných s příkazy typu echo „I'm here“; echo „podmínka splněna“; a po pár minutách již jen echo „xxx“; apod.

Takto se dá odhalit jistě mnoho, je to však časově náročné, nezábavné a v neposlední řadě je potom potřeba všechny tyto výpisy odstranit. Díky tomu, že PHP v sobě žádný debugger nemá, troufnu si říci, že touto cestou jde většina programátorů.

Při práci na projektu nad jakýmkoli moderním frameworkem na tom budeme lépe a budeme volat pouze nějakou funkci, která nám přidá obsah proměnné do nějakého debugovacího výpisu, logu apod. Toto řešení je o mnoho pohodlnější, ale pořád člověk musí nejdříve někam napsat volání dané funkce - většinou na více míst, a potom teprve sledovat „co se vlastně děje“.

Třetí možností je použití některého debuggeru pro daný jazyk. V případě PHP může jít například o Xdebug, Fire PHP apod. V tomto případě má programátor k dispozici pokročilý nástroj pro sledování běhu programu a jeho ladění, a to zejména pokud je tento debugger integrován do IDE, ve kterém člověk program píše. Ovšem použití tohoto debuggeru obvykle závisí na tom, zda je na daném počítači instalován, zda je dostupné IDE, které má možnost integrace tohoto debuggeru apod. Nehledě na to, že se může stát, že je třeba aplikaci debugovat (resp. zkontrolovat chování) třeba přímo na produkčním serveru, kde takovýto typ debuggeru nemáme k dispozici.

Co si vybereme…

Ze všech výše uvedených variant zřejmě vyplývá, že žádné řešení není natolik univerzální, aby jeho použití bylo rychlé, jednoduché a možné na kterémkoli projektu bez nutnosti přidávat knihovnu, instalovat debugger nebo jinak zasahovat do aplikace. Chceme prostě vzít kód a vidět, co se v něm děje, kudy jde a co se nám plní do kterých proměnných. Zní to ideálně a krásně. V kompilovaných jazycích bychom s tímto ideálním řešením, které popíšu níže, asi měli problém. Ale v interpretovaném programovacím jazyku typu PHP, Ruby nebo Python tuto možnost máme. Chce to jen trochu si s jazykem pohrát a vytvořit automatizovaný nástroj, který dokáže modifikovat váš kód do podoby potřebné pro debugging a následně vrátit do původní podoby.

A jdeme na to!

Nebudu zde psát konkrétní řešení, ale obecný nástin, jak toho dosáhnout. Prvně si určeme, pro který jazyk náš jednoduchý debugger má fungovat – zvolím jazyk PHP (chci debuggovat PHP aplikace). Nyní zvolme jazyk, ve kterém chceme jednoduchý debugger napsat. Může to být také PHP nebo jakýkoli jazyk, který dokáže rozumně pracovat s textem a upravovat ho. Sám jsem zvolil Ruby, ale může to být cokoli. Debugger bude potom fungovat jako konzolová aplikace spouštěná jako:

  • php phpdebug.php zkoumany_soubor.php,
  • nebo ruby phpdebug.rb zkoumany_soubor.php.

Jak už jsem psal, princip tohoto nástroje spočívá v tom, že daný zdrojový soubor modifikuje do podoby, kdy jsou logovány všechny důležité informace bez nutnosti označovat, jaké to mají být. Následně je daný skript spuštěn a na konec zdrojový soubor navrácen do původního stavu. Potom máme v log souboru dostupný celý průběh skriptu se všemi hodnotami. Chce to pár regulárních výrazů a ušetříte si hodiny odhalování problémů.

Co tedy bude univerzální phpdebug skript obsahovat?

  • Záloha původního souboru zkoumany_soubor.php např. zkopírováním na zkoumany_soubor.php.origin.
  • Úprava souboru zkoumany_soubor.php taková, že na začátku doplníme definici funkce Phpdbg($obsah_promenne, $nazev_promenne, $radek), která bude ukládat informace předané této funkci do souboru. Pro umístění zvolme adresář /tmp kvůli právům (podle operačního systému).
  • Můžeme nadefinovat funkci phpshutdown(), kde zalogujeme případnou chybu a nastavíme register_shutdown_function('phpshutdown');
  • Celý obsah souboru dáme do try – catch bloku. Výjimku obsloužíme zavoláním Phpdbg();
  • V celém souboru přidáme za řádek s přiřazením volání této funkce s patřičnými parametry: Phpdbg($obsah_promenne, $nazev_promenne, $radek);
  • Před každý if ve tvaru if ($abc <= ….) přidáme řádek s Phpdbg($obsah_promenne, $nazev_promenne, $radek);
  • Počkáme na ruční provedení skriptu (zobrazení stránky na webu, provedení akce na stránce) - čekání na stisk klávesy.
  • Vrátíme zpět soubor zkoumany_soubor.php.origin přejmenováním na původní název. 

V log souboru máme dostupný kompletní průběh skriptu. Můžeme hledat a zkoumat, kudy skript běžel, jaké měl parametry, kdy měly které proměnné jaké hodnoty apod. Celé debugování nám nemění obsah původního souboru, ale pokud potřebujeme, můžeme si v kroku 7 tento soubor překopírovat na ostrý server a podívat se do logu na chování v konkrétním prostředí. 

Hlavní výhody tohoto řešení

  1. Můžete takto debugovat skripty, jejichž běh funguje na pozadí, nemají (nebo ani nesmějí mít) žádné debug výstupy. Typicky např. nějaký import, AJAX požadavek, webové služby.
  2. Úprava souboru pro debug je automatizovaná a tedy snadno opakovatelná a integrovatelná např. do editoru VIM – volání lze namapovat na klávesovou zkratku, kdy se skript spustí, upraví editovaný soubor, počká na provedení akce, po stisku klávesy navrátí původní soubor a otevře v okně VIMu soubor s debug logem.
  3. Upravený soubor lze použít na kterémkoli stroji bez dalších závislostí na jiné aplikace, knihovny, rozšíření PHP apod.
  4. Debugovací nástroj, stejně jako jeho výstup lze spouštět z konzole a tedy je možné jej používat vzdáleně při připojení pře SSH (opět ideálně v kombinaci s VIMem :-)).

Jistě tento způsob debugování nebude pro každého, ale ten, kdo si najde čas na tuto vlastní implementaci, získá určitě mnoho výhod. Samotná implementace není nikterak zdlouhavá. Uvedený debug skript pro PHP i pro Ruby má v obou případech kolem sta řádků. Také je pro každý jazyk trochu jiný – využívá jeho specifika a loguje informace, které jsou v daném jazyce dostupné a důležité. Pro zajímavost přikládám příklad textového výstupu debug logu pro PHP, jedná se o velice jednoduchý, ale ne moc smysluplný příklad, který jen ilustruje fungování:

Soubor test.php

  1. <?php
  2. $date = date("m-d");
  3. if ($date == "01-01") {
  4.     $msg = "Je Nový rok";
  5. } else {
  6.     $msg = "Neni Nový rok :-(";
  7. }
  8. echo $msg;
  9. ?>

Soubor /tmp/.phpdebug

  1. 26.12.2011 10:39:54 - /home/user/www/test.php
  2. ***********************
  3. #2# $date = 12-26
  4. -----------------------------------------------
  5. #3# $date  = 12-26
  6. -----------------------------------------------
  7. #6# $msg = Neni Nový rok :-(
  8. -----------------------------------------------
  9. #19# no error =
  10. -----------------------------------------------
Autor: , 2. 1. 2012

Potřebujete poradit? Kontaktujte nás

Your name *
Odesláním formuláře přijímáte naše Zásady zpracování osobních údajů.
Děkujeme za vyplnění formuláře.Odeslání formuláře se nezdařilo.