Trapping calculation errors and finding which line it occurred on

Version 2

    Introduction

    If a calculation isn't working the Calculations Troubleshooting Guide descibes how to enable logging to find the error message and gives reasons for some of the more common ones. In Service Desk version 7.6 you can find this error easily by using the Test Calculation button in the calculation editor (see the troubleshooting guide for more details).  However prior to version 7.6 it is harder to find the error message and even harder to find out which line of the calculation the error occurred on.   This isn't a problem if the calculation is simple but when there are more than a few lines and complex logic it is often not enough to know just the error message.

     

    By adding some extra lines to your calculation you can:

    • Trap the error message and return is as the calculation result (available on String attributes only)
    • Add the line the error occurred on to the error message as used either as the calculation result or in the calculation logging.

     

    The following technique will change a log entry like this:

     

    Calculation
    Attribute Calculation Unsuccessful at 2012-05-16 14:09:12.994
    Calculation successful for Attribute [_MyCalculation] on Class Type [IncidentManagement.Incident]
    On Object : Key = [44fb66cc-0961-4939-b9db-ae0e969f17c3]  Name = [25]
    Calculated Value = []
    FAILED
    Object reference not set to an instance of an object.
    

     

    To this:

     

    Calculation
    Attribute Calculation Unsuccessful at 2012-05-16 14:15:05.165
    Calculation successful for Attribute [_MyCalculation] on Class Type [IncidentManagement.Incident]
    On Object : Key = [44fb66cc-0961-4939-b9db-ae0e969f17c3]  Name = [25]
    Calculated Value = []
    FAILED
    Error on line 5: Object reference not set to an instance of an object.
    

     

    Implementing the technique

    The technique works by wrapping the calculation in some extra code to capture the error when it occurs and change the way it is reported.  The extra code looks like this:

     

    import System
    static def GetAttributeValue(Incident):
         try:
              <your calculation code here>
         except e:
              raise String.Format('Error on {0}: {1}', e.StackTrace.Substring(e.StackTrace.LastIndexOf(':') + 1), e.Message)
    

     

    The indenting is very important and getting this wrong will cause the calculation fail even more.  The original calculation goes after the line "try:" and must be further indented.  The line "except e:" must be back at the same indent as "try:" and the last line should be further indented.

     

    Here is an example calculation that will error if the Catagory is not set:

     

    import System
    static def GetAttributeValue(Incident):
         Value = ''
         if Incident.Category.FullName == 'Hardware': Value = 'The category is hardware'
         return Value
    

     

    This will fail with the error "Object reference not set to an instance of an object." if the Category is not set because you can't access the FullName attribute.

     

    Here is the same calculation wrapped in the extra code to capture the error and display the line number in the resulting log:

     

    import System
    static def GetAttributeValue(Incident):
         try:
              Value = ''
              if Incident.Category.FullName == 'Hardware': Value = 'The category is hardware'
              return Value
         except e:
              raise String.Format('Error on {0}: {1}', e.StackTrace.Substring(e.StackTrace.LastIndexOf(':') + 1), e.Message)
    

     

    This will still fail but the error will now read "Error on line 5: Object reference not set to an instance of an object".  The line numbering includes the header of the calculation and the extra code added around it to capture the error so "import System" is line 1, "static def GetAttributeValue(Incident):" is line 2, and so on.  In this case Line 5 is the "if" statement where the Category is referenced but is not set.

     

    Returning the error to display in the client

    The final trick to this technique is to force the calculation to appear successful and return the error as the calculation result.  This is especially useful because it removes the need to enable the logging and looking at the resulting log files.  However this will only work if your calculation is on a String attribute.

     

    To do this you simply change the word raise at the start of the last line with the word return, as follows:

     

    import System
    static def GetAttributeValue(Incident):
         try:
              Value = ''
              if Incident.Category.FullName == 'Hardware': Value = 'The category is hardware'
              return Value
         except e:
              return String.Format('Error on {0}: {1}', e.StackTrace.Substring(e.StackTrace.LastIndexOf(':') + 1), e.Message)
    

     

    This will return the value "Error on line 5: Object reference not set to an instance of an object." and display that as the value of the calculation attribute.