Nette\Debug – callback?

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
jtousek
Člen | 951
+
0
-

Zdravím,

potřeboval bych nějak docílit, abych při zachycení chyby (v produkčním módu) mohl odeslat na výstup uživateli jednoduchou hlášku o tom, že nastala chyba a bylo odesláno nějaké upozornění vývojářům – samozřejmě kompletní chybovou hlášku nezobrazovat v žádném případě. Tzn. potřeboval bych do laděnky nastavit jakýsi callback, který by tuto hlášku pro uživatele generoval. A úplně ideálně bych potřeboval odeslat vývojáři e-mailem odkaz na kompletní HTML kód který laděnka generuje a loguje (anebo to hodit rovnou do mejlu či jako přílohu).

Zatím mi to připadá, že laděnka chyby v produkčním módu prostě schová a zaloguje, ale jak říct uživateli „něco je špatně, pracujeme na tom…“?

Ještě ideálnější by bylo rozlišit vývojáře (např. podle IP) a tomu rovnou zobrazit odkaz na vygenerované html chyby (tyto html bych ukládal do zvlášní složky, kde by v .htaccess bylo deny pro všechny kromě právě toho vývojáře). Proč to HTML nehodit pro vývojáře rovnou na výstup? – Kvůli ajaxu – kompletní report by se hodil i u těchto požadavků, ale ve firebugu je to jen zjednodušené.

Btw. proč je třída Debug final? Zrovna v tomhle případě by se expand laděnky docela hodil…

Honza Kuchař
Člen | 1662
+
0
-

Na vlastní chybové hlášky je ErrorPresenter.

Petr Motejlek
Člen | 293
+
0
-

Otázká má tak trochu dvě části, tak si dovolím odpověď rozdělit:

Přesně to, co popisuješ, Laděnka běžně dělá, když je správně nastavená ;). Do bootstrapu si před $application->run() přidej

<?php
  $application->errorPresenter = 'Error';
  $application->catchExceptions = Environment::isProduction();
?>

To nastaví, že když dojde k výjímce a aplikace je v produkčním režimu, tak Laděnka výjímku chytne. Tím errroPresenter se nastavuje presenter, kterému je předána obsluha v případě výskytu takové neodchycené výjímky. Kód toho presenteru nemusí být nijak složitý, stačí například něco jako

<?php
class ErrorPresenter extends Presenter {
    public function renderDefault($exception) {
        if ($this->isAjax()) {
            $this->getAjaxDriver()->events[] = array('error', $exception->getMessage());
            $this->terminate();
        }
        else {
            if ($exception instanceof BadRequestException) {
                Environment::getHttpResponse()->setCode($exception->getCode());

                $this->setView('404');
            }
            else {
                Environment::getHttpResponse()->setCode(500);
                $this->setView('500');

                Debug::processException($exception, Environment::isDebugging());
            };

        };
    }
}
?>

Tehnle presenter podle typu chyby buď jen zobrazí stránku upozorňující na chybu v adrese (klasická 404) – tu není potřeba nijak logovat. Všechny ostatní chyby se logují – to dělá ten řádek Debug::processException(), a šablona, která se vykresluje, je taky trochu jiná u 404 než u ostatních. Pokud chceš posílat i maily, atd. dá se tuším pomocí třetího parametru Debug::processException nastavit e-mail, kam se má všechno o té výjímce poslat. Já si to neposílám, já si pravidelně čtu logy, ale tuším, že Laděnka dokonce i pozná, že jde o naprosto stejnou výjímku a tudíž nebude posílat e-mail tolikrát, kolikrát k ní dojde, ale jen jednou.

Pokud chceš vývojářům ukazovat chyby, není IMHO nic jednoduššího, než si do config.ini nadefinovat nové prostředí, které bude de facto totožné s tím, co máš jako produkční, ale nastavíš u něj mode.debug = true a mode.production = false. Potom si v bootstrapu ještě před nastavením ErrorPresenteru uděláš test na IP adresu aktuálně připojeného klienta a uděláš Environment::setName(jménoTohoProstředí). Laděnka bude automaticky vypisovat chyby hned v prohlížeči, nikam se nebude posílat e-mail, protože se ErrorPresenter ani ke slovu nedostane… Tohle bych ale nedoporučoval dělat, protože i IP se dá podvrhnout…

vlki
Člen | 218
+
0
-

Jen doplním těch pár nejistých míst.

