Show-n-Tell Thursday

Logging JavaScript Errors to OpenLog

If you haven't heard of OpenLog then you should get over to OpenNTF and catch up now, don't worry we'll wait for you...

OK, are you ready now? Good then we can continue.

I have been busy adding OpenLog to a couple of applications over the last day or so, all works wonderfully (as we have become used to with Julian's code!). However these apps are very JavaScript heavy and there are some problems which need to be sorted. The challenge is locating all of the errors out there, so I thought it might be useful to be able to log JavaScript errors to OpenLog as well as LotusScript and Java. It's a little more involved than other implementations but my solution seems to work pretty well. (I know Kevin came up with a great logging apporach for when users do particular tasks, but I want to trap all unhandled JavaScript errors to make sure that we are fixing all of the underlying problems).

Javascript allows us to set the "onerror" function so that whenever there is a JavaScript error a function is run. What we are going to do is create an AJAX request which submits all of the details about the error to an agent which then logs the information to the OpenLog database.

Step 1
First we add two new JS libraries to the form header: "prototype-1.4.0.js" and "jserror.js". Prototype is being used for the AJAX stuff (of course you can use your own method for the actual posting of data if you want to, it's just we already have Prototype on every page anyway) and the new library called jserror.js:
function doError(msg,url,ln) {
  var strURLPrefix = document.location.href.split(".nsf")[0] + ".nsf";
  var strURL = strURLPrefix + "/agLogJSError?openagent&rand=" + Math.floor(Math.random()*1001);
  var strData = "message=" + escape(msg);
  strData += "&url=" + escape(url);
  strData += "&ln=" + escape(ln);
  new Ajax.Request(strURL,
    {  method: 'post',
      postBody: strData,
      onComplete: handleErrorResponse
    }
  );
  return true;
}

function handleErrorResponse(originalRequest) {
  alert("An error has been detected on this page and logged with the support team. Please continue to use the application as normal.");
}

try {
  window.onerror = doError;
}
catch(er) {}

Step 2
Now we need to create the agent which errors will be posted to, it's called agLogJSError and is really very simple:
Sub Initialize
  On Error Goto Whoops
  Dim sess As New NotesSession
  Dim dbCurrent As NotesDatabase
  Dim docContext As NotesDocument
  Dim vFields As Variant
  Dim vData As Variant
  Dim strMessage As String
  Dim i As Integer
  Dim url As String
  Dim errorline As String
  
  Set dbCurrent = sess.CurrentDatabase
  Set docContext = sess.DocumentContext
  
  Print |Content-Type: text/xml|
  Print ||
  
  strMessage = "Javascript Error:"
  
  vFields = Evaluate(|@URLDecode("Domino"; @Explode(REQUEST_CONTENT; "&"))|, docContext)
  For i = Lbound(vFields) To Ubound(vFields)
    vData = Split(vFields(i), "=")
    If vData(0) = "url" Then
      url = vData(1)
    Elseif vData(0) = "ln" Then
      errorline = vData(1)
    Else
      If strMessage <> "" Then
        strMessage = strMessage + Chr(10) + Chr(13)
      End If
      strMessage = strMessage + vFields(i)
    End If
  Next
  
  Call LogErrorJS (strMessage, url, errorline, SEVERITY_HIGH, docContext)
  
  Print ||
  
  Exit Sub
Whoops:
  Call logError()
  Print ||
  Print "Error #" & Err & " " & Error$ & " " & "Line #" & Erl & | in sub/function: "| & Lsi_info(2) & |"|+ "."
  Print |
|
  Print ||
  Exit Sub
End Sub

Step 3
Finally to make things slightly easier I have created a new function in the OpenLogFunctions script library called LogErrorJS which just formats the error slightly differently than a "normal" LotusScript or Java error.

The end result of all of this is that when there is a JavaScript error the user gets an alert saying that an error has been encountered and logged with support but please keep going as it shouldn't affect you. In reality you may not even want to notify your user that an error happened, I am undecided about that as yet, we'll see what they think during testing.

To be honest all of this is terribly simple but I hope it demonstrates two things. Firstly JavaScript is a "proper" language and should be treated as such, ignoring error messages is not a good long term strategy. Secondly OpenLog is great but it's also flexible, if it doesn't do exactly what you want then just change it to meet your requirements, I don't think Julian is going to mind too much ;o)


Big Reminder
Ooh, I almost forgot. If you're using IE (spit!) and you're a web developer then you probably have Script Debugging turned on. Well for the "onerror" function to work you have to have script debugging disabled. If you don't then the function is just never called! Wonderful IE eh?

Online Demo: here
Download Demo Database: JSOpenLogDemo.nsf
Technorati Tags: Show-N-Tell Thursday