2015. június 03.

JavaScript hibák naplózása szerver oldalon

10 perc olvasási idő

JavaScript hibák naplózása szerver oldalon

A modern böngészők óriási segítséget nyújtanak a fejlesztőeszközeikkel a JavaScript hibák feltérképezésében és javításában. Csak megnyitod a konzolt, és nyomban látsz minden fontos információt, pár kattintással odanavigálhatsz a forrásához és jobb esetben tiszta is a kép. Persze, ha ott vagy a hiba keletkezésénél…

Maga a módszer, amit boncolgatok nem újkeletű, már évekkel ezelőtt is felvetődött, és konkrét szolgáltatások is léteznek a probléma megoldására. Mégis úgy gondoltam manapság ez méginkább aktuális, hiszen webappok esetén több a hibalehetőség, és nem minden platform támogatja még a megfelelő hibakeresést. A Chrome for Android egy kellemes kivétel, ahol a remote debugging jóideje segít a hibák feltérképezésében és javításában, de sajnos nem minden platformon adatott meg ez a lehetőség.

Az elv

Az elv roppant egyszerű, és kb. magától értetődő: a felbukkanó JavaScript hibákat kell elkapni és továbbítani a szervernek a lehető legtöbb környezeti paraméterrel együtt. Így utólag visszakereshető, szűrhető és minden fontos információ kinyerhető a hibát generáló eszközt illetően is.

A megvalósítás

A JavaScript hibák lekezelésének alapja a window.onerror esemény. Minden, a weboldalon bekövetkező hiba esetén meghívásra kerül ez az esemény, így el lehet kapni a hibát, annak helyét és egyéb paramétereit. Öröm az ürömben, hogy ahány JavaScript motor, annyiféle lehetséges visszatérési értéke van az onerror eseménynek. Pontosabban, nem minden esetben kapsz meg minden adatot:


window.onerror = function (errorMsg, url, lineNumber, column, errorObj) {}

  • errorMsg (string) : Az interpreter által adott hibaüzenet. Szerencsére, a modern böngészők már informatívabban kezelik a régi „undefined is not a function” problémát, és visszakapod a meghívott függvény nevét, így könnyebben beazonosíthatod azt.
  • url (string) : Az url, ahol a hiba keletkezett
  • lineNumber (int) : A script sora, ahol a hiba keletkezett
  • column (int) : a pozíció (karakterszám), ahol a hiba keletkezett
  • errorObj (object) : hibaobjektum

Fontos megjegyezni, hogy az utolsó két paramétert nem minden böngésző adja vissza. Windows Phone (Internet Explorer) és iOS (Safari) eszközök nem támogatják, viszont a Chrome, Chrome for Android esetén megkapod, így érdemes foglalkozni velük.

Az így elkapott hibákat AJAX hívással elposztolod egy PHP fájlnak, ami feldolgozza és eltárolja azokat, a neked megfelelő formában. A legegyszerűbb megoldás, ha a PHP fájl is a saját szervereden van, így kevésbé kavar be egyes böngészők (teljesen jogosan támasztott) Same-origin policy-je. Az alábbi kód ezt valósítja meg:


<script type="text/javascript">
window.onerror = function (errorMsg, url,
lineNumber, column, errorObj) {
    if (errorMsg.indexOf('Script error.') > -1) {
        return;
    }
    var text = 'Err: ' + errorMsg + ' | Script: '
    + url + ' | Ln: '
    + lineNumber    + (column ? ' | Clmn: '
    + column : '') + (errorObj ? ' | Stacktrc: '
    +  errorObj : '');
    var r = new XMLHttpRequest();
    var params = "d=" + encodeURIComponent(text);
    r.open("POST", "jslogger.php", true);
    r.setRequestHeader("Content-type",
    "application/x-www-form-urlencoded");
    r.setRequestHeader("Content-length",
    params.length);
    r.setRequestHeader("Connection",
    "close");
    r.send(params);
}
</script>

A Script error ellenőrzése azért van benne, mert némely böngészők CDN-ről behúzott fájlok esetén nem közlik a hiba konkrét okát és helyét csak az előbb említett hibaüzenetet, amivel valljuk be, sokat nem lehet kezdeni. Megkerülhető a dolog, ahogy azt ebben a cikkben ki is fejtik, viszont én az egyszerűbb megoldást választottam.

A PHP script faék egyszerűségű. A POST metódussal megkapott stringet eltárolod egy időbélyeggel a SERVER tömbböl kiszedett user agenttel együtt az adott fájl egy-egy sorába. Ez a rész még sok lehetőséget rejt magában, mind tárolási módot, mind a letárolt adatokat illetően, viszont így is kellő információhoz juthatsz a felmerülő hibákkal kapcsolatban.


<?php
 if ($d = addslashes(strip_tags(trim($_POST['d']))))
 {
   file_put_contents('jserror.log',
   date('y-m-d H:i : ').$d.' | UA: '
   .$_SERVER['HTTP_USER_AGENT']."\n",FILE_APPEND);
 }
?>

További lehetőségek

Az imént taglalt kódsorok sajnos nem fednek le minden esetet. Például AngularJS és egyéb frameworkok hibáit már nem mentik el, viszont erre is van külön megoldás.

A fenti megoldásokat egy eléggé JS-érzékeny projektünk nehezen megmagyarázható anomáliája ihlette, amikor már csak arra tudtunk gondolni, hogy valamelyik eszközön valami általunk eddig nem tapasztalt JavaScript hiba léphetett fel és ez akasztotta meg az oldal működését. Szerencsére be is igazolódott a dolog, relatíve rövid idő alatt megkaptuk a hibát és javítani is tudtuk. Minden bizonnyal még igényelne további finomításokat és kiegészítéseket az eljárás, ezt viszont már rád bízom és várom a felvetéseket. :)

Tóth Zoltán

Vezető fejlesztő. Közel tíz éve foglalkozik webfejlesztéssel, igyekszik egyaránt backend és frontend területen is képben lenni. WordPresspárti, böngészőkiegészítő- és bookmarkletgyűjtő.

Tóth Zoltán

Hozzászólások