Pro zasílání emailu při zachycení výjimky je potřeba uvést daný mail jako třetí parametr statické metody Debug::enable().

Email se odešle při prvním zachycení a do složky s logy vytvoří soubor [název logu].monitor. Další emaily nebude posílat do té doby, než bude ten soubor odstraněn.

jtousek
Člen | 951
+
0
-

Díky všem za odpovědi. Nevěděl jsem, jak přesně se pracuje s tím ErrorPresenterem takže díky moc za názorný příklad. Nakonec jsem to vyřešil ještě trochu jinak podle svých představ – použil jsem production mód, soubor .log se mění podle data (nemusím myslet na mazání .monitor – prostě se mi případná chyba pošle jednou za den). Dále v ErrorPresenteru odešlu výstup s odkazem (jen pokud IP odpovídá mé IP) na soubor, který vygeneruje Debug::processException($e). Tyhle soubory jsou samozřejmě chráněné .htaccess (IP) a .htpasswd (autentizace). Výsledkem je, že chyba se mi přímo nezobrazí nikdy, zato se mi vždy zobrazí odkaz na podrobný report (ať už šlo o ajaxový požadavek nebo ne).

Editoval jtousek (13. 12. 2009 0:35)

jtousek
Člen | 951
+
0
-

Tak jsem zjistil, že to stejně není úplně optimální – co když někde nastane např. parse error? V takovém případě se sice zaloguje chyba, ale zavolání ErrorPresenteru se přirozeně nekoná. Je i v tomto případě nějaké řešení (jiné než přímo upravit zdroják laděnky)?

redhead
Člen | 1313
+
0
-

Já bych teda na svět nevypustil nic, co by mělo v sobě parse error.. ;)

jtousek
Člen | 951
+
0
-

…samozřejmě, ale když se pak stane že web nefunguje, nic se nevypíše tak se pak hledá hodně blbě

Tomik
Nette Evangelist | 485
+
0
-

Parse error by měl být přirozeně odhalen už při vývoji. Neboť při testech by mělo dojít ke spuštění VŠECH zdrojových kódů – tudíž parse bude odhalen. Pouštět na produkční něco, co jsem si ani nepustil v prohlížeči (nemluvě o automatických testech, třeba PHPUnit) by se nemělo dělat. :)

jtousek
Člen | 951
+
0
-

Tomik: já to myslel trochu jinak… původní záměr byl, abych při ajaxovém požadavku, který skončil chybou získal odkaz na soubor, který laděnka vygenerovala – což se ovšem děje jen v produkčním módu. Jinak je aplikace stále ve vývoji. Prostě chci po laděnce asi něco trochu jiného, než na co je stavěná. :)

Ondřej Mirtes
Člen | 1536
+
0
-

jtousek napsal(a):

Tomik: já to myslel trochu jinak… původní záměr byl, abych při ajaxovém požadavku, který skončil chybou získal odkaz na soubor, který laděnka vygenerovala – což se ovšem děje jen v produkčním módu. Jinak je aplikace stále ve vývoji. Prostě chci po laděnce asi něco trochu jiného, než na co je stavěná. :)

Laděnka ty error logy hází do app/log a to přirozeně má být skryté před světem pomocí deny from all v .htaccess :)

Jinak AJAX se dobře ladí přes konzoli Firebugu a FirePHP, ale zase jen na development mašině, na produkčním serveru toto všechno musí být před očima návštěvníků skryté.

jtousek
Člen | 951
+
0
-

Ondřej Mirtes:

jak jsem psal výše – konzoli firebugu používám, ale nestačí – nezískám kompletní report jako u neajaxového požadavku (nemohu si prohlédnout obsah proměnných apod.)

Ondřej Mirtes
Člen | 1536
+
0
-

Když se podíváš na záložku Síť do odezvy do podzáložky HTML, tak tam máš komplet Laděnku jako kdyby byla v okně prohlížeče :)

Honza Kuchař
Člen | 1662
+
0
-

Na prase error má laděnka taky něco: https://api.nette.org/…bug.php.html#80

Ale tomuto na výstupu se neubráníš: Parse error: syntax error, unexpected T_STRING, expecting T_FUNCTION in D:\www\00_Vyvoj\GRIFART\source\PHP\app\presenters\ZakazkyPresenter.php on line 20

I pokud nastavíš error_reporting(0); tak je to tam pořád.