9

My Situation

Hi, Im relatively new to Javascript so my question could be really easy. Im developing multiple webapps for my company. One problem I run in regularly are Javascript-errors. I know how to handly them using try/catch.

What I want to do

I want to either write a logfile on the server or give the user something they can send me without any knowledge of debugging. This means, the user has to be informed that an error occurred in both cases.

What I already did

One idea I had was using try catch and using code I found here: https://stackoverflow.com/a/6055620/3581748 to give the user the possibility to send me the stacktrace.

Example:

<button id="demo" onClick="errorHandling()">Produce error</button>
<script>
function errorHandling() {
    try {
        document.getElementById("somethingNotExisting").value * 2;
    } catch (_err) {
        window.prompt("Copy to clipboard: Ctrl+C, Enter", _err.stack);
    }
}
</script>

Or here: https://jsfiddle.net/n79xv6nt/

Which works most times.

The Problem

I sometimes embed scriptfiles in my "main"-page using jQuery. Example:

<div id="forScript"></div>
<script>
    $("#forScript").load('scripts/additionalScript.php');
</script>

If I use the above code (the one below "What I already did"). I dont get a stacktrace that tells me where the error occured. It instead points to a jQuery-file. The Google Chrome Console shows the real stacktrace. Another problem is, how do I get to the file after I got the linenumber? In my IDE the lines are different because there is php in between.

My Question

Is it possible to get a good errormessage for this case? (preferably without having to throw an error myself) How can I access the additional script and see the same linenumbers that chrome is seeing? And how would you notify the user/log the error?

Community
  • 1
  • 1
Simon Balling
  • 481
  • 4
  • 13
  • You're missing closing quote: `load('scripts/additionalScript.php)` – Bhojendra Rauniyar Nov 17 '15 at 09:54
  • Rather than getting the user to tell you when something went wrong, you could use something like http://errbit.github.io/errbit/ to collect your errors without needing the end-user to do anything for you. – Jon Nov 17 '15 at 09:58
  • Looks like you're [not the only one](http://stackoverflow.com/questions/21894582/how-can-i-get-a-useful-stack-trace-from-a-jquery-function) asking. Unless someone has a smart answer, this would be more than enough reason to avoid using the jquery .load(). Promises are going to sort out a lot of this mess, but not today or tomorrow. – bbsimonbb Nov 17 '15 at 10:03
  • non standard as per mdn but worth a look https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/stack – Jai Nov 17 '15 at 10:09
  • @Jai, I think that's what he's doing already? – bbsimonbb Nov 17 '15 at 10:22
  • @user1585345 this wasn't included before when i suggested comment. – Jai Nov 17 '15 at 11:16

1 Answers1

1

Information

Ok, first of all have a look at this link: http://tobyho.com/2011/06/08/the-javascript-stacktrace-blog/. It has lots of information on the topic regarding different browsers and different ways of executing javascript. Each browser and execution method gives a different covering of possibilities.

For example in IE, most methods do not work, and you can only get a line-number with sometimes the correct file.

Another method that works in most browsers but only provides you with the linenumber and file is:

window.onerror = function(message, fileURL, lineNumber){
  log(message + ': ' + fileURL + ': ' + lineNumber)
}

Solution 1: DIY

Your solution is the DIY (Do it Yourself) Stacktrace. With the DIY Stacktrace the trace you get is always correct. There are some disadvantages though that you need to consider:

  1. It will not get you file locations/line numbers.
  2. It does not work with thrown errors - either implicitly or explicitly - because the building of the stacktrace needs to be explicited done as its own statement, say, printStackTrace, for example. So, you cannot have a stacktrace and an error thrown - you cannot have your cake and eat it too.

code:

function printStackTrace() {
  var callstack = [];
  var isCallstackPopulated = false;
  try {
    i.dont.exist+=0; //doesn't exist- that's the point
  } catch(e) {
    if (e.stack) { //Firefox
      var lines = e.stack.split('\n');
      for (var i=0, len=lines.length; i&lt;len; i++) {
        if (lines[i].match(/^\s*[A-Za-z0-9\-_\$]+\(/)) {
          callstack.push(lines[i]);
        }
      }
      //Remove call to printStackTrace()
      callstack.shift();
      isCallstackPopulated = true;
    }
    else if (window.opera &amp;&amp; e.message) { //Opera
      var lines = e.message.split('\n');
      for (var i=0, len=lines.length; i&lt;len; i++) {
        if (lines[i].match(/^\s*[A-Za-z0-9\-_\$]+\(/)) {
          var entry = lines[i];
          //Append next line also since it has the file info
          if (lines[i+1]) {
            entry += ' at ' + lines[i+1];
            i++;
          }
          callstack.push(entry);
        }
      }
      //Remove call to printStackTrace()
      callstack.shift();
      isCallstackPopulated = true;
    }
  }
  if (!isCallstackPopulated) { //IE and Safari
    var currentFunction = arguments.callee.caller;
    while (currentFunction) {
      var fn = currentFunction.toString();
      var fname = fn.substring(fn.indexOf(&amp;quot;function&amp;quot;) + 8, fn.indexOf('')) || 'anonymous';
      callstack.push(fname);
      currentFunction = currentFunction.caller;
    }
  }
  output(callstack);
}

function output(arr) {
  //Optput however you want
  alert(arr.join('\n\n'));
}

Solution 2: Getting line X from js or php file.

Using the methods you use already, and the one provided in the Information section of this answer, in most cases you can get the linenumber and filename of where the error occurs.
You can use javascript to get the actual line of code from a file so you know where the error occurs. You can do that using ajax (jQuery $.get for example). See the below code:

var LineNumber = 0; //your line number from error here.
$.ajax({
    type: 'GET',
    url: 'YOURFILE',
    success: function (file_html) {
        // success
        console.log('success : ' + file_html);
        var file_content = "" + file_html //implicit convert to string
        var lines = file_content.split("\n");

        alert(lines[LineNumber]);

    }
});  
Bas van Stein
  • 9,955
  • 3
  • 22
  • 60