Merged PR 11569: added local error services and removed error services common

added local error services and removed error services common
This commit is contained in:
Stieber Daniel (CSC FI SPS MESLEO) 2025-02-25 18:59:14 +01:00
parent 7a389414c5
commit c238f339ba
3 changed files with 406 additions and 6 deletions

View File

@ -22,10 +22,10 @@ $insert LOGICAL
$insert RTI_DEBUG_COMMON
$insert ENVIRON_CONSTANTS
Equ CRLF$ to \0D0A\
Common /ErrorServices/ ErrorMessages@, ErrorSources@, ErrorCodes@, RetStacks@, EsSpStatCode@, EsSpStatMessage@, Unused7@, Unused8@
Equ CRLF$ to \0D0A\
Declare function Environment_Services, Logging_Services, GetSessionCallStack, Error_Services, RetStack
Declare subroutine Logging_Services, Get_Status, Set_Env

View File

@ -0,0 +1,404 @@
Function Error_Services(@Service, @Params)
/***********************************************************************************************************************
This program is proprietary and is not to be used by or disclosed to others, nor is it to be copied without written
permission from SRP Computer Solutions, Inc.
Name : Error_Services
Description : Handler program for all error services.
Notes : Application errors should be logged using the Error Services module. There are a few methodological
assumptions built into way errors are managed which are important to understand in order to properly
work with Error Services:
- The term 'top' refers to the originating procedure of a call stack and the term 'bottom' refers to
the last routine (or the current routine) within a call stack. Within the OpenInsight Debugger
this will appear backwards since the originating procedure always appears at the bottom of the
list and the current routine appears at the top of the list. We are using this orientation because
it is common to refer to the process of calling other procedures as 'drilling down'.
- The reason for defining the orientation of the call stack is because Error_Services allows for
multiple error conditions to be appended to an original error. In most cases this will happen when
a procedure at the bottom of the stack generates an error condition and then returns to its
calling procedure. This higher level procedure can optionally add more information relevant to
itself. This continues as the call stack 'bubbles' its way back to the top to where the
originating procedure is waiting.
- Native OpenInsight commands that handle errors (e.g., Set_Status, Set_FSError, Set_EventStatus)
preserve their error state until explicitly cleared. This can hinder the normal execution of code
since subsequent procedures (usually SSPs) will fail if a pre-existing error condition exists.
Our philosophy is that error conditions should automatically be cleared before a new procedure
is executed to avoid this problem. However, the nature of Basic+ does not make this easy to
automate for any given stored procedure. Therefore, if a stored procedure wants to conform to our
philosophy then it should include a call into the 'Clear' service request at the top of the
program. Alternatively this can be done through a common insert (see SERVICE_SETUP for example.)
- Service modules will use the SERVICE_SETUP insert and therefore automatically clear out any
error conditions that were set before.
- The 'Set' service request is the equivelent to the various forms of setting an error within Basic+
(e.g., Set_Status, Set_FSError, Set_EventStatus). This will clear out any pre-existing error(s)
first (see 'Clear' service request description below). In most cases the 'Add' service request
(see below) should be used since error conditions are intended to be automatically cleared by
service modules or properly managed stored procedures.
- The 'Add' service request is similar to the 'Set' service request but it will not clear out any
pre-existing errors. Using 'Add', the error conditions can be stacked allowing the higher level
calling procedures the ability to contribute to the existing error or add additional errors.
- The 'Clear' service request will reset all of the error condition flags.
Parameters :
Service [in] -- Name of the service being requested
Param1-10 [in/out] -- Additional request parameter holders
Response [out] -- Response to be sent back to the Controller (MCP) or requesting procedure
History : (Date, Initials, Notes)
12/28/12 dmb Original programmer.
12/31/12 dmb Add hooks for various service requests. Add comments in the Notes section to explain the
theory of operation of Error Services.
01/01/13 dmb Add functionality to the Set, Add, GetMessage, and GetMessages service requests.
01/02/13 dmb Remove reference to SERVICES_SETUP and put the Assigned command lines directly into this
code to avoid infinite loop problem.
01/05/13 dmb Added HasError service request.
03/13/13 dmb [SRPFW-9] Added NoError service request.
10/01/13 dmb [SRPFW-18] Replace APP_INSERTS with LOGICAL and declare Error_Services.
10/06/13 dmb [SRPFW-17] Retrofit to use the default FrameWorks system font.
03/20/17 fjt [SRPFW-160] Conversion to EB+; addition of justification parameter to display.
10/09/17 dmb Add SendRuntimeAlert service to act as a debugger intercept process.
***********************************************************************************************************************/
#pragma precomp SRP_PreCompiler
$Insert LOGICAL
$Insert MSG_EQUATES
$Insert RTI_DEBUG_COMMON
$Insert SRPMail_Inserts
$Insert ENVIRON_CONSTANTS
Common /ErrorServices/ ErrorMessages@, ErrorSources@, ErrorCodes@, RetStacks@, EsSpStatCode@, EsSpStatMessage@, Unused7@, Unused8@
Equ Segoe_UI$ to 'Segoe UI' : @SVM : -12 : @SVM : 400 : @SVM : 0 : @SVM : 0 : @SVM : 0 : @SVM : 0 : @SVM : 34 : @SVM : 0 : @SVM : 3 : @SVM : 2 : @SVM : 1 : @SVM : 0 : @SVM : 0 : @SVM : 0 : @SVM : 0
// Make sure any request parameters which have not been assigned are nulled.
// Normally these would be referenced in the SERVICES_SETUP insert but there is a call to ERROR_SERVICES in that
// insert which causes an infinite loop to occur.
If Assigned(Service) else Service = ''
If Assigned(Error) else Error = ''
If Assigned(Param1) else Param1 = ''
If Assigned(Param2) else Param2 = ''
If Assigned(Param3) else Param3 = ''
If Assigned(Param4) else Param4 = ''
If Assigned(Param5) else Param5 = ''
If Assigned(Param6) else Param6 = ''
If Assigned(Param7) else Param7 = ''
If Assigned(Param8) else Param8 = ''
If Assigned(Param9) else Param9 = ''
If Assigned(Param10) else Param10 = ''
If Assigned(Response) else Response = ''
AutoDisplayErrors = False$ ; // Set this to True$ when debugging so all errors will automatically display.
Declare function RetStack, Error_Services, SRPSendMail, Get_Env
Declare subroutine Error_Services, Set_Env, Set_Status
GoToService else
Error_Services('Set', Service : ' is not a valid service request within the Error services module.')
end
Return Response else ''
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Service Parameter Options
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Options BOOLEAN = True$, False$
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Services
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//----------------------------------------------------------------------------------------------------------------------
// Set
//
// Param1 - Error message. Messages should be fairly descriptive.
//
// Sets an error to the stack. This will automatically clear any existing error conditions first so this error will
// be the only one on the stack.
//----------------------------------------------------------------------------------------------------------------------
Service Set(ErrorMessage)
Error_Services('Clear')
Error_Services('Add', ErrorMessage)
If AutoDisplayErrors then Error_Services('DisplayError')
End Service
//----------------------------------------------------------------------------------------------------------------------
// Add
//
// Param1 - Error message. Messages should be fairly descriptive.
//
// Adds an error to the stack. This will not clear existing error conditions first. It is intended to allow higher level
// routines to add more information to an existing error condition or simply to maintain an ongoing error log for some
// troubleshooting or debugging purposes.
//----------------------------------------------------------------------------------------------------------------------
Service Add(ErrorMessage)
CurStack = RetStack()
AtSelf = CurStack[1, @FM] ; // AtSelf should be the name of this routine (e.g., ERROR_SERVICES)
Loop
CurRoutine = CurStack[1, @FM] ; // Get the next routine from the program call stack.
Until CurRoutine _NEC AtSelf
CurStack = Delete(CurStack, 1, 0, 0) ; // Remove any self-references from the program call stack.
Repeat
Convert @FM to @VM in CurStack ; // Convert the delimiter so it can be added to the global common.
If Len(ErrorMessages@) then
ErrorMessages@ := @FM : ErrorMessage
RetStacks@ := @FM : CurStack
end else
ErrorMessages@ = ErrorMessage
RetStacks@ = CurStack
end
If AutoDisplayErrors then Error_Services('DisplayError')
End Service
//----------------------------------------------------------------------------------------------------------------------
// Clear
//
// Clears all error conditions and related information.
//----------------------------------------------------------------------------------------------------------------------
Service Clear()
ErrorMessages@ = ''
ErrorSources@ = ''
ErrorCodes@ = ''
RetStacks@ = ''
End Service
//----------------------------------------------------------------------------------------------------------------------
// GetMessage
//
// Returns the most current error message.
//----------------------------------------------------------------------------------------------------------------------
Service GetMessage()
Response = ErrorMessages@[-1, 'B' : @FM]
End Service
//----------------------------------------------------------------------------------------------------------------------
// GetMessages
//
// Returns the stack of error messages. This will be @FM delimited.
//----------------------------------------------------------------------------------------------------------------------
Service GetMessages()
// Business logic goes here. Data that needs to be returned should be assigned to the Response parameter.
Response = ErrorMessages@
End Service
//----------------------------------------------------------------------------------------------------------------------
// HasError
//
// Returns True if there is an error condition, False if there is no error condition. Caller will still need to use
// the GetMessage or GetMessages service to determine what the error is. The HasError service allows the caller to
// embed the Error_Services service call inside of a conditional statement like this:
//
// If Error_Services('HasError') then
// * An error has occured. Proceed accordingly.
// ErrorMessage = Error_Services('GetMessage')
// end else
// * No error has occured.
// end
//----------------------------------------------------------------------------------------------------------------------
Service HasError()
If Len(ErrorMessages@) then
Response = True$
end else
Response = False$
end
End Service
//----------------------------------------------------------------------------------------------------------------------
// NoError
//
// Returns True if there are no error conditions, False if there is an error condition. This is the opposite of the
// HasError service and exists for improved readability.
//----------------------------------------------------------------------------------------------------------------------
Service NoError()
If Len(ErrorMessages@) then
Response = False$
end else
Response = True$
end
End Service
//----------------------------------------------------------------------------------------------------------------------
// DisplayError
//
// Displays the current error message to the end user.
//----------------------------------------------------------------------------------------------------------------------
Service DisplayError(Justification)
ErrorMessage = Error_Services('GetMessage')
If Len(ErrorMessage) then
MsgStruct = ''
MsgStruct<MTEXT$> = ErrorMessage
MsgStruct<MTYPE$> = 'BO'
MsgStruct<MMODAL$> = 'W'
MsgStruct<MICON$> = '!'
MsgStruct<MCOL$> = -1
MsgStruct<MROW$> = -1
MsgStruct<MJUST$> = Justification
MsgStruct<MCAPTION$> = 'Error Services'
MsgStruct<MFONT$> = Segoe_UI$
Msg(@Window, MsgStruct)
end
End Service
Service GetSource()
// Business logic goes here. Data that needs to be returned should be assigned to the Response parameter.
Response = '<Service Response>'
End Service
Service GetSources()
// Business logic goes here. Data that needs to be returned should be assigned to the Response parameter.
Response = '<Service Response>'
End Service
Service GetCode()
// Business logic goes here. Data that needs to be returned should be assigned to the Response parameter.
Response = '<Service Response>'
End Service
Service GetCodes()
// Business logic goes here. Data that needs to be returned should be assigned to the Response parameter.
Response = '<Service Response>'
End Service
Service GetStackTrace()
// Business logic goes here. Data that needs to be returned should be assigned to the Response parameter.
Response = '<Service Response>'
End Service
//----------------------------------------------------------------------------------------------------------------------
// LogStack
//
// Uses a custom debugger intercept to log the stack including line numbers to .../LogFiles/StackTrace.
//----------------------------------------------------------------------------------------------------------------------
Service LogStack()
DebuggerEnabled = Get_Env(ENV_DEBUGGER_ENABLED$)
DebuggerIntercept = Get_Env(ENV_DEBUGGER_INTERCEPT_PROC$)
Set_Env(ENV_DEBUGGER_ENABLED$, 2, 1)
Set_Env(ENV_DEBUGGER_INTERCEPT_PROC$, 'DEBUGGER_LOGGER', 1)
// Save the current status code and message before forcing runtime error
// to get OI to update stack variables in RTI_DEBUG_COMMON.
EsSpStatCode@ = Get_Status(EsSpStatMessage@)
ForceRuntimeError = 1/0
Set_Env(ENV_DEBUGGER_ENABLED$, DebuggerEnabled, 1)
Set_Env(ENV_DEBUGGER_INTERCEPT_PROC$, DebuggerIntercept, 1)
// Restore OI status variables so we don't break any logic relying on it.
Set_Status(EsSpStatCode@, EsSpStatMessage@)
end service
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Internal GoSubs
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////?
//----------------------------------------------------------------------------------------------------------------------
// SendRuntimeAlert
//
// Sends out an email alert when this service is called as a debugger intercept.
//----------------------------------------------------------------------------------------------------------------------
SendRuntimeAlert:
Done = False$
Error = False$
Program = Curr_Program@
MsgSent = ''
If Program EQ '' then Program = 'Error Services'
ConfigFile = ''
ConfigFile<1> = SendUsing_Port$
ConfigFile<2> = ''
ConfigFile<3> = '' ; // Server port
ConfigFile<4> = '' ; // Mail server
ConfigFile<5> = True$ ; // Authenticate
ConfigFile<6> = '' ; // Username
ConfigFile<7> = '' ; // Password
ConfigFile<8> = False$ ; // Use SSL
Text = ''
Text<-1> = 'App: ' : @APPID<1>
Text<-1> = 'Window: ' : @WINDOW
Text<-1> = 'User: ' : @USERNAME
Text<-1> = 'Station: ' : @STATION
Text<-1> = ' '
Text<-1> = 'SP Status: ' : SPStatus@
Text<-1> = 'SP Stat Code: ' : SPStatCode@
Text<-1> = 'Program: ' : Program
Text<-1> = 'Call Depth: ' : CallDepth@
Text<-1> = 'Line No: ' : LineNo@
Text<-1> = ' '
Text<-1> = 'Stack: '
Text<-1> = CallStack@
Convert \00\ TO ',' in Text
Swap @VM with ':@VM:' IN Text
Swap @FM with Char(13) : Char(10) IN Text
Swap @TM with Char(13) : Char(10) IN Text
SentFrom = ''
SentTo = ''
Message = ''
Message<1> = '' : Program ; // Subject
Message<2> = SentFrom ; // From (email address)
Message<3> = SentTo ; // Send to (email address)
Message<5> = '' ; // Blind Carbon Copy (email address)
Message<6> = '' ; // Reply To (email address)
Message<7> = 'TEXT' ; // Content Type (TEXT or HTML)
Message<8> = Text ; // Content / Body
Message<9> = '' ; // Attachment(s) (path to file name(s))
MsgSent = SRPSendMail(Message, ConfigFile)
return

View File

@ -1,4 +0,0 @@
Compile Insert ERROR_SERVICES_COMMON
Common /ErrorServices/ ErrorMessages@, ErrorSources@, ErrorCodes@, RetStacks@, EsSpStatCode@, EsSpStatMessage@, Unused7@, Unused8@