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 = Message MsgStruct = Icon MsgStruct = 2 MsgStruct = 'L' MsgStruct = 'HTTP Logs' MsgStruct = '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 = 'No log indexes could be found but there are detailed log files.' : @TM : @TM : 'Would you like to rebuild the log indexes?' MsgStruct = 'BNY' MsgStruct = '?' MsgStruct = 2 MsgStruct = 'L' MsgStruct = 'HTTP Logs' MsgStruct = '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 = 'No log indexes could be found at this location:' : @TM : @TM : LogCapturePath : @TM : @TM : 'Would you like to select another path?' MsgStruct = 'BNY' MsgStruct = '?' MsgStruct = 2 MsgStruct = 'L' MsgStruct = 'HTTP Logs' MsgStruct = '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 = 'No logs could be found at this location:' : @TM : @TM : LogCapturePath : @TM : @TM : 'Would you like to select another path?' MsgStruct = 'BNY' MsgStruct = '?' MsgStruct = 2 MsgStruct = 'L' MsgStruct = 'HTTP Logs' MsgStruct = '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 : @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