Friday, 23 November 2012

Capture Custom Data With Your Errors

The more context you have around an error, the better it'll help you when debugging. And who understands your application's context better than you!

Starting today, you will be able to record custom information with your errors. It's super simple too! Just create an _errs.meta object, and add anything you want to it!

You can pass the _errs.meta object any number of properties, and the values can either be strings, numbers or booleans. Values with other types will be ignored.

You can even add and remove properties from the _errs.meta object at runtime. So, if your user changes his or her preferences about cats while using your application, you can set _errs.meta.lovesCats = false; when that happens. The tracking script will record the new value lovesCats from that point on whenever an error occurs.

This can be a huge help when debugging your code. Imagine if you could record which user got the error, which action the user was performing at the time, and on which area of your page!

Other improvements

There have also been several improvements to the tracking code. Two hard-to-find bugs have been squashed, overall performance has been improved, browser support has been expanded, resilience has been improved in case our servers are in the middle of a hurricane, and the code is much better tested now. All of this while reducing the code size! (Ok, it only reduced by 4 bytes, but it's something, right?) Just to remind you, the code size doesn't really effect you, because the tracking script doesn't come in the way of your page load time at all, giving you maximum performance at all times.

As always, feedback welcome. I can't wait to see what you will do with this ability to record custom data.

Limits

The custom data recorded is put into the same store as the one used for raw error data and shares the same limits. That is, you can currently put in upto 25 MB of data. Beyond that, older data is purged to make room for the new data.

9 comments:

  1. Great feature! It would be nice to be able to set any object into the meta, and have the site display it as a json string.

    ReplyDelete
    Replies
    1. Thanks, Jonathan.

      This isn't supported directly, but don't let that stop you from posting such data. Since strings are supported, you can simply add _errs.meta.deepObject = JSON.stringify(deepObject);

      I would have supported this directly, but I can't assume that JSON.stringify will be available. Old browsers really must die! If however you have a way to serialize objects, go ahead and pass them to _errs.meta.

      Delete
  2. Your product / service is brilliant.

    With many scripts running asynchronously, it is not clear to me how to set custom info in _errs.meta and have that custom data only recorded with the currently running script. I.e. I believe _errs.meta is a document-level / global variable and so custom data defined by one script but inapplicable to another script, would have to be cleared by the second script. Which would be an undesirable degree of coupling.

    Can I limit the scope of _errs.meta so its data is transient & dies with the current running instance of the script that defined it? Perhaps, can your master script observe the value of _errs.meta in the script reporting the error, merge its dictionary with the global version of _errs.meta and report that combination?

    Basically how would you recommend one script not clobbering other scripts with unneeded custom data?

    Thanks

    ReplyDelete
  3. I will share how I'm using this capability -- and ask if others have suggestions for improvement.

    When I use a try / catch to handle an error, but still want to trace the error for further review:

    (1) The function that catches the error creates a message to pass via _errs.meta:

    function someFunction(data) {
    try {
    // something important
    }
    catch (err) {
    // do other things to handle the error, then
    _errs.meta = {
    trace: JSON.stringify({
    message: encodeURIComponent(JSON.stringify(err.message)).substring(0,200),
    data: encodeURIComponent(JSON.stringify(data)).substring(0,200)
    }),
    source: 'someFunction',
    thrown: false
    };
    }
    // rest of the function
    };

    (2) A timed monitoring function then sends the message to Errorception via a throw:

    function watchErrors() {
    if ('undefined' !== typeof _errs.meta) {
    if (!_errs.meta.thrown) {
    _errs.meta.thrown = true;
    throw('tracelog');
    }
    }
    };

    setInterval(watchErrors, 500);

    --------

    Then on the Errors page, the data looks like this:

    {"message":"%22Unexpected%20token%20%3C%22","data":"%22%3C!DOCTYPE%20HTML%20PUBLIC%20%5C%22-%2F%2FW3C%2F%2FDTD%20HTML%204.01%2F%2FEN%5C%22%20%5C%22http%3A%2F%2Fwww.w3.org%2FTR%2Fhtml4%2Fstrict.dtd%5C%22%3E%5Cn%3C!--%5Bif%20lt%20IE%207%5D%3E%20%20%3Chtm"}

    ... which is easily reconstituted -- I use Python to convert string --> dict, then URI-decode the values

    --------

    Not sure if this is good or bad. Observations --

    0. The URI encoding is because when my data included special characters, the message was cut short @ Errorception
    1. I don't know how to send an error to Errorception without causing an actual error (like a throw)
    2. Therefore I don't know how to send an error from the function that caught it / should not error out -- leads to the timed monitor
    3. Timed approach is not great because you don't want to loop too fast; but if you loop too slow traces can be overwritten / missed

    I suppose there are ways to do this using a queue and a bound event of some kind

    The above is just my first crack at this interesting problem. Anyone else care to share?

    Regards

    ReplyDelete
    Replies
    1. Hi P. Regius,

      The problem is interesting. The way I intended to use _errs.meta was to set its values at the lower-most frame of the callstack, and then delete the uninteresting properties at the end of call, when the stack has unwinded.

      Eg:

      function showCalendar() {
      _errs.meta = {action: "Showing calendar", user: "email here"};
      var dt = getTodaysDate();
      var field = getSelectedField();
      var calValues = computeCalendarValuesToRender();
      renderCalendar(field, calValues, dt);
      delete _errs.meta;
      }

      This could easily be extended to work with async functions by calling delete within the innermost callback.

      I guess the biggest difference in your approach and mine is that you are trying to throw errors manually, which Errorception doesn't currently support. Therefore, it's clunky right now to work in the fashion you are trying. In the example I've shown, the _errs.meta object (it could be just properties within the object too) is set and deleted contextually to the functions called. If any errors are thrown in the process, Errorception will serialize the errors object. Whether errors are thrown or not, the meta object is cleared when the context has unrolled.

      I hope that answers your question. If not, do let me know.

      I'm also interesting in finding out more about the special characters issue you mentioned. Feel free to let me know either here in comments, or over email. I'm rakeshpai at errorception dot com.

      Delete
  4. p.s. if there is a markup language available for these comments so we can paste code and whatnot without losing formatting -- please tell us

    ReplyDelete
  5. This, combined with the raw error data makes errorception 10000% more useful! Thank you so much!

    ReplyDelete
  6. Nice addition! Keep up the good work.

    ReplyDelete