Tips_tutorials   >   Studiojs202   >   Non-Visual Web App Monitoring
Non-Visual Web App Monitoring
Based on some of the code in rtWizard_Monitor and wMonitor we will build a non-visual web app monitoring object class.
Other features we would like to add to the web monitoring object class:
- Write the web monitoring statistics to the database so we can review and run reports on them at any time.
- Email web monitoring statistics to the developer and/or client on a regular basis using a timer object.
For the rest of the tutorial we will build a web monitoring object class with these features.
Data to Capture
Before we create the web monitoring object we need to decide what web app data we want to capture.
Here is the information which we are going to record in our database.
- Each new connection, the remote task class name, client's IP address.
- Each busy connection.
- Each rejected connection and the error message.
If the above information is saved to the database we can then report the following summary statistics from the database.
- Total connections. (Number of requests)
- Total busy connections.
- Total rejected connections.
- Number connections per client IP address.
- Number connections per remote task class.
In our database we will need a Webappstat table, with the following columns:
- ConnectionTime - Timestamp when the client request started
- ClientAddress - the IP address of the client
- RemoteTaskClassName - the name of the remote task which was instantiated
- ResponseSeconds - the number of seconds it took to process the request.
- EventCode - evRejected or evBusy if applicable.
Create Schema Class
- F2 Browser > select ContactsWeb library > New Class > Schema > name it sWebappstat
- Double-click sWebappstat to add the columns.
- Set the table name field to Webappstat
- Add the following columns to the schema class:
- ConnectionTime - Date Time - D m Y H:N:S
- ClientAddress - Character 15
- ResponseSeconds - Integer
- RemoteTaskClassName - Character 50
- EventCode - Character 15
- Set the No nulls property to kTrue for all of the columns.
We are doing something a bit unorthodox by not including a primary key in this table. This is done to avoid the overhead caused by setting the primary key. We will only be inserting records into this table, no updates, so we can get away with skipping the primary key column.
Create Servertable
Create the Webappstat servertable by dragging the sWebappstat schema class onto the CONTACTS_01 session node of the SQL Browser root node in the F2 Browser treelist.
You can check your work by clicking the
Tables child node of the
CONTACTS_01 node and then double-clicking the
Webappstat table. An
Alter Table window opens showing the table columns.
Create Table Class
We should have a table class mapped to the sWebappstat schema class.
- Select the tCountry table class.
- Right-click Duplicate. Name the copy tWebappstat
- F6 Properties > set the $sqlclassname to sWebappstat
- Double-click tWebappstat.
- Change the $:DefaultOrderBy method to:
Quit method "ORDER BY ConnectionTime DESC"
Create Web Monitor Object Class
We are ready to create the non-visual web monitor object class.
- F2 Browser > select ContactsWeb library > New Class > Object > name it oWebMonitor
- Double-click oWebMonitor to go to the class methods.
- Rename the $construct method to $initialize and enter the following code:
Do iRow.$definefromsqlclass('tWebappstat')
Do iRow.$sessionobject.$assign($ctask.dbsessionobj)
Quit method kTrue
The reason we are using a $initialize method rather than a $construct method in oWebMonitor object is the $intialize gives error checking control to the class which instantiates the object. You'll see this in more detail later in the tutorial.
- Add a method and name it $addConnection.
- Add a parameter, prTask, Item reference data type to the method.
- Add a parameter, pEventCode_opt, Long Integer data type to the method.
- Add the following code to the method.
Calculate iRow.ConnectionTime as prTask.$connectiontime
Calculate iRow.ClientAddress as prTask.$clientaddress
Calculate iRow.ResponseSeconds as ddiff(kSecond,prTask.$connectiontime,#D)
Calculate iRow.RemoteTaskClassName as prTask().$class().$name
If isnull(pEventCode_opt)
Calculate iRow.EventCode as ''
Else If pEventCode_opt=evBusy|pEventCode_opt=evRejected
Calculate iRow.EventCode as pEventCode_opt
Else
Calculate iRow.EventCode as ''
End If
Do iRow.$insert() Returns FlagOK
If not(FlagOK)
Calculate ErrText as iRow.$statementobject().$nativeerrortext
Calculate Mssg as con('SQL Error on Insert',kCr,kCr,ErrText)
Do errhndlr.$logError($cmethod,Mssg)
End If
Quit method FlagOK
Add webmon Startup_Task Variable
To avoid having to initialize the oWebMonitor object each time a request comes through the Omnis Web App Server we will initialize it once in the Startup_Task and then simply reference it when each remote task is initialized.
- Add the task variable, webmon, to the Startup_Task class.
- Set the data type to Object and point it to the oWebMonitor object class.
- Remove the following line of code which was added to the end of $construct method of the Startup_Task by the Class Wizard.
Do $clib.$windows.wMonitor.$openonce() ;; added by Monitor remote task wizard
- Add the following code to the end of $construct method of the Startup_Task:
Do webmon.$initialize() Returns FlagOK
If not(FlagOK)
Do errhndlr.$promptonceLastError()
End If
Quit method FlagOK
The oWebMonitor class is initialized just once, when the library is opened. If there is an initialization error it is immediately reported.
The developer has little control over the $construct methods. Omnis Studio automatically calls the $construct method when the object is instantiated. If an error is logged by a $construct method, we really don't have a way of receiving the return flag from the $construct method, so the error would go by unnoticed. By using an $initialize method rather than a $construct method, the developer has control over when the initialization code is run. The developer receives the return flag and can properly notify the user of the error.
Create Remote Task Superclass
We will now create a remote task superclass which other remote tasks will be subclassed from. The remote task superclass will have all of the remote task - task variables and the web monitoring calls to the oWebMonitor object.
- F2 Browser > select ContactsWeb library > New Class > Remote Task > name it rtBase_abstract
- Double-click rtBase_abstract to go to the class methods.
- Add the instance variable, ioHTMLTools, Object type. Point it to oHTMLTools.
- Add the following task variables:
- dbsessionobj - Item reference
- errhndlr - Item reference
- webmon - Item reference
- Copy the setTaskVars method from rtCountryList to rtBase_abstract and modify the code so that it reads as follows:
Do $itasks.[$clib().$name].$getTaskVarRef('errhndlr',errhndlr) Returns FlagOK
If FlagOK
Do $itasks.[$clib().$name].$getTaskVarRef('dbsessionobj',dbsessionobj) Returns FlagOK
If FlagOK
Do $itasks.[$clib().$name].$getTaskVarRef('webmon',webmon) Returns FlagOK
End If
End If
Quit method FlagOK
- Add the following code to the $construct method.
Do method setTaskVars Returns FlagOK
Quit method FlagOK
- Add the following code to the $destruct method.
Do webmon.$addConnection($cinst,pEventCode) Returns FlagOK
Quit method FlagOK
- Add an $event method to rtBase_abstract.
- Add the following code to the $event method.
On evBusy
Do webmon.$addConnection($cinst,pEventCode)
On evIdle
On evRejected
Do webmon.$addConnection($cinst,pEventCode)
Subclass rtCountryList
We now need to make rtCountryList a subclass of rtBase_abstract.
- F2 Brower > select rtCountryList > F6 Properties
- Set the $superclass property to rtBase_abstract
There are task variables and methods in the superclass which we need to inherit in the subclass.
- Double-click rtCountryList to get to the class methods.
- Right-click the instance variable ioHTMLTools > select Inherit Variable... > click Yes
- Right-click the task variable dbsessionobj > select Inherit Variable... > click Yes
- Repeat the above step for errhndlr.
- Setting the task variables is being handled by the superclass, so we can delete the setTaskVars method in rtCountry. Right-click the setTaskVars method and select Delete Selected Methods...
- Modify the start of the $construct method as follows so that it no longer calls the setTaskVars method, and instead calls the superclass $construct method.
Do inherited Returns FlagOK
If FlagOK
We are ready for testing our non-visual web monitoring object.
Web Monitoring Sequence
Here is the sequence of what happens with our web monitoring classes and methods.
- The ContactsWeb library is opened causing the $construct method of the Startup_Task class to execute.
- Near the end of the $construct method the oWebMonitor object class is instantiated by the task variable webmon and sent an $initialize message.
The web app is now ready to receive HTTP requests.
- An HTTP request specifying the rtCountyList remote task class is received by the Omnis Web App Server.
- rtCountryList is instantiated by the Omnis Web App Server and a $construct message is sent to it.
- The $construct method of rtCountryList calls the superclass $construct method of rtBase_abstract which sets all of the remote task task variables by referencing them to the matching Startup_Task task variables.
- The $construct method of rtCountryList processes the request and returns the results as an HTML web page to the client via the Omnis Web App Server.
- A $destruct message is sent to the rtCountryList instance by the Omnis Web App Server. The superclass $destruct method is immediately called. The superclass $destruct method sends an $addConnection message to oWebMonitor.
- The $addConnection method prepares the row variable and inserts a record into the Webappstat table in the database.
I tried to get my ContactsWeb to generate an evBusy or evRejected event, but was unsuccessful in doing so. Should either or those events occur the following sequence would happen:
- If an evBusy or evRejected event occurs it would be caught by the $event method of rtBase_abstract
- An $addConnection message is sent to oWebMonitor.
- The $addConnection method prepares the row variable including with the pEventCode, and inserts a record into the Webappstat table in the database.
Web Monitoring Test
Time to test our web monitor classes and code.
- Close and reopen the ContactsWeb library in order to initialize the the oWebMonitor object class with the webmon task variable of the Startup_Task class.
- Put a blue breakpoint at the top of the $construct method of the rtCountry remote task.
- Put a blue breakpoint at the top of the $addConnection method of the oWebMonitor object class.
- Using your web browser open the searchcountries.htm web page which you created in the Studio JS 201 tutorial.
http://localhost/searchcountries.htm
- Enter the first letter of a country (e.g. 'C') and click the Submit button on the web page.
- All going well you should hit the blue breakpoint in the $construct method of rtCountry.
- Click the Go button in the IDE toolbar.
- All going well you should hit the blue breakpoint in the $addConnection method of oWebMonitor.
- Step through the code and check to make sure the record is successfully inserted into the database.
- Click the Go button to finish
- Do a couple more searches from the searchcountries.htm web page.
We can now look at the database and view the Webappstat table records.
- F2 Browser > SQL Browser > CONTACT_01 session > Tables > Webappstat
- Click Show Data
- The Interactive SQL window will open displaying all of the Webappstat records.
There you have it! Any requests made to our Omnis Studio web app are being recorded in the database. We can now generate summary reports on the data to measure the useage of our web app.