PhoneGap - Remote error logging (incl. uncaught script errors)

Catching and logging runtime errors, like script errors, in PhoneGap can be a challenge. There are several possibilities to write logs and to handle errors with different advantages and disadvantages.

First, local error logging means to create a functionality to send data to a place where someone cares about. Also this will spam the device with a text file or database, occupies memory and the question "when to send where?" has to be solved.
Second, remote debugging using debug.phonegap.com does not store data persistently, as it is also meant for developing popurses, not for live mode logging.

Third, to be independent from used frameworks (like JQuery, PhoneGap itself), the error may be thrown in there, I wrote a little plain vanilla Javascript logger method which uses windows.onerror to send errors to a server. It also has a little switch to distinguish between development mode (desktop browser) and live mode (PhoneGap open the files via file://). Besides a simple string text message, also objects can be passed, for more detailed information. If the log level is set to "trace", a stack trace will be included.


/**
 * Global logging method
 * 
 * @param String msg The message to log
 * @param Object obj Any plain object
 * @param String level TRACE, DEBUG, ERROR, WARN
 */
function errorLogger(msg, obj, level) {

  "use strict";

  if (!level) {
    level = 'log';
  }

  var trace = "";
  if (level === 'trace') {

    try {
      throw new Error("tmp");
    } catch (e) {
      msg = msg + " \n" 
                + e.stack ? 
                  e.stack : 
                  e.sourceURL + ":" + e.line;
    }
  }

  // Developing in desktop browser
  // using console.log, console.error,...
  if (window.location.href.indexOf("http://") > -1 
   || window.location.href.indexOf("https://") > -1) {

    console[level !== 'trace' ? level : 'debug'](msg);
    if (obj) {
      obj = JSON.stringify(obj, null, " ");
      console[level !== 'trace' ? level : 'debug'](obj);
    }

  // Live mode in PhoneGap container
  } else {

    // Add a timestamp
    var now = new Date();
    var stamp = [
        (now.getHours().length < 10 ? 
           '0' + now.getHours() : 
            now.getHours()),
        (now.getMinutes() < 10 ? 
           '0' + now.getMinutes() : 
            now.getMinutes()), 
         now.getMilliseconds()].join(".");
    msg = "[" + stamp + "] [" + level.toUpperCase() + "] " + msg;

    // Build request
    var xmlHttp = new XMLHttpRequest();
    var param = 'message=' + encodeURI(msg);
 
    if (obj) {
      param += '&obj=' + 
        encodeURI(JSON.stringify(obj, null, " "));
    }

    // send to server
    xmlHttp.open("GET", 
                 'https://HOST/PATH/TO/SCRIPT/?' + param, 
                 true);
    xmlHttp.send(null);
  }
}


Register global error handler

/**
 * General error handling
 */
window.onError = function(errorMsg, url, lineNumber) {

  "use strict";
  // Call error logger, including a stack trace
  errorLogger("Script error", 
                {errorMsg: errorMsg, 
                 url: url, 
                 lineNumber: lineNumber}, 
              "trace");

  // Do not break let the default handler run.
  return false;
};


PHP remote script
Just a very simple PHP, file based error log:

<?php

function error_log() {
 
  $msg = isset($_REQUEST["message"])?$_REQUEST["message"]:false;
  $obj = isset$_REQUEST["obj"])?$_REQUEST["obj"]:false;
  $logfile = APPLICATION_PATH_LOG . "mobile.log";
 
  $msg = "\n\n" . $msg;
  error_log($msg, 3, $logfile);
 
  if($obj) {

    if(is_array($obj)) {
      $obj = print_r($obj, true); 
    }
    error_log($obj, 3, $logfile);
  }
}

1 comment:

  1. Great article. If you are looking for a service, you can try https://www.atatus.com/javascript-error-tracking which support PhoneGap and Ionic hybrid apps.

    ReplyDelete