Autor Zpráva
petr.hudik
Profil
Dobrý den,

už jsem si tak zvykl, že když se na serveru v PHP přihodí nějaká chyba, tak mi Nette vygeneruje moc hezkou laděnku - díky které se nejen o chybě dozvím, ale zároveň se dozvím i bližší informace o chybě. Na stránkách používáme velké množství JS kódu a bohužel občas se nějaká chybka objeví - rád bych ji zalogoval a někam odeslal. Máte s tím nějakou zkušenost? jak tento problém řešíte?

Samozřejmě, stačí trochu googlit a člověk narazí na spoustu nástrojů, některé si můžete napsat sami (např. openmymind.net/2012/4/4/You-Really-Should-Log-Client-Side-Error), nebo použít již hotové řešení: gist.github.com/cheeaun/5835757 Máte s některým konkrétní zkušenosti? jak Vám funguje?

Osobně jsem jich zkoušel několik - nyní testují www.getsentry.com - vypadá to supr, ale v logu se mi hromadí velké množství "těžko vysvětlitelných" chyb. Například syntax errory, kdy chybí koncová závorka apod. ale soubor ve kterém se chyba nachází je sloučený a mimofikovaný již při deploymentu - taková chyba by se asi musela projevit častěji. Navíc vím, že zákaznící aplikaci používají a (z větší části) funguje. Je nějaký způsob jak vysvětlit podobné chyby? jak byste postupovali při hledání?

Díky za každý názor.
Kcko
Profil
petr.hudik:
Taky Sentry a stejně jako ty množství chyb ignoruji, protože se jedná o blbosti, které Sentry špatně přelouská v zminifikovaných a sloučených souborech. Občas se tam podívám a řeším závažné věci. A taky nevím jak to pořádně nastavit (resp zatím jsme to do hloubky neřešili = firma).
Chamurappi
Profil
Reaguji na petra.hudika:
Také si vzpomínám na svůj úžas, když jsem při logování onerrorů zjistil, co všechno se u lidí rozbíjí.
Opravdu platí, že všechno, co se může pokazit, se při dostatečné návštěvnosti u někoho někdy pokazí. Většina frontend-vývojářů je na můj vkus až příliš málo paranoidní :-)

Je nějaký způsob jak vysvětlit podobné chyby?
1) Nedotažený JS. Pokud na stránce nejsou reklamy, nemusí být špatný nápad vyvolat při syntaktické chybě jednou location.reload(true).
2) Proxy servery. Prohlížeče běžně načtou JS, i když je poslán jako text/html, ale proxy server může do HTML zasahovat. U AJAXu s JSONem posílaným jako text/html může být také podobný problém.
3) Nějaké agresivní rozšíření v prohlížeči. Adblock patří v tomto ohledu do kategorie těch slušnějších.
4) Sám prohlížeč v sobě může mít chyby, které se projeví událostí onerror. V mobilních prohlížečích nebývají chybové konzole, proto si jich ani jejich vývojáři nevšimnou – třeba Safari v iOSu občas zkoušelo volat atomicFindClose().
petr.hudik
Profil
Děkuji za odpovědi. "Jsem rád", že množství chyb nezaskočilo jen mě. V každém případě JS je pro náš web kriticky důležitý a tak se musím do problému pořádně ponořit. (jedná se o webovou aplikaci a bez JS si uživatel ani neuprdne)

Reaguji na Chamurappi:
1) Nedotažený JS.

Osobně si myslím, že většina syntax errorů bude způsobena tím, že se skript nestáhl kompletní. Ale divím se, že by to prohlížeč sám nepoznal a pokusil se parsovat soubor, který není kompletní. Nemáte k tomu bližší informace, jak to detekovat? dá se to případně nasimulovat - vyzkoušet?

Na stránce máme includovaný jQuery z CDN a jeden sloučený, mimifikovaný soubor, když se pokusím v Chrome snížit rychlost načítání, vymazat cache, a v průběhu načítání internet zastavit, tak se soubor nenačte vůbec, tj. nevyvolá se žádná syntax error.

