open-insight/FRAMEWORKS/STPROC/NDW_HTTP_LOGS_EVENTS.txt
2024-03-25 15:15:48 -07:00

1087 lines
52 KiB
Plaintext

Function NDW_HTTP_Logs_Events(CtrlEntId, Event, Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15)
/***********************************************************************************************************************
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 : NDW_HTTP_Logs_Events
Description : This function acts as a commuter module for all events related to this window.
Notes : Commuter Modules are automatically called from the Promoted_Events function which is called by the
application-specific promoted event handler. This makes it possible to add QuickEvents that need to
execute Basic+ logic without having use the Form Designer to make the association, although this is
limited to the events which are currently promoted.
If the form needs to call the commuter module directly then the QuickEvent parameters should be
formatted like this:
'@SELF','@EVENT',['@PARAM1','@PARAMx']
Parameters :
CtrlEntId [in] -- The fully qualified name of the control calling the promoted event
Event [in] -- The event being executed. See the Notes section regarding "PRE" events
Param1-15 [in] -- Additional event parameter holders
EventFlow [out] -- Set to 1 or 0 so the calling event knows whether or not to chain forward. See comments in
EVENT_SETUP insert
History (Date, Initials, Notes)
06/18/19 jwh [SRPFW-277] Created NDW_HTTP_LOGFILES_Events.
06/20/19 jwh [SRPFW-277] Got Report Table working with logs from 'C:\RevSoft\OInsight\httpLogs\'
06/21/19 jwh [SRPFW-277] Got hyperlinks to work from table to open actual log files
07/17/19 dmb [SRPFW-277] Rename to NDW_HTTP_Logs.
07/17/19 dmb [SRPFW-277] Replace harcoded reference to 'C:\RevSoft\OInsight\httpLogs\' with a call to the
GetCapturePath service.
07/18/19 dmb [SRPFW-277] Implement caching and filtering.
07/19/19 dmb [SRPFW-277] Prompt user to select the log file folder first, defaulting to the configured
capture path. Allow user to select a different folder if there are no files. Save the last
known location in cache.
07/19/19 dmb [SRPFW-277] Clear log count display when the list is being refreshed. Update the log count
display for every 100 logs found.
07/19/19 dmb [SRPFW-277] Change the default sort order of the log list to be descending for date, time,
process ID, and sequence.
08/11/19 dmb [SRPFW-278] Retrofit to use log indexes rather than the log files themselves. This speeds up
the process of populating the ReportTable.
08/11/19 dmb [SRPFW-278] Add ability to rebuild log indexes. Modify the Action Bar so the Refresh Logs
are now in the new Log Actions group.
08/11/19 dmb [SRPFW-278] Update the EDL_SEARCH_TEXT.CHAR event handler to avoid refreshing the list of
of logs if the user is backspacing in an empty control.
08/13/19 dmb [SRPFW-278] Revamp the search feature so that text searching no longer filters the list but
locates the next row with the match. Add support for Next and Previous search requests.
09/23/19 dmb [SRPFW-278] Various changes to add support for a Remote Address / Execute Time column.
09/23/19 dmb [SRPFW-278] Add support to archive logs.
09/24/19 dmb [SRPFW-278] Update archive log feature to display a success or error message as needed.
09/24/19 dmb [SRPFW-278] Hide ReportTable and display Picture control with caption when archiving logs
to help indicate a process is running.
09/24/19 dmb [SRPFW-278] Clear the log count indicator when the capture path is empty.
09/25/19 dmb [SRPFW-278] Update the RefreshLogTable internal gosub so the log count will report 0 instead
of empty if the UDP has not yet been set.
09/28/19 dmb [SRPFW-278] Fix VNAV in the OLE_ACTION_BAR.OnClick when archiving logs and cancelling the
CHOOSE folder dialog.
11/14/19 dmb [SRPFW-296] Replace the Utility("RUNWIN") service with ShellExecute in the
OLE_RPT_LOGTABLE.OnItemHyperlink event handler since not all systems work properly with the
RUNWIN service.
***********************************************************************************************************************/
#pragma precomp SRP_PreCompiler
#window NDW_HTTP_LOGS
$insert LOGICAL
$insert MSG_EQUATES
$insert HTTP_FRAMEWORK_SETUP_EQUATES
Equ CR$ to \0D\
Equ CRLF$ to \0D0A\
Equ BACKSPACE$ to \08\
Equ TAB$ to \09\
Equ NEXT$ to 1
Equ PREVIOUS$ to 2
Declare subroutine Set_Property, Send_Event, Send_Message, PlaceDialog, Utility, SRP_JSON, Logging_Services, Yield
Declare subroutine SRP_Run_Command, ShellExecute
Declare function Get_Property, DirList, Dialog_Box, HTTP_Services, SRP_Path, Send_Message, SRP_Decode, SRP_JSON
Declare function RTI_OS_Directory, Logging_Services, SRP_Array, Database_Services, GetTickCount
// Get the design time name of the window in case this is a multi-instance window.
Window = @Window[1, 'F*']
// Always get the CtrlClassID since we are not passing it through the event parameters.
CtrlClassId = Get_Property(CtrlEntId, 'TYPE')
// Get the name of the control on the window based on the CtrlClassId.
Begin Case
Case CtrlClassId EQ 'WINDOW'
Control = Window
Case CtrlClassId EQ 'RADIOBUTTON'
Control = Field(CtrlEntId, '.', 2, 2)
Case CtrlClassId EQ 'MENU'
Control = CtrlEntId[-1, 'B.']
Case 1
Control = Field(CtrlEntId, '.', 2, 1)
End Case
If Event EQ 'OLE' then GoSub TransferParams
GoToEvent Event for CtrlEntID
If Event EQ 'OLE' then GoSub RestoreParams
Return EventFlow OR EVENT_CONTINUE$
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Events
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Event WINDOW.CREATE(CreateParam)
GoSub SetupOLEControls
PlaceDialog(-2, -2)
GoSub RefreshLogTable
end event
Event OLE_ACTION_BAR.OnClick(Group, Item, Point, Button, Shift, Ctrl)
Begin Case
Case Group EQ 1
// Form Actions
Begin Case
Case Item EQ 1
// Clear Filters
Set_Property(@Window : '.EDL_SEARCH_TEXT', 'INVALUE', '')
Set_Property(@Window : '.EDL_START_DATE', 'INVALUE', '')
Set_Property(@Window : '.EDL_END_DATE', 'INVALUE', '')
Set_Property(@Window : '.EDL_START_TIME', 'INVALUE', '')
Set_Property(@Window : '.EDL_END_TIME', 'INVALUE', '')
GoSub RefreshLogTable
Set_Property(@Window : '.EDL_SEARCH_TEXT', 'FOCUS', True$)
Set_Property(@Window : '.EDL_SEARCH_TEXT', 'SELECTION', 1)
Set_Property(@Window : '.EDL_START_DATE', 'GOTFOCUS_VALUE', '')
Case Item EQ 2
// Close Form
Send_Event(@Window, 'CLOSE')
End Case
Case Group EQ 2
// Log Actions
Begin Case
Case Item EQ 1
// Refresh Logs
Set_Property(@Window, '@FULL_LOG_LIST', '')
Set_Property(@Window, '@FULL_RECORD_COLORS', '')
Set_Property(@Window, '@FULL_LOG_COUNT', 0)
Set_Property(@Window : '.OLE_RPT_LOGTABLE', 'OLE.List', '')
Set_Property(@Window : '.OLE_RPT_LOGTABLE', 'OLE.RecordColors', '')
GoSub RefreshLogTable
Set_Property(@Window : '.EDL_SEARCH_TEXT', 'FOCUS', True$)
Set_Property(@Window : '.EDL_SEARCH_TEXT', 'SELECTION', 1)
Case Item EQ 2
GoSub RebuildLogIndex
// Refresh Logs
Set_Property(@Window, '@FULL_LOG_LIST', '')
Set_Property(@Window, '@FULL_RECORD_COLORS', '')
Set_Property(@Window, '@FULL_LOG_COUNT', 0)
Set_Property(@Window : '.OLE_RPT_LOGTABLE', 'OLE.List', '')
Set_Property(@Window : '.OLE_RPT_LOGTABLE', 'OLE.RecordColors', '')
GoSub RefreshLogTable
Set_Property(@Window : '.EDL_SEARCH_TEXT', 'FOCUS', True$)
Set_Property(@Window : '.EDL_SEARCH_TEXT', 'SELECTION', 1)
Case Item EQ 3
// Archive Logs
ArchiveDate = Dialog_Box('NDW_HTTP_LOGS_ARCHIVE_DATE', @Window)
If ArchiveDate NE '' then
Utility('CURSOR', 'H')
Set_Property(@Window : '.OLE_PIC_MESSAGE', 'OLE.Caption', 'Please wait while logs are archived.' : @TM : @TM : 'This might take several minutes.')
Set_Property(@Window : '.OLE_PIC_MESSAGE', 'VISIBLE', True$)
Set_Property(@Window : '.OLE_RPT_LOGTABLE', 'VISIBLE', False$)
LogCapturePath = Get_Property(@Window, '@LOG_CAPTURE_PATH')
ArchivePathExists = False$ ; // Assume false for now.
// If the log capture path has not been identified, allow the user to pick one.
If LogCapturePath EQ '' then
// Default to the configured log capture folder.
LogCapturePath = HTTP_Services('GetCapturePath')
LogCapturePath = RTI_OS_Directory('CHOOSE', LogCapturePath, 'Path to the HTTP log files.')
end
If LogCapturePath NE '' then
LogArchivePath = SRP_Path('Combine', LogCapturePath, 'archive')
If RTI_OS_Directory('EXISTS', LogArchivePath) EQ -1 then
ArchivePathExists = RTI_OS_Directory('CREATE', LogArchivePath)
end else
ArchivePathExists = True$
end
end
If ArchivePathExists EQ True$ then
// Both the log path and the log archive path are confirmed.
ArchiveDate = Oconv(ArchiveDate, 'DJS-')
ArchiveScript = Database_Services('ReadDataRow', SetupTable$, ArchiveScriptKeyID$)
Swap @FM with CRLF$ in ArchiveScript
WindowsTempPath = RTI_OS_Directory('GetWindowsTempPath')
ScriptFilePath = SRP_Path('Combine', WindowsTempPath, 'psoi ' : GetTickCount() : '.ps1')
Swap '{{ArchiveOlderThanDate}}' with ArchiveDate in ArchiveScript
Swap '{{ArchiveStorageFolder}}' with LogArchivePath in ArchiveScript
Swap '{{ArchiveLogsFromFolder}}' with LogCapturePath in ArchiveScript
OSWrite ArchiveScript to ScriptFilePath
// Create a command line to run the script.
ArchiveCommand = 'PowerShell.exe -noprofile -ExecutionPolicy ByPass -File "' : ScriptFilePath : '"'
Results = 'VAR'
SRP_Run_Command(ArchiveCommand, Results, WindowsTempPath)
Convert \0D0A\ to '' in Results
OSDelete ScriptFilePath
If Results[1, 2] EQ 'OK' then
Message = 'Logs have been successfully archived.'
Icon = '*'
end else
Error = Results[6, Len(Results)]
Message = 'There was an error archiving the logs: ' : Error
Icon = '!'
end
MsgStruct = ''
MsgStruct<MTEXT$> = Message
MsgStruct<MICON$> = Icon
MsgStruct<MDEFBTN$> = 2
MsgStruct<MJUST$> = 'L'
MsgStruct<MCAPTION$> = 'HTTP Logs'
MsgStruct<MFONT$> = '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
Msg(@Window, MsgStruct)
end
Set_Property(@Window : '.OLE_RPT_LOGTABLE', 'VISIBLE', True$)
Set_Property(@Window : '.OLE_PIC_MESSAGE', 'VISIBLE', False$)
Set_Property(@Window : '.OLE_PIC_MESSAGE', 'OLE.Caption', '')
Utility('CURSOR', 'A')
end
End Case
End Case
end event
Event EDL_SEARCH_TEXT.LOSTFOCUS(Flag, FocusID)
If Flag EQ 1 then
// Only trigger the search if moving to another control on the form.
Send_Event(@Window : '.OLE_PUB_FIND_NEXT', 'OLE', 'OnClick')
end
end event
Event EDL_START_DATE.OPTIONS()
CurrentDate = Get_Property(@Window : '.EDL_START_DATE', 'INVALUE')
NewDate = Dialog_Box('NDW_HTTP_DATEPICKER', @Window)
If CurrentDate NE NewDate then
Set_Property(CtrlEntId, 'INVALUE', NewDate)
GoSub RefreshLogTable
end
end event
Event EDL_END_DATE.OPTIONS()
CurrentDate = Get_Property(CtrlEntId, 'INVALUE')
NewDate = Dialog_Box('NDW_HTTP_DATEPICKER', @Window)
If CurrentDate NE NewDate then
Set_Property(CtrlEntId, 'INVALUE', NewDate)
GoSub RefreshLogTable
end
end event
Event EDL_START_DATE.LOSTFOCUS(Flag, FocusID)
GotFocusID = Get_Property(CtrlEntId, 'GOTFOCUS_VALUE')
StartDate = Get_Property(CtrlEntId, 'TEXT')
If GotFocusID NE StartDate then
GoSub RefreshLogTable
end
end event
Event EDL_END_DATE.LOSTFOCUS(Flag, FocusID)
GotFocusID = Get_Property(CtrlEntId, 'GOTFOCUS_VALUE')
EndDate = Get_Property(CtrlEntId, 'TEXT')
If GotFocusID NE EndDate then
GoSub RefreshLogTable
end
end event
Event EDL_START_TIME.LOSTFOCUS(Flag, FocusID)
GotFocusID = Get_Property(CtrlEntId, 'GOTFOCUS_VALUE')
StartTime = Get_Property(CtrlEntId, 'TEXT')
If GotFocusID NE StartTime then
GoSub RefreshLogTable
end
end event
Event EDL_END_TIME.LOSTFOCUS(Flag, FocusID)
GotFocusID = Get_Property(CtrlEntId, 'GOTFOCUS_VALUE')
EndTime = Get_Property(CtrlEntId, 'TEXT')
If GotFocusID NE EndTime then
GoSub RefreshLogTable
end
end event
Event OLE_PUB_FIND_NEXT.OnClick(Point, Button, Shift, Ctrl)
Direction = NEXT$
GoSub FindMatch
end event
Event OLE_PUB_FIND_PREVIOUS.OnClick(Point, Button, Shift, Ctrl)
Direction = PREVIOUS$
GoSub FindMatch
end event
Event OLE_RPT_LOGTABLE.OnItemHyperlink(Row, Col, Text)
// Get the path to the log file from the hidden column and display it in the default .log viewer.
Record = Send_Message(CtrlEntId, 'OLE.RowToRecord', Row)
LogFilePath = Get_Property(CtrlEntId, 'OLE.ItemText[11;' : Record : ']')
ShellExecute(0, 'open' : \00\, LogFilePath : \00\, '', '', 5)
end event
Event OLE_SUBCLASS.OnOptionClick(CtrlId)
Send_Event(CtrlId, 'OPTIONS')
end event
Event MENU.FILTER_TEXT.MENU()
Set_Property(@Window : '.EDL_SEARCH_TEXT', 'FOCUS', True$)
end event
Event MENU.FIND_NEXT.MENU()
Send_Event(@Window : '.OLE_PUB_FIND_NEXT', 'OLE', 'OnClick')
end event
Event MENU.FIND_PREVIOUS.MENU()
Send_Event(@Window : '.OLE_PUB_FIND_PREVIOUS', 'OLE', 'OnClick')
end event
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Internal Gosubs
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
SetupOLEControls:
// All OLE controls can use this qualify configuration.
Qualify = ''
Qualify<1> = 1
Qualify<3> = ''
Qualify<4> = 0
//------------------------------------------------------------------------------------------------------------------
//
// SRP Subclass Control
//
//------------------------------------------------------------------------------------------------------------------
Ctrl = @Window : '.OLE_SUBCLASS'
EditCtrls = 'EDL_START_DATE,EDL_END_DATE'
NumCtrls = DCount(EditCtrls, ',')
For EditCnt = 1 to NumCtrls
EditCtrl = Field(EditCtrls, ',', EditCnt, 1)
Handle = Get_Property(@Window : '.' : EditCtrl, 'HANDLE')
Send_Message(Ctrl, 'OLE.Subclass', Handle, @Window : '.' : EditCtrl)
Set_Property(Ctrl, 'OLE.OptionButton[' : @Window : ';' : EditCtrl : ']', True$)
Set_Property(Ctrl, 'OLE.OptionImage[' : @Window : ';' : EditCtrl : ']', 'BMPS\SRPHTTPDateField.png')
Set_Property(Ctrl, 'OLE.Prompt[' : @Window : ';' : EditCtrl : ']', 'YYYY-MM-DD' : @FM : @FM : 'Center' : @FM : 'Center' : @FM : 'Segoe UI' : @SVM : 9 : @SVM : 400 : @VM : 0)
Send_Message(Ctrl, 'QUALIFY_EVENT', 'OLE.OnOptionClick', Qualify)
Next EditCnt
EditCtrls = 'EDL_START_TIME,EDL_END_TIME'
NumCtrls = DCount(EditCtrls, ',')
For EditCnt = 1 to NumCtrls
EditCtrl = Field(EditCtrls, ',', EditCnt, 1)
Handle = Get_Property(@Window : '.' : EditCtrl, 'HANDLE')
Send_Message(Ctrl, 'OLE.Subclass', Handle, @Window : '.' : EditCtrl)
Set_Property(Ctrl, 'OLE.Prompt[' : @Window : ';' : EditCtrl : ']', 'hh:mm:ss AM/PM' : @FM : @FM : 'Center' : @FM : 'Center' : @FM : 'Segoe UI' : @SVM : 9 : @SVM : 400 : @VM : 0)
Next EditCnt
EditCtrls = 'EDL_SEARCH_TEXT'
NumCtrls = DCount(EditCtrls, ',')
For EditCnt = 1 to NumCtrls
EditCtrl = Field(EditCtrls, ',', EditCnt, 1)
Handle = Get_Property(@Window : '.' : EditCtrl, 'HANDLE')
Send_Message(Ctrl, 'OLE.Subclass', Handle, @Window : '.' : EditCtrl)
Set_Property(Ctrl, 'OLE.Prompt[' : @Window : ';' : EditCtrl : ']', 'Search anything...(Ctrl+F)' : @FM : @FM : 'Center' : @FM : 'Center' : @FM : 'Segoe UI' : @SVM : 9 : @SVM : 400 : @VM : 0)
Next EditCnt
//------------------------------------------------------------------------------------------------------------------
//
// SRP Button Control
//
//------------------------------------------------------------------------------------------------------------------
ButtonCtrls = 'OLE_PUB_FIND_NEXT,OLE_PUB_FIND_PREVIOUS'
NumCtrls = DCount(ButtonCtrls, ',')
For ButtonCnt = 1 to NumCtrls
Ctrl = @Window : '.' : Field(ButtonCtrls, ',', ButtonCnt, 1)
Send_Message(Ctrl, 'QUALIFY_EVENT', 'OLE.OnClick', Qualify)
Next ButtonCnt
//------------------------------------------------------------------------------------------------------------------
//
// SRP ReportTable Control
//
//------------------------------------------------------------------------------------------------------------------
Ctrl = @Window : '.OLE_RPT_LOGTABLE'
ColumnList = ''
ColumnList := 'Date' : @VM : 'Date' : @VM : '100' : @VM : True$ : @VM : True$ : @VM : @VM : True$ : @VM : True$ : @VM : @VM : 'Left' : @VM : @VM : 'YYYY-MM-DD' : @VM : False$ : @VM : 'Segoe UI' : @SVM : '9' : @FM
ColumnList := 'Time' : @VM : 'Time' : @VM : '100' : @VM : True$ : @VM : True$ : @VM : @VM : True$ : @VM : True$ : @VM : @VM : 'Left' : @VM : @VM : 'hh:mm:ss AA' : @VM : False$ : @VM : 'Segoe UI' : @SVM : '9' : @FM
ColumnList := 'Process ID' : @VM : 'Number' : @VM : '80' : @VM : True$ : @VM : True$ : @VM : @VM : True$ : @VM : True$ : @VM : @VM : 'Right' : @VM : @VM : '0' : @VM : False$ : @VM : 'Segoe UI' : @SVM : '9' : @FM
ColumnList := 'Sequence' : @VM : 'Number' : @VM : '80' : @VM : True$ : @VM : True$ : @VM : @VM : True$ : @VM : True$ : @VM : @VM : 'Center' : @VM : @VM : '000000' : @VM : False$ : @VM : 'Segoe UI' : @SVM : '9' : @FM
ColumnList := 'Log Type' : @VM : 'Text' : @VM : '80' : @VM : True$ : @VM : True$ : @VM : @VM : True$ : @VM : True$ : @VM : @VM : 'Left' : @VM : @VM : '' : @VM : False$ : @VM : 'Segoe UI' : @SVM : '9' : @FM
ColumnList := 'Method' : @VM : 'Text' : @VM : '80' : @VM : True$ : @VM : True$ : @VM : @VM : True$ : @VM : True$ : @VM : @VM : 'Left' : @VM : @VM : '' : @VM : False$ : @VM : 'Segoe UI' : @SVM : '9' : @FM
ColumnList := 'Home URL / Status Code' : @VM : 'Text' : @VM : '150' : @VM : True$ : @VM : True$ : @VM : @VM : True$ : @VM : True$ : @VM : @VM : 'Left' : @VM : @VM : '' : @VM : False$ : @VM : 'Segoe UI' : @SVM : '9' : @FM
ColumnList := 'API Endpoint / Status Phrase' : @VM : 'Text' : @VM : '150' : @VM : True$ : @VM : True$ : @VM : @VM : True$ : @VM : True$ : @VM : @VM : 'Left' : @VM : @VM : '' : @VM : False$ : @VM : 'Segoe UI' : @SVM : '9' : @FM
ColumnList := 'Remote Address / Execute Time' : @VM : 'Text' : @VM : '150' : @VM : True$ : @VM : True$ : @VM : @VM : True$ : @VM : True$ : @VM : @VM : 'Right' : @VM : @VM : '' : @VM : False$ : @VM : 'Segoe UI' : @SVM : '9' : @FM
ColumnList := 'View' : @VM : 'Text' : @VM : '75' : @VM : True$ : @VM : True$ : @VM : @VM : True$ : @VM : True$ : @VM : @VM : 'Center' : @VM : @VM : '' : @VM : False$ : @VM : 'Segoe UI' : @SVM : '9' : @VM : '' : @VM : '' : @VM : True$ : @FM
ColumnList := 'Log File' : @VM : 'Text' : @VM : '350' : @VM : True$ : @VM : True$ : @VM : @VM : True$ : @VM : False$ : @VM : @VM : 'Left' : @VM : @VM : '' : @VM : False$ : @VM : 'Segoe UI' : @SVM : '9'
Set_Property(Ctrl, 'OLE.ColumnList', ColumnList)
Set_Property(Ctrl, 'OLE.SortOrder', 1 : @VM : 'D' : @FM : 2 : @VM : 'D' : @FM : 3 : @VM : 'D' : @FM : 4 : @VM : 'D')
Set_Property(Ctrl, 'OLE.AlwaysShowSelection', True$)
Send_Message(Ctrl, 'QUALIFY_EVENT', 'OLE.OnItemHyperlink', Qualify)
//------------------------------------------------------------------------------------------------------------------
//
// SRP Picture Control
//
//------------------------------------------------------------------------------------------------------------------
Ctrl = @Window : '.OLE_PIC_MESSAGE'
Set_Property(Ctrl, 'OLE.Border', 'XP Flat')
Set_Property(Ctrl, 'OLE.Font', 'Segoe UI' : @SVM : '24')
Set_Property(Ctrl, 'OLE.BackgroundColor', '3DFace')
Set_Property(Ctrl, 'OLE.CaptionAlignment', 'Center' : @FM : 'Center')
//------------------------------------------------------------------------------------------------------------------
//
// SRP ShortcutBar Control
//
//------------------------------------------------------------------------------------------------------------------
Ctrl = @Window : '.OLE_ACTION_BAR'
Set_Property(Ctrl, 'OLE.Border', 'XP Flat')
Set_Property(Ctrl, 'OLE.Animation', 'Never')
Set_Property(Ctrl, 'OLE.Theme', 'Office2007Blue')
Set_Property(Ctrl, 'OLE.GroupFont', 'Segoe UI' : @SVM : 11 : @SVM : 400)
Set_Property(Ctrl, 'OLE.ItemFont', 'Segoe UI' : @SVM : 9 : @SVM : 400)
Set_Property(Ctrl, 'OLE.GroupCount', 2)
Set_Property(Ctrl, 'OLE.GroupCaption[1]', 'Form Actions')
Set_Property(Ctrl, 'OLE.GroupItemCount[1]', 2)
Set_Property(Ctrl, 'OLE.ItemCaption[1;1]', 'Clear Filters')
Set_Property(Ctrl, 'OLE.ItemCaption[1;2]', 'Close Form')
Set_Property(Ctrl, 'OLE.GroupCaption[2]', 'Log Actions')
Set_Property(Ctrl, 'OLE.GroupItemCount[2]', 3)
Set_Property(Ctrl, 'OLE.ItemCaption[2;1]', 'Refresh Logs')
Set_Property(Ctrl, 'OLE.ItemCaption[2;2]', 'Rebuild Log Index')
Set_Property(Ctrl, 'OLE.ItemCaption[2;3]', 'Archive Logs')
Margins = 0 : @FM : 0 : @FM : 0 : @FM : 0 : @FM : 0
Set_Property(Ctrl, 'OLE.HotTrackStyle', 'Item')
Set_Property(Ctrl, 'OLE.ItemBold[All; All]', True$)
Send_Message(Ctrl, 'QUALIFY_EVENT', 'OLE.OnClick', Qualify)
return
RefreshLogTable:
OrigLogList = Get_Property(@Window : '.OLE_RPT_LOGTABLE', 'OLE.List')
FullLogList = Get_Property(@Window, '@FULL_LOG_LIST')
RecordColors = Get_Property(@Window, '@FULL_RECORD_COLORS')
LogCount = Get_Property(@Window, '@FULL_LOG_COUNT') + 0
If LogCount EQ 1 then
LogFoundText = LogCount : ' Log Found'
end else
LogFoundText = LogCount : ' Logs Found'
end
Set_Property(@Window : '.EDL_LOG_COUNT', 'INVALUE', LogFoundText)
If FullLogList EQ '' then
// There is no full log list available so rebuild it.
GoSub GetLogList
end
// Apply any filters that have been set. This will remove log rows that do not match the filter criteria.
GoSub ApplyFilters
// Compare the original log list with the new one created by any filters. If they match then there is no needs to
// refresh the display.
If OrigLogList NE LogList then
Set_Property(@Window : '.OLE_RPT_LOGTABLE', 'OLE.List', LogList)
Set_Property(@Window : '.OLE_RPT_LOGTABLE', 'OLE.RecordColors', RecordColors)
If LogCount EQ 1 then
LogFoundText = LogCount : ' Log Found'
end else
LogFoundText = LogCount : ' Logs Found'
end
Set_Property(@Window : '.EDL_LOG_COUNT', 'INVALUE', LogFoundText)
// If a search value is entered, find it in the new filtered list.
Direction = NEXT$
GoSub FindMatch
end
return
TransferParams:
// ActiveX controls pass their own event names through Param1. Modify the parameter values so they conform to
// OpenInsight event parameter values. This will allow commuter modules to be structured the same for OpenInsight
// event and ActiveX (OLE) events.
Transfer Param1 to Event
Transfer Param2 to Param1
Transfer Param3 to Param2
Transfer Param4 to Param3
Transfer Param5 to Param4
Transfer Param6 to Param5
Transfer Param7 to Param6
Transfer Param8 to Param7
Transfer Param9 to Param8
Transfer Param10 to Param9
Transfer Param11 to Param10
Transfer Param12 to Param11
Transfer Param13 to Param12
Transfer Param14 to Param13
Transfer Param15 to Param14
return
RestoreParams:
// Restore the event parameters so the rest of the event chain will see the parameter values as they were originally
// created by OpenInsight. This will also prevent the parameter values from being transferred multiple times in case
// there are multiple OLE promoted event handlers (e.g. APPNAME*..OIWIN* and APPNAME*OLE..OIWIN*).
Transfer Param14 to Param15
Transfer Param13 to Param14
Transfer Param12 to Param13
Transfer Param11 to Param12
Transfer Param10 to Param11
Transfer Param9 to Param10
Transfer Param8 to Param9
Transfer Param7 to Param8
Transfer Param6 to Param7
Transfer Param5 to Param6
Transfer Param4 to Param5
Transfer Param3 to Param4
Transfer Param2 to Param3
Transfer Param1 to Param2
Transfer Event to Param1
Event = 'OLE'
return
GetLogList:
Utility('CURSOR', 'H')
// Try to build the log list using the log index files. This is much quicker than parsing each individual log file.
GoSub GetLogFileIndexes
// If there are log index files, proceed to build the log list from them.
If LogFileIndexes NE '' then
// Save the current log capture path since it is valid.
Set_Property(@Window, '@LOG_CAPTURE_PATH', LogCapturePath)
FullLogList = ''
RecordColors = ''
LogCount = 0
Set_Property(@Window : '.EDL_LOG_COUNT', 'INVALUE', '0 Logs Found')
// Build the log list one log row at a time. This will also allow us to create a custom color scheme for each
// log row based on the log type and other relevant information.
For Each LogFileIndex in LogFileIndexes using @FM
IndexFilePath = SRP_Path('Combine', LogCapturePath, LogFileIndex)
OSRead LogFile from IndexFilePath then
FileRead = True$
end else
FileRead = False$
end
If FileRead EQ True$ then
// Initialize the variables that might not be used.
Convert CR$ to '' in LogFile
Convert TAB$ to @VM in LogFile
For Each LogRow in LogFile using \0A\
LogType = LogRow<0, 5>
HomeURLStatus = LogRow<0, 7>
LogFilePath = LogRow<0, 11>
LogRow<0, 11> = SRP_Path('Combine', LogCapturePath, LogFilePath[-1, 'B\'])
Begin Case
Case LogType _EQC 'Response'
Begin Case
Case HomeURLStatus[1, 1] EQ 1
RecordColor = 'None' : @VM : 'ForestGreen'
Case HomeURLStatus[1, 1] EQ 2
RecordColor = 'None' : @VM : 'ForestGreen'
Case HomeURLStatus[1, 1] EQ 3
RecordColor = 'None' : @VM : 'ForestGreen'
Case HomeURLStatus[1, 1] EQ 4
RecordColor = 'None' : @VM : 'Crimson'
Case HomeURLStatus[1, 1] EQ 5
RecordColor = 'None' : @VM : 'FireBrick'
Case Otherwise$
RecordColor = 'None' : @VM : 'ForestGreen'
End Case
Case LogType _EQC 'Aborted'
RecordColor = 'None' : @VM : 'Red'
Case LogType _EQC 'Debugger'
RecordColor = 'None' : @VM : 'Red'
Case LogType _EQC 'GetStatus'
RecordColor = 'None' : @VM : 'Red'
Case Otherwise$
// Default colors.
RecordColor = 'None' : @VM : 'None'
End Case
FullLogList := LogRow : @FM
RecordColors := RecordColor : @FM
LogCount += 1
If Mod(LogCount, 100) EQ 0 then
Set_Property(@Window : '.EDL_LOG_COUNT', 'INVALUE', LogCount : ' Logs Found')
Yield(); Yield(); Yield(); Yield()
Utility('CURSOR', 'H')
end
Next LogRow
end
Next LogFileName
FullLogList[-1, 1] = ''
RecordColors[-1, 1] = ''
Set_Property(@Window, '@FULL_LOG_LIST', FullLogList)
Set_Property(@Window, '@FULL_RECORD_COLORS', RecordColors)
Set_Property(@Window, '@FULL_LOG_COUNT', LogCount)
end
Utility('CURSOR', 'A')
return
GetLogFileIndexes:
LogFileIndexes = ''
// Check first to see if a valid log capture path has already been identified.
LogCapturePath = Get_Property(@Window, '@LOG_CAPTURE_PATH')
// If the log capture path has not been identified, allow the user to pick one.
If LogCapturePath EQ '' then
// Default to the configured log capture folder.
LogCapturePath = HTTP_Services('GetCapturePath')
LogCapturePath = RTI_OS_Directory('CHOOSE', LogCapturePath, 'Path to the HTTP log files.')
end
If LogCapturePath NE '' then
InitPath = SRP_Path('Combine', LogCapturePath, '*_Index.log')
Utility('CURSOR', 'H')
InitDir InitPath
LogFileIndexes = DirList()
If LogFileIndexes EQ '' then
// No log index files can be found. Check to see if there are detailed log files. If so, then offer to
// rebuild the index files. If not, then offer to pick another location.
RebuildIndexes = False$
InitPath = SRP_Path('Combine', LogCapturePath, '*.log')
Utility('CURSOR', 'H')
InitDir InitPath
LogFiles = DirList()
If LogFiles NE '' then
// Detailed log files were found. Offer to rebuild the index files.
MsgStruct = ''
MsgStruct<MTEXT$> = 'No log indexes could be found but there are detailed log files.' : @TM : @TM : 'Would you like to rebuild the log indexes?'
MsgStruct<MTYPE$> = 'BNY'
MsgStruct<MICON$> = '?'
MsgStruct<MDEFBTN$> = 2
MsgStruct<MJUST$> = 'L'
MsgStruct<MCAPTION$> = 'HTTP Logs'
MsgStruct<MFONT$> = '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
RebuildIndexes = Msg(@Window, MsgStruct)
end
If RebuildIndexes EQ True$ then
Set_Property(@Window, '@LOG_CAPTURE_PATH', LogCapturePath)
GoSub RebuildLogIndex
GoSub GetLogFileIndexes
end else
// The log files may have been relocated or this is running from a different machine than the OEngineServer
// is running from. Allow the user an opportunity to pick a different directory.
MsgStruct = ''
MsgStruct<MTEXT$> = 'No log indexes could be found at this location:' : @TM : @TM : LogCapturePath : @TM : @TM : 'Would you like to select another path?'
MsgStruct<MTYPE$> = 'BNY'
MsgStruct<MICON$> = '?'
MsgStruct<MDEFBTN$> = 2
MsgStruct<MJUST$> = 'L'
MsgStruct<MCAPTION$> = 'HTTP Logs'
MsgStruct<MFONT$> = '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
PickAnother = Msg(@Window, MsgStruct)
If PickAnother EQ True$ then
LogCapturePath = RTI_OS_Directory('CHOOSE', '', 'Path to the HTTP log files.')
InitPath = SRP_Path('Combine', LogCapturePath, '*_Index.log')
Utility('CURSOR', 'H')
InitDir InitPath
LogFileIndexes = DirList()
If LogFileIndexes NE '' then
Set_Property(@Window, '@LOG_CAPTURE_PATH', LogCapturePath)
end
end
end
end else
Set_Property(@Window, '@LOG_CAPTURE_PATH', LogCapturePath)
end
end
return
RebuildLogIndex:
// Remove all current indexes.
LogCapturePath = Get_Property(@Window, '@LOG_CAPTURE_PATH')
InitPath = SRP_Path('Combine', LogCapturePath, '*_Index.log')
Utility('CURSOR', 'H')
InitDir InitPath
LogFileIndexes = DirList()
If LogFileIndexes NE '' then
For Each LogFileIndex in LogFileIndexes using @FM
IndexFilePath = SRP_Path('Combine', LogCapturePath, LogFileIndex)
OSDelete IndexFilePath
Next LogFileIndex
end
// Get all detail logs and create new indexes.
GoSub GetLogFiles
If LogFiles NE '' then
LogCount = 0
For Each LogFileName in LogFiles using @FM
If IndexC(LogFileName, 'Index', 1) else
LogFilePath = SRP_Path('Combine', LogCapturePath, LogFileName)
OSRead LogFile from LogFilePath then
FileRead = True$
end else
FileRead = False$
end
If FileRead EQ True$ then
LogDate = Iconv(LogFileName[1, '_'], 'DJS')
LogTime = Iconv(LogFileName[Col2() + 1, '_'], 'MT')
ProcessID = LogFileName[Col2() + 1, '_']
Sequence = LogFileName[Col2() + 1, '_']
LogType = LogFileName[Col2() + 1, '_'][1, '.']
IncludeLogFile = True$ ; // Assume True for now.
// Initialize the variables that might not be used.
Method = ''
HomeURLStatus = ''
APIEndpointError = ''
RemoteAddressTime = ''
Begin Case
Case LogType _EQC 'Request'
If LogFile[1, 7] _EQC 'Request' then
GoSub ParseRequestLog
end else
// If a request encounters a runtime error, it will still produce a request log with
// a description of the error. However, this will also be captured in the Aborted Log
// so just ignore this redundant log.
IncludeLogFile = False$
end
Case LogType _EQC 'Response'
GoSub ParseResponseLog
Case LogType _EQC 'Aborted'
GoSub ParseAbortedLog
Case LogType _EQC 'Debugger'
GoSub ParseDebuggerLog
Case LogType _EQC 'GetStatus'
GoSub ParseGetStatusLog
End Case
end
// If the log row is flagged to be included, update the counter and use the AppendLog service to update
// the log index.
If IncludeLogFile EQ True$ then
LogCount += 1
If Mod(LogCount, 100) EQ 0 then
Set_Property(@Window : '.EDL_LOG_COUNT', 'INVALUE', LogCount : ' Logs Found')
Yield(); Yield(); Yield(); Yield()
Utility('CURSOR', 'H')
end
objLog = Logging_Services('NewLog', LogCapturePath, Oconv(LogDate, 'DJS-') : '_Index.log', CRLF$, TAB$, '', '', False$, False$)
LogRow = LogDate : @FM : LogTime : @FM : ProcessID : @FM : Sequence : @FM : LogType : @FM : Method : @FM : HomeURLStatus : @FM : APIEndpointError : @FM : RemoteAddressTime : @FM : 'View...' : @FM : LogFilePath
Logging_Services('AppendLog', objLog, LogRow, @RM, @FM, True$)
end
end
Next LogFileName
Set_Property(@Window : '.EDL_LOG_COUNT', 'INVALUE', LogCount : ' Logs Found')
end else
Set_Property(@Window : '.EDL_LOG_COUNT', 'INVALUE', '0 Logs Found')
end
return
GetLogFiles:
LogFiles = ''
// Check first to see if a valid log capture path has already been identified.
LogCapturePath = Get_Property(@Window, '@LOG_CAPTURE_PATH')
// If the log capture path has not been identified, allow the user to pick one.
If LogCapturePath EQ '' then
// Default to the configured log capture folder.
LogCapturePath = HTTP_Services('GetCapturePath')
LogCapturePath = RTI_OS_Directory('CHOOSE', LogCapturePath, 'Path to the HTTP log files.')
end
If LogCapturePath NE '' then
InitPath = SRP_Path('Combine', LogCapturePath, '*.log')
Utility('CURSOR', 'H')
InitDir InitPath
LogFiles = DirList()
If LogFiles EQ '' then
// The log files may have been relocated or this is running from a different machine than the OEngineServer is
// running from. Allow the user an opportunity to pick a different directory.
MsgStruct = ''
MsgStruct<MTEXT$> = 'No logs could be found at this location:' : @TM : @TM : LogCapturePath : @TM : @TM : 'Would you like to select another path?'
MsgStruct<MTYPE$> = 'BNY'
MsgStruct<MICON$> = '?'
MsgStruct<MDEFBTN$> = 2
MsgStruct<MJUST$> = 'L'
MsgStruct<MCAPTION$> = 'HTTP Logs'
MsgStruct<MFONT$> = '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
PickAnother = Msg(@Window, MsgStruct)
If PickAnother EQ True$ then
LogCapturePath = RTI_OS_Directory('CHOOSE', '', 'Path to the HTTP log files.')
InitPath = SRP_Path('Combine', LogCapturePath, '*.log')
Utility('CURSOR', 'H')
InitDir InitPath
LogFiles = DirList()
If LogFiles NE '' then
Set_Property(@Window, '@LOG_CAPTURE_PATH', LogCapturePath)
end
end
end else
Set_Property(@Window, '@LOG_CAPTURE_PATH', LogCapturePath)
end
end
return
ApplyFilters:
FilterLogList = ''
FilterRecordColors = ''
FilterLogCount = 0
FilterStartDate = Get_Property(@Window : '.EDL_START_DATE', 'INVALUE')
FilterEndDate = Get_Property(@Window : '.EDL_END_DATE', 'INVALUE')
FilterStartTime = Get_Property(@Window : '.EDL_START_TIME', 'INVALUE')
FilterEndTime = Get_Property(@Window : '.EDL_END_TIME', 'INVALUE')
If FilterStartDate : FilterEndDate : FilterStartTime : FilterEndTime NE '' then
// At least one filter has been set.
For Each Log in FullLogList using @FM setting LogPos
LogDate = Log[1, @VM]
LogTime = Log[Col2() + 1, @VM]
SearchText = Log[Col2() + 1, @FM]
IncludeLogFile = True$ ; // Assume True for now.
If FilterStartDate NE '' then
If LogDate LT FilterStartDate then
// Date of the log is before the filter start date.
IncludeLogFile = False$
end else
If (LogDate EQ FilterStartDate) AND (FilterStartTime NE '') then
// Date of the log is the same as the filter start date. Check to see if this date also has
// a filter start time.
If LogTime LT FilterStartTime then
// Time of the log is before the filter start time.
IncludeLogFile = False$
end
end
end
end
If FilterEndDate NE '' then
If LogDate GT FilterEndDate then
// Date of the log is after the filter end date.
IncludeLogFile = False$
end else
If (LogDate EQ FilterEndDate) AND (FilterEndTime NE '') then
// Date of the log is the same as the filter end date. Check to see if this date also has
// a filter end time.
If LogTime GT FilterEndTime then
// Time of the log is after the filter end time.
IncludeLogFile = False$
end
end
end
end
If IncludeLogFile EQ True$ then
FilterLogList := Log : @FM
FilterRecordColors := RecordColors<LogPos> : @FM
FilterLogCount += 1
end
Next Log
FilterLogList[-1, 1] = ''
FilterRecordColors[-1, 1] = ''
Transfer FilterLogList to LogList
Transfer FilterRecordColors to RecordColors
Transfer FilterLogCount to LogCount
end else
Transfer FullLogList to LogList
end
return
FindMatch:
MatchSearchText = Get_Property(@Window : '.EDL_SEARCH_TEXT', 'INVALUE')
MatchFound = False$ ; // Assume false for now.
If MatchSearchText NE '' then
CurrentRow = Get_Property(@Window : '.OLE_RPT_LOGTABLE', 'OLE.SelPos')
CurrentLogList = Get_Property(@Window : '.OLE_RPT_LOGTABLE', 'OLE.List')
LogListCount = DCount(CurrentLogList, @FM)
If Direction EQ PREVIOUS$ then
// Search is going backwards. In order to use the same search logic as forward searching, the current
// log list will be sorted in reverse. This will place all new searches into the remaining list of logs.
LenLogList = Len(CurrentLogList)
TempLogList = Str(\00\, LenLogList)
NewPos = LenLogList + 1
Pos = 1
Loop
Curr = CurrentLogList[Pos, @FM]
LenCurr = Len(Curr)
NewPos -= LenCurr
TempLogList[NewPos, LenCurr] = Curr
Pos += LenCurr + 1
While Pos LT LenLogList
NewPos -= 1
TempLogList[NewPos, 1] = @FM
Repeat
Transfer TempLogList to CurrentLogList
CurrentRow = LogListCount - CurrentRow + 1
end
PastList = Field(CurrentLogList, @FM, 1, CurrentRow)
NewList = CurrentLogList[Col2() + 1, @RM]
PastListRowCount = DCount(PastList, @FM)
If PastList : NewList NE '' then
// Search for the string in the new log list.
If NewList NE '' then
For Each Log in NewList using @FM setting LogPos
LogDate = Log[1, @VM]
LogTime = Log[Col2() + 1, @VM]
SearchText = Log[Col2() + 1, @FM]
SearchText = Delete(SearchText, 0, 8, 0)
If IndexC(SearchText, MatchSearchText, 1) then
MatchFound = True$
end
Until MatchFound
Next Log
end
If MatchFound EQ True$ then
// The true log position is the total logs in the new list and the position in the past list.
LogPos += PastListRowCount
end else
// No match found in the new log list. Search the past log list before giving up. This will
// allow a search result to circle back.
If PastList NE '' then
For Each Log in PastList using @FM setting LogPos
LogDate = Log[1, @VM]
LogTime = Log[Col2() + 1, @VM]
SearchText = Log[Col2() + 1, @FM]
SearchText = Delete(SearchText, 0, 8, 0)
If IndexC(SearchText, MatchSearchText, 1) then
MatchFound = True$
end
Until MatchFound
Next Log
end
end
end
end
If MatchFound EQ True$ then
If Direction EQ PREVIOUS$ then
// Since the match was found in a reverse sorted log list, the true log position will need to be
// calculated.
LogPos = LogListCount - LogPos + 1
end
Set_Property(@Window : '.OLE_RPT_LOGTABLE', 'OLE.SelPos', LogPos)
end
return
ParseRequestLog:
StartChar = Index(LogFile, 'HTTPRequestMethod', 1)
Method = Trim(LogFile[StartChar, 'F' : CR$])
Method = Trim(Method[-1, 'B:'])
StartChar = Index(LogFile, 'HTTPServerName', 1)
ServerName = Trim(LogFile[StartChar, 'F' : CR$])
ServerName = Trim(ServerName[-1, 'B:'])
HomeURLStatus = ServerName
StartChar = Index(LogFile, 'HTTPPathInfo', 1)
PathInfo = Trim(LogFile[StartChar, 'F' : CR$])
PathInfo = Trim(PathInfo[-1, 'B:'])
StartChar = Index(LogFile, 'HTTPRemoteAddr', 1)
RemoteAddressTime = Trim(LogFile[StartChar, 'F' : CR$])
RemoteAddressTime = Trim(RemoteAddressTime[-1, 'B:'])
If PathInfo NE '' then
If PathInfo[1, 1] NE '/' then PathInfo = '/' : PathInfo
end
APIEndpointError = HTTP_Services('GetAPIRootURL', False$) : PathInfo
return
ParseResponseLog:
StartChar = Index(LogFile, 'Time to Execute :', 1)
RemoteAddressTime = Trim(LogFile[StartChar, 'F' : CR$])
RemoteAddressTime = Trim(RemoteAddressTime[-1, 'B:'])
StartChar = Index(LogFile, 'OECGI21', 1)
If StartChar NE 0 then
// Response is binary. Decode the body first.
ResponseBody = Trim(LogFile[StartChar, 'F' : CR$])
ResponseBody = SRP_Decode(ResponseBody, 'HEX')
Transfer ResponseBody to LogFile
end
StartChar = Index(LogFile, 'Status:', 1)
Status = Trim(LogFile[StartChar, 'F' : CR$])
Status = Trim(Status[-1, 'B:'])
HomeURLStatus = Status[1, 'F ']
APIEndpointError = Status[Col2() + 1, 999]
return
ParseAbortedLog:
Status = LogFile[-1, 'B' : \0A\]
HomeURLStatus = Status[1, 'F:']
APIEndpointError = Trim(Status[Col2() + 1, 999])
return
ParseDebuggerLog:
If SRP_JSON(objLog, 'Parse', LogFile) EQ '' then
SPStatCode = SRP_JSON(objLog, 'GetValue', 'SPStatCode')
HomeURLStatus = SPStatCode[1, 'F:']
APIEndpointError = Trim(SPStatCode[Col2() + 1, 'F:'])
SRP_JSON(objLog, 'Release')
end
return
ParseGetStatusLog:
Status = Trim(LogFile[1, 'F' : CR$])
Status = Trim(Status[-1, 'B:'])
HomeURLStatus = Trim(Status[1, 'F-'])
APIEndpointError = Trim(Status[Col2() + 1, 999])
return