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!

  • 0
  • 0
  • 358
  • 6
  • 2

Answers

If you call LOG^%ETN it will dump all of the stack into the Application Error Log which you can access via the management portal or the terminal.

http://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=ATRYCATCHFAQ has some discussion on LOG^%ETN which may be helpful.

Ben

Thank you so much!  This is exactly the type of functionality I was looking for! 

Hi, Justin!

Also, if you are using try/catch blocks, you may conside use Log() method of %Exception class, which literally does the call of LOG^%ETN:


{ 
 try {
  	$$$TOE(sc,StatusMethod())
 }
 catch e {
 	set sc=e.AsStatus()
 	do e.Log()
 }

See the related discussion.

I'd like to add that you need to purge the log often, in my experience the UI becomes not very responsive after about 10 000 entries per namespace per day.

Sounds like it's necessary to start fixing some bugs if there are that many errors thrown ;)

Is this more for debugging / tracing data that you are generating that volume of events?

Recently I built a REST API, 1 typical client for which generated dozens of requests per second, I tested locally with one client and usually got 10 to 20 thousands of exceptions in a few minutes as one "run" of the client.

In the end I wrote a custom logging system, because even one minimal run hanged UI.

Code.

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...

http://www.cachewiki.org/index.php/Undocumented_Syntax

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")
        $$$ThrowOnError(sc)
    } catch exception {
        set errorString=##class(Cogs.Lib.Status).AsStatus(exception)
        write !,errorString
    }
}

}

The error object...

{
   "Error":"",
   "Objects":{
      "customer":{
         "Properties":{
            "Address":"Obere Str. 57",
            "City":"Berlin",
            "CompanyName":"Alfreds Futterkiste",
            "ContactName":"Maria Anders",
            "ContactTitle":"Sales Representative",
            "Country":"Germany",
            "CustomerID":"ALFKI",
            "Fax":"030-0076545",
            "Phone":"030-0074321",
            "PostalCode":"12209",
            "Region":""
         },
         "Reference":"1@Northwind.Customers"
      },
      "exception":{
         "Properties":{
            "NextException":""
         },
         "Reference":"2@%Exception.StatusException"
      }
   },
   "Primatives":{
      "foo":"Hello, World",
      "sc":"0 $\u0001\u0004\u0004‰\u0013\u0016\u0001A general error type\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001"
   },
   "Stack":{
      "1":"zFoo+7^Foo.Exception.1 +1 : set errorString=##class(Cogs.Lib.Status).AsStatus(exception)"
   }
}