How to make a javascript trace log

by Peter Tyrrell Wednesday, May 16, 2007 2:19 AM

After I wrote my previous post on handling script errors, it occurred to me I had taken knowledge about about tracing and exceptions for granted. So, here is a description of how I add a trace log and exception handling to my scripts in DB/ or CS/Textworks.

Make an Inmagic DB/Textworks Trace Log

First, add a form box and two buttons to the form, named boxDebugLog, btnBugs, and btnClearLog.

Add code to handle the two buttons and and a log method, which writes a new line into the form box whenever called. The bugs button ensures there is no syntax error lurking in the code, which would halt any code from running on the form, and therefore would stop "no syntax bugs" from being written into the log (no news is bad news). The isLogging boolean variable can be turned on and off globally so that trace statements don't have to be ripped out of deployed code.

var isLogging = true;
function btnBugs_onClick()
{
  log("no syntax bugs");
}
 
function btnClearLog_onClick()
{
  Form.boxes("boxDebugLog").content = ''
}
 
function log(val)
{
  if (!isLogging)
  {
    return
  }
 
  var box = Form.boxes("boxDebugLog");
  if (box.content != '')
  {
    box.content += "\n"
  }  
  box.content += val;
}

Within the code, insert trace statements wherever you want to see the results of an operation.

log("GetRequestorsByQuery() " + commandQuery);

The result of the above would look like this in the Debug Log form box:

Extend the Trace Log to Handle Exceptions

The above is good for viewing the results of expected steps in a series of operations and can help you debug. Of course, when you work with code the real bugbear is the unexpected. And, further, there are operational errors (not bugs) which may crop up long after you're done building the code.

Inmagic DB/Textworks presents us with an obstacle in that any error encountered simply halts the process and does not in any way indicate there has been an error. To the average user this is perhaps a blessing (ignorance being bliss), but to the developer it is nothing but an impediment. Fortunately there is a way to free the errors from their airless dungeon so as to inform you of what is really going on.

The try/catch/finally statement attempts operations with instructions (the catch block) on what to do if an exception is encountered in the try block. The finally block tells what to do after try and catch have been dealt with, and is useful for closing objects or releasing resources that might otherwise have been stuck as a result of the exception encountered.

In our case, we can use try/catch to handle exceptions, and log the error messages to the trace log.

  var item = new catalogItem();

  var isInserted = false;

 

  try

  {

    isInserted = InsertCatalogRecord(item); 

  }

  catch (err)

  {

 

    log("Unable to add to catalog. " + err.name + ": " + err.message);

  }

Note that the err variable is an Error object, and so has predictable properties to call upon, name being the exception type and message being the short description. (More about exception types.Error is a built-in javascript object. I should mention that it is normally good practice to isolate specific exception types with multiple catch blocks, but I think that's overkill for Inmagic scripting.

You can also generate custom exceptions using the throw statement.

throw new Error("something went wrong");

throw "something went wrong";

Both statements are valid, because javascript is extremely lenient about what you can throw. I prefer to throw an Error object instead of a string, to be consistent with other exception types that might come up. Then I can ask for err.name and err.message without having to first check and see if the exception is actually a string instead.

So the throw statement allows you to "throw" (i.e. raise) an error whenever you like. Why would you want to, if the whole point of this exercise is to eliminate errors from the script? The reason becomes clear when you are working with operations whose scope is beyond your immediate control. In the scenario above where try/catch is demonstrated, we are adding a new record to a catalog. It's possible the catalog might not be there, or might reject a new record for some reason, or a field name changed since we wrote the script. If any of these happens, or anything else we can't now predict, we can still catch the problem and deal with it in a predictable way so that the script fails gracefully and passes on vital information before it expires.

If you wanted to force the Inmagic recordset object to throw any error it encountered, you could do that, for instance (and I do).

      if (rs.Errors.Count > 0)

      {

        throw new Error(rs.Errors(0).Description);

      }

It takes a bit of an adjustment at first to deliberately throw an error, or to let an error bubble up to another, calling function and deal with it there, but it is a powerful and freeing concept once you get it.

Tags:

blog comments powered by Disqus

Month List