Nyní jsem vložil úplně na konec toho souboru řádek, který změní proměnnou js-loaded='yes', která informuje, že se JS načetlo. Tuhle proměnnou si posílám do www.getsentery.com, pokud tyto chyby jsou skutečně způsobené nekompletním načtením JS, tak by do logu měly padat chyby s js-loaded='no'. Nebo se pletu?

2) Proxy servery.

Daný soubor zasílám jako Content-Type:application/javascript, odpovědi na AJAX také... Na stránce není nějaký inline JS nebo JS vložený do stránky (vyjma toho logování). Je ještě něco jak to ověřit? nebo

3) Nějaké agresivní rozšíření v prohlížeči. Adblock patří v tomto ohledu do kategorie těch slušnějších.

S Adblockem mám své zkušenosti, stránky není testuji i s ním.

Napadají Vás ještě nějaká rozšíření, která by mohli stránku nepříjemně ovlivnit?

Je možné zalogovat jaká rozšíření uživatel používá? Vygooglil jsem navigator.plugins, ale zdá se, že mi to nevypisuje všechny (a některé rozhodně do stránky zasahují)...
_es
Profil
petr.hudik:
většina syntax errorů bude způsobena tím, že se skript nestáhl kompletní.
Prehliadač začne JS spracovávať až vtedy, keď je celý obsah elementu script dostupný, či už celý externý súbor alebo text medzi <script> a </script>. Ak sa nestiahne súbor celý, tak je to rovnaká chyba, ako by sa nestiahol vôbec. Prípadne môže server namiesto skriptu odoslať nejakú chybovú stránku, čo spôsobí syntaktickú chybu v JS. Možno sú však nejaké prehliadače, čo by za celý obsah elementu považovali aj neúplne stiahnutý súbor v dôsledku nejakej sieťovej chyby, no to sa mi nezdá.

Vygooglil jsem navigator.plugins
To sú iné typy „rozšírení“, napríklad Flash, Java a pod. - je málo pravdepodobné, že by spôsobovali problémy v JS, no ak ich na stránkach používate, možné to je. Spomínaný Adblock patrí medzi „Extensions“ - tie sú často zistiteľné len nepriamo.

Môže byť aj to, že ide o skripty, ktoré v niektorých prehliadačoch chybu vyvolajú, možno len niekedy, a v iných nie. Hlavne ak sa tam „nacápe“ plno rôznych „vylepšujúcich“ vecí, čo nie sú nutne treba. Rôzne skripty si môžu navzájom „vadiť“ a pod....

Ešte môže nastať aj chyba v dôsledku vysokého vyťaženia počítača návštevníka od JS. Prehliadač môže ponúknuť zastaviť pridlho bežúci skript.

Z rád v [#3] od Chamurappiho: Skotroloval si HTTP hlavičky všetkých externých JS súborov, či nemajú typ text/html?

Na stránce máme includovaný jQuery z CDN
To ako že sa načítava z iného servera ako stránka? Nie je to priveľké riziko, vzhľadom na to, že je JS „kriticky důležitý“? Od natiahnutého jQuery bude asi závisieť funkčnosť väčšiny vašich skriptov, či nie?
petr.hudik
Profil
_es:
Děkuji za odpověď.

Prehliadač začne JS spracovávať až vtedy, keď je celý obsah elementu script dostupný, či už celý externý súbor alebo text medzi <script> a </script>. Ak sa nestiahne súbor celý, tak je to rovnaká chyba, ako by sa nestiahol vôbec. Prípadne môže server namiesto skriptu odoslať nejakú chybovú stránku, čo spôsobí syntaktickú chybu v JS. Možno sú však nejaké prehliadače, čo by za celý obsah elementu považovali aj neúplne stiahnutý súbor v dôsledku nejakej sieťovej chyby, no to sa mi nezdá.

Ano, také se mi to nezdá, ale v v současné době to považuji za nejlepší vysvětlení :-). Spustil jsem ten test s proměnnou js-loaded, uvidíme jaké chyby tam budou padat.

Skotroloval si HTTP hlavičky všetkých externých JS súborov, či nemajú typ text/html?

Ano. Pokud zvolím v Chrome "Nástroje pro vývojáře", vyberu záložku "Network", reloadnu stránku, najdu JS soubor, tak v Response Headers vidím Content-Type:application/javascript. Stačí to takto? mohu to zkontrolovat ještě jinak?

To ako že sa načítava z iného servera ako stránka? Nie je to priveľké riziko, vzhľadom na to, že je JS ‚kriticky důležitý‘? Od natiahnutého jQuery bude asi závisieť funkčnosť väčšiny vašich skriptov, či nie?

Používáme načítání, kdy se soubor pokusí stáhnout z CDN, pokud to nevyjde, tak se načte z naše kopie, viz např. github.com/twbs/bootstrap/blob/master/docs/examples/starter-template/index.html#L70-L71 Mohu říct, že toto řešení se nám osvědčilo, častěji se jQuery načte rychleji - navíc dříve, když jsme includovali jen lokální verzi, nám do logu padalo hodně chyb typu $ není definovaný, nyní se to nestává.
_es
Profil
petr.hudik:
dříve, když jsme includovali jen lokální verzi, nám do logu padalo hodně chyb typu $ není definovaný, nyní se to nestává.
Nenastávalo niekedy preťaženie servera? Že sa nenatiahli všetky súbory a zhodou okolností niekedy práve súbor jQuery? Rôzne prehliadače môžu súčasne pracovať na rôznom počte pripojení a ak ich je priveľa, tak môže server niektoré odmietnuť, napríklad nastane prekročenie limitu na jedného klienta. Alebo pri pomalom pripojení môže prehliadač pri dlhom čakaní na súbor to čakanie vzdať.
Chamurappi
Profil
Reaguji na _es:
Ak sa nestiahne súbor celý, tak je to rovnaká chyba, ako by sa nestiahol vôbec.
Určitě? Máš to vyzkoušené?
Už jsem několikrát viděl nedotaženou HTML stránku a nedotažený obrázek a jednou kdysi i nedotažené CSS – v jejich případě si prohlížeč řekne „není to celé, tak co se dá dělat, zkusím rozebrat to, co mám“. Dávalo by smysl, že si to u JS neříká, protože nekompletní JS bude skoro určitě syntakticky špatně (podobně jako nekompletní XML) a spouštět blok před kompletním stažením nejde. Opravdu si to neříká?

Je také otázka, jestli prohlížeč vždy ví, že je nekompletní odpověď nekompletní. Za běžného stavu s Content-Length apod. to asi ví, ale opět může být v cestě nějaký méně rozumný proxy server, který si stáhne nekompletní data a ta pak dál předává jako kompletní.


Reaguji na petr.hudika:
Napadají Vás ještě nějaká rozšíření, která by mohli stránku nepříjemně ovlivnit?
Existují různá invazivní zlá rozšíření, která si lidi neinstalují úmyslně, nebo která byla původně hodná a zaprodala se. Ta třeba přidávají reklamy do stránky, nebo nějak jinak necitlivě vylepšují obsah.

Je možné zalogovat jaká rozšíření uživatel používá?
Ne, je to jeho soukromá záležitost.
Ale můžeš zkusit navázat s nebohým uživatelem dialog v okamžiku syntaktické chyby – říct mu, že se něco pokazilo a ať se ti ozve na e-mail, že mu za to dáš třeba fidorku, pokud ti pomůže odhalit příčinu chyby.

navíc dříve, když jsme includovali jen lokální verzi, nám do logu padalo hodně chyb typu $ není definovaný, nyní se to nestává
To je nějaké divné. CDN by neměla být spolehlivější než lokální verze, spíš naopak.
_es
Profil
Chamurappi:
Už jsem několikrát viděl nedotaženou HTML stránku a nedotažený obrázek a jednou kdysi i nedotažené CSS – v jejich případě si prohlížeč řekne ‚není to celé, tak co se dá dělat, zkusím rozebrat to, co mám‘.
Ale HTML aj obrázky sa spracúvajú a aj zobrazujú priebežne ešte počas načítania, takže je logické, že ak sa načítavanie preruší, tak to, čo sa doteraz zobrazilo, zostane zobrazené - to môže platiť aj pre CSS. V prípade JS kódu je priamo v špecifikácii, že sa má začať spracovávať až kompletný kód (v rámci jedného elementu script). Je napríklad jedno, či je príkaz var premenná; na konci alebo začiatku skriptu - premenná existuje už na začiatku kódu.

Je také otázka, jestli prohlížeč vždy ví, že je nekompletní odpověď nekompletní.
No na rozdiel od HTML kódu a obrázka musí byť nejaký „impulz“ na spracovanie JS kódu, ktoré má nastať až pri kompletnom kóde. Teoreticky možno môže nastať chyba, že prehliadač mylne pokladá nedotiahnutý JS za kompletný. Alebo, ako píšeš, informáciu o kompletnosti pozmení proxy server - no to asi len keď je HTTP hlavička nesprávne ako HTML obsah.

petr.hudik, [#4]:
Nyní jsem vložil úplně na konec toho souboru řádek, který změní proměnnou js-loaded='yes', která informuje, že se JS načetlo. Tuhle proměnnou si posílám do www.getsentery.com, pokud tyto chyby jsou skutečně způsobené nekompletním načtením JS, tak by do logu měly padat chyby s js-loaded='no'. Nebo se pletu?
Ak chceš otestovať, či prehliadač začal spracovávať neúplne stiahnutý JS súbor, tak to takto spoľahlivo neotestuješ. Dalo by sa to napríklad:
try{premennná}catch(e){tento kód sa spustí v prípade, že prehliadač spustil neúplne stiahnutý súbor}
kód skriptu
var premenná;
Aspoň by sa otestovalo tvrdenie z [#5]. Ak chceš takto otestovať viac skriptov na tej istej stránke, nazvi premennú v každom skripte inak.
petr.hudik
Profil
Děkuji za odpovědi!

_es:
Nenastávalo niekedy preťaženie servera? Že sa nenatiahli všetky súbory a zhodou okolností niekedy práve súbor jQuery?

Výkon serveru monitorujeme, nic jsem nezaznamenal.

Chamurappi:
Ale můžeš zkusit navázat s nebohým uživatelem dialog v okamžiku syntaktické chyby

Přihlášeným uživatelům jsem zkusil napsat e-mail, uvidíme, jak to dopadne.

_es:
Ak chceš otestovať, či prehliadač začal spracovávať neúplne stiahnutý JS súbor, tak to takto spoľahlivo neotestuješ.

Omlouvám se, trochu jsem to zjednodušil, využívám tagy v Sentry, když sentry vytvářím tak mu nastavím tag js-loaded='no' a na konci spojeného JS souboru ho nastavím na na yes. Pokud by první nastavení neproběhlo v pořádku, tak by tam tag prostě nebyl, pokud by neproběhlo v pořádku druhé nastavení tak by měl valstnost no, to by ale mohlo stačit, nebo se pletu?

To nás vede k tomu, že když si vyfiltruju všechny chyby s tagem js-loaded='no', tak mi to zobrazí docela směsku:

- [object Event] (2x)
- SyntaxError: Unexpected end of input (12x)
- Unterminated comment
- ReferenceError: Chart is not defined (chart je knihovna, která je integrovaná v daném souboru)
- Byl očekáván znak '}'
- ReferenceError: playSounds is not defined 13x (playSound je funkce v daném souboru)
- SyntaxError: missing name after . operator
- SyntaxError: missing ) after argument list (7x)
- Objekt tuto vlastnost nebo metodu nepodporuje. (8x)

Všechny chyby jsou samozřejmě v tom mimifikovaným souboru, nacházejí se na různých stránkách, ale nejčastěji na titulce (30 %). Stejnou chybu má (asi) stejný uživatel, nevidím tam žádné křížení (kde by jednu chybu mělo více uživatelů).

Teď nastává otázka, zda je vůbec možné tyto chyby odstranit? zda se opravdu jedná tedy o chyby, které jsou spojeny s neúplným načtením stránky, zlou proxy, či ošklivým rozšířením - co si o tom myslíte? jak byste dál postupovali?
_es
Profil
petr.hudik [#10]:
Ale tým vôbec neotestuješ to, o čom sme sa bavili, či môže alebo nemôže (prakticky) nastať spustenie neúplne načítaného JS súbora. Ak je napríklad v súbore:
neexistujúcaFunkcia();
alert("koniec");
tak k zavolaniu funkcie alert vôbec nedôjde. Ďalej píšeš o „premennej js-loaded“, ale tak sa predsa premenná volať nemôže. Príkaz var js-loaded='yes'; je syntaktickou chybou.
To, či sa spustil neúplne načítaný súbor, otestuješ napríklad podľa návodu v [#9], konkrétne to, či premenná definovaná na konci existuje aj na začiatku, teda či prebehla prvá fáza spracovania JS kódu s celým kódom. Daj odoslanie chybovej správy do bloku catch - je jedno, ako správy odosielaš, či vlastným spôsobom, alebo nejakými skriptami na ten účel.
Chamurappi
Profil
Reaguji na _es:
V prípade JS kódu je priamo v špecifikácii, že sa má začať spracovávať až kompletný kód (v rámci jedného elementu script).
Ano, to si uvědomuji. Ale parser v té první fázi, kdy se zpracovává syntaxe a vytvářejí se proměnné, může začít pracovat dřív, než je skript kompletní. Jediný nežádoucí projev této optimalizační nedočkavosti by byly právě tyto zachytitelné syntaktické chyby, ne? (Protože syntaktické chyby, vyjma evalu, vznikají před spuštěním kódu.)
Skutečně by bylo lepší provést nějaké testy, ale momentálně mě nenapadá snadný a rychlý způsob, jak to vyzkoušet. Str4wberry může něco vymyslet a napsat o tom článek :-)

Ďalej píšeš o ‚premennej js-loaded‘, ale tak sa predsa premenná volať nemôže.
Také o ní píše jako o tagu. Tipnul bych si, že to ve skutečnosti bude atribut, který má nastavený v HTML, přenastavuje ho v externím JS a čte ho v logujícím JS. Kdyby měl v kódu opravdu var js-loaded, nedošel by k informacím, které později zmiňuje (krom toho by musel mít podstatně horší znalosti JS, než soudě dle příspěvků má).


Reaguji na petr.hudika:
Ještě bych úplně nezavrhoval možnost chyby serveru. Je stoprocentně vyloučené, že by server někomu poslal neúplný soubor? Šlo by to ověřit tím, že skript přesuneš na úplně jiný stroj a jinou doménu. Chybě serveru by nasvědčovalo i to, že jQuery z CDN funguje spolehlivěji než lokální.

Stejnou chybu má (asi) stejný uživatel
Patrně má tu nekompletní verzi skriptu nakešovanou, takže mu spadne při každé návštěvě.

Teď nastává otázka, zda je vůbec možné tyto chyby odstranit?
Pokud znovunačtení nemá vedlejší účinky, zkusil bych vyvolat u návštěvníka Ctrl+F5, tedy location.reload(true). Prohlížeč při tomto silnějším reloadu (krom toho, že ignoruje vlastní keš) posílá další HTTP hlavičky, kterými říká všemu po cestě, že se nemá číst z keší. Aby uživatel neskončil v nekonečné smyčce reloadů, můžeš podle těchto hlaviček poznat, že je stránka takto znovunačtená a nedat do ní podmínku na další location.reload(true) při chybě.
_es
Profil
Chamurappi:
Ale parser v té první fázi, kdy se zpracovává syntaxe a vytvářejí se proměnné, může začít pracovat dřív, než je skript kompletní.
Ale „druhá fáza“ nastáva až po prvej a tá môže skončiť, až keď je súbor kompletný, takže z toho stále vyplýva len to, že neúplný súbor by nemal byť spustený, teda mať nejaký vplyv na objekty stránky.

Také o ní píše jako o tagu....
Takže testuje niečo úplne iné, než si myslí, že testuje. Testuje asi, či bol vykonaný nejaký príkaz na konci kódu, čo má veľmi ďaleko od testovania toho, či sa súbor spustil kompletný. Či prebehla spomínaná „prvá fáza“ s kompletným kódom by mohol otestovať podľa návodu v [#9], tam predsa ten HTML atribút môže meniť tiež, nie? Také testovanie by mohlo byť nesprávne snáď len vtedy, keby bol kód skriptu nejako syntakticky nezmyselný, no to by asi nefungoval v žiadnom prehliadači.

Teraz ma napadlo, že „prvá fáza“ možno tiež zapisuje do chybovej konzoly. Zachytáva petr.hudik aj chyby, že nastala „prvá fáza“, no už nie „druhá fáza“ spracovania JS? Teda ak by prehliadač začal prvú fázu ešte pred kompletným načítaním?
petr.hudik
Profil
Děkuji za odpovědi.

Jsem PHP programátor, JS píšu spíš z "nutnosti" a je možné, že mi některé základní koncepty unikají. A právě, pokud se na to podívám optikou PHP, tak byl velký šok, když jsem viděl množství chyb, které mi nedávají smysl (např. to, že chybí závorka, na to bych přece přišel).

Ještě bych měl poznamenat, že stránky intenzivně testujeme - používáme DalekJS, který prochází všechny důležité use-case v chrome, IE a FF. Používáme kontinuální integraci (CI) a stránky testujeme na několika fyzických zařízení a další use-case testujem v emulovaných zařízeních. Právě proto nerozumím tomu, proč tam tyto chyby padají.

Je třeba říct, že se mi NIKDY žádnou podobnou událost nepodařilo nasimulovat, na žádném počítači (prohlížeči), nebo mobilním zařízení k ní nedošlo.

Ještě jednou se omlouvám za to nedorozumění s proměnnou, tagem. Chtěl jsem to zjednodušit, abychom se nebabrali v jednotlivostech.

_es:
Takže testuje niečo úplne iné, než si myslí, že testuje. Testuje asi, či bol vykonaný nejaký príkaz na konci kódu, čo má veľmi ďaleko od testovania toho, či sa súbor spustil kompletný.

Představoval jsem si, že skript bude zpracovaná v následujícím pořadí:

1) nakonfiguruje se logovátko, nastaví se tag js-loaded='no'
2) začne se načítat skript
3) nastane syntaktická chyba - vyvolá se událost onerror, kterou (magicky) zachytí logovátko
4) protože logovátko má stále nastaven tag js-loaded na no, tak se zaloguje
5) (volitelné) dojde k přepsání tagu, js-loaded='yes'
6) při další chybě by do logu padaly záznamy s js-loaded na yes

Vím, že mi do logu padají záznamy, které mají js-loaded='no'. Proto předpokládám, že k událostem dochází v tomto pořadí. Otázka je co z toho můžeme usuzovat. Co můžeme usuzovat o chybách typu: "SyntaxError: missing ) after argument list" apod.?

PS: obrátil jsem se na několik uživatelů, na které mám e-mail a zatím všechny reakce byly, že uživatelé si žádného podezřelého chování ani nevšimli.

Vaše odpověď

Mohlo by se hodit

Neumíte-li správně určit příčinu chyby, vkládejte odkazy na živé ukázky.
Užíváte-li nějakou cizí knihovnu, ukažte odpovídajícím, kde jste ji vzali.

Užitečné odkazy:

Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm: