· May 9, 2018

Standardizing Error Logging

I have been tasked with creating a class that will handle error logging in a consistent manor for an application I am working on.  The need is to have all variables in the calling method logged along with some other information. 

The example given was zwrite which is exactly what I need, however, I somehow need to capture the output of ZW and put it into a database table.  Any easy way to capture this data?  I was able to dump ZW to a file, but that is not ideal.

Any help is appreciated!

Discussion (8)2
Log in or sign up to continue

This is a bit of an experimental (not released) error dump utility that I developed not so long back to explore the idea of dumping all variables into a JSON string.

It uses undocumented $zu functions which are listed on this site...

Essentially you use $zu(42 to $order over the variables at a specific stack level.

In this instance I build an exception object with all of the primitives and objects at the stack level in error.

I then use the Cogs JSON library to covert the entire error object into a serialised JSON string that is embedded into a Status string. The good thing here is that it will do a deep serialisation of objects which often get clipped in other solutions.

From here I can pass the JSON part of the Status string to an error log viewing tool that formats the JSON into an HTML view.

It doesn't look like I fully got the stack levels into the object, so the code would need some further tweaking.

Class Cogs.Lib.Status Extends Cogs.JsonClass

Property Error As %String(MAXLEN = 50000);

Property Stack As array Of %String(MAXLEN = 50000);

Property Objects As array Of Cogs.Lib.Status.Object;

Property Primatives As array Of %String(MAXLEN = 50000);

ClassMethod AsStatus(pException As %Exception.AbstractException) As %Status
    set sc=pException.AsStatus()
    try {
        do pException.Log()
        set status=##class(Cogs.Lib.Status).%New()
        set status.Error=$zerror
        for i=1:1:$stack-1 do status.Stack.SetAt($stack(i,"PLACE")_" : "_$zstrip($stack(i, "MCODE"),"<W"),i)
        set level=$ZU(41)-2
        set var=$zu(42,level,"~")
        while var'="" {
            set name=$p(var,"~",2)
            set item=$zu(43,level,var)
            if $data(item),item'["%Exception.SystemException" {
                if $IsObject(item) {
                    set object=##class(Cogs.Lib.Status.Object).%New()
                    set object.Reference=item
                    set object.Properties=##class(Cogs.JsonObject).toJSON(item)
                    do status.Objects.SetAt(object,name)
                } else {
                    do status.Primatives.SetAt(item,name)
            set var=$zu(42,level,var)
        set sc=$$$ERROR($p(##class(%SYSTEM.Status).GetErrorCodes(sc),","),status.toJSON())
    } catch err {}
    quit sc


Example in use...

Class Foo.Exception Extends %RegisteredObject

ClassMethod Foo()
    try {
        set customer=##class(Northwind.Customers).%OpenId("ALFKI")
        set foo="Hello, World"
        set sc=$$$ERROR($$$GeneralError,"A general error type")
    } catch exception {
        set errorString=##class(Cogs.Lib.Status).AsStatus(exception)
        write !,errorString


The error object...

            "Address":"Obere Str. 57",
            "CompanyName":"Alfreds Futterkiste",
            "ContactName":"Maria Anders",
            "ContactTitle":"Sales Representative",
      "foo":"Hello, World",
      "sc":"0 $\u0001\u0004\u0004‰\u0013\u0016\u0001A general error type\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001"
      "1":"zFoo+7^Foo.Exception.1 +1 : set errorString=##class(Cogs.Lib.Status).AsStatus(exception)"