Tips_tutorials   >   Studiojs202   >   Studio JS 202 (All Contents)
Welcome to the
tutorial.At the time of writing this tutorial I had not been monitoring my web apps to find out when and how often they were being used. When you create a web app it's nice to get some usage statistics, for yourself, and for your client.
In this tutorial we will delve into the area of monitoring and recording web app usage. It will be a learning experience for both of us!
You will also learn about sending emails from Omnis Studio and using timer objects.
This tutorial is provided to only. If you are not currently a please go to www.studiotips.net and click the link provided for becoming a StudioTips Member. The cost of membership is minimal and helps to cover the time and expense of creating these tutorials and maintaining the studiotips.net website.If you use the Omnis Studio
to create a remote task in one of the steps is asks if you want to inherit from a Monitor Task. If you select the checkbox it creates a web monitor task and window. Let's give this a try and then look at what the Omnis Studio creates for us.The code in the rtWizard_Monitor is what we need to study to figure out how web app monitoring works.
There are 3 methods:
The wMonitor window is keeping track of the following stats:
The wMonitor window has a tasks list which displays each remote task that has been instantiated, the IP address which made the request, time connected, last response, time disconnected.
The wMonitor window has quite a few methods which you can study. We are not going to review the wMonitor window code in this tutorial. Feel free to study it on your own.
The problem I have with the web monitor created by the Omnis Studio
Many web apps run remotely on a headless server, so it would make sense to create a non-visual object class which handles the web monitoring functions. is that it is a visual monitor. The code is inside a window class which must be instantiated for any monitoring to occur. If the window is closed, the monitoring ceases. The usage statistics are stored in memory, so when you close the window, the stats are lost.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:
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.
If the above information is saved to the database we can then report the following summary statistics from the database.
In our database we will need a Webappstat table, with the following 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 the Webappstat servertable by dragging the sWebappstat schema class onto the session node of the root node in the r treelist.
You can check your work by clicking the child node of the node and then double-clicking the table. An window opens showing the table columns.We should have a table class mapped to the sWebappstat schema class.
We are ready to create the non-visual web monitor object class.
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.
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
; Set the event code to blank, unless it is evBusy or evRejected.
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
; Insert the record in the database.
Do iRow.$insert() Returns FlagOK
If not(FlagOK)
; Log the SQL error.
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
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.
; Initialize the web monitoring object.
Do webmon.$initialize() Returns FlagOK
If not(FlagOK)
Do errhndlr.$promptonceLastError()
End If
Quit method FlagOK
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.
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.
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
Do method setTaskVars Returns FlagOK
Quit method FlagOK
Do webmon.$addConnection($cinst,pEventCode) Returns FlagOK
Quit method FlagOK
On evBusy
Do webmon.$addConnection($cinst,pEventCode)
On evIdle
On evRejected
Do webmon.$addConnection($cinst,pEventCode)
We now need to make rtCountryList a subclass of rtBase_abstract.
There are task variables and methods in the superclass which we need to inherit in the subclass.
Do inherited Returns FlagOK
If FlagOK
Here is the sequence of what happens with our web monitoring classes and methods.
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:
Time to test our web monitor classes and code.
We can now look at the database and view the Webappstat table records.
We want to get summary statistics from the detailed Webappstat records. There are many ways to accomplish this. For this tutorial we'll add methods to the oWebMonitor object which return the stats in a list variable. The reason for doing this, is so that the results can be used for a report class, web page, or an email message.
What statistics would we like to know for a given time period? (Day, Week, Month, Year)
I like to use dummy schema classes for defining lists which get passed around my application. This makes it easy to find the column names because they can be viewed in the
.Create a list definition dummy schema class for our web app stats summary values.
There are numerous ways to compile the summary statistics. If you are an advanced SQL guru and using a 3rd party RDBMS you could get the statistics using SQL. Since we are working with the Omnis data file and I'm not an advanced SQL guru we'll compile the statistics using Omnis list notation.
The summary stats method is fairly lengthy. We won't go into detail explaining the code because learning SQL and learning lists notation is not the purpose of this tutorial.
; Prepare the statement object using bind variables.
Do dbsessionobj.$newstatement() Returns StmntObj
Calculate SQLText as "SELECT * FROM Webappstat WHERE ConnectionTime >= @[BeginDate] AND ConnectionTime <= @[EndDate]"
Do StmntObj.$prepare(SQLText) Returns FlagOK
If not(FlagOK)
Calculate Mssg as con("SQL Error occured while compiling Web App stats. ",kCr,"SQLText = ",SQLText,kCr,"Error = ",StmntObj.$nativeerrortext)
Do errhndlr.$logError($cmethod,Mssg)
Else
; Loop from the begin date to the end date in the specified subtotal period.
If pBeginDate>pEndDate
Calculate BeginDate as pEndDate
Else
Calculate BeginDate as pBeginDate
End If
Calculate DateTo as dadd(kDay,1,pEndDate)
Calculate DateTo as dadd(kSecond,-1,DateTo)
While BeginDate<=DateTo
Switch pkSubtotalPeriod
Case kDay
Calculate EndDate as BeginDate
Calculate NextBeginDate as dadd(kDay,1,BeginDate)
Case kWeek
Calculate EndDate as lday(kWeek,BeginDate)
Calculate NextBeginDate as dadd(kDay,1,EndDate)
Case kMonth
Calculate EndDate as lday(kMonth,BeginDate)
Calculate NextBeginDate as dadd(kDay,1,EndDate)
Case kYear
Calculate EndDate as lday(kYear,BeginDate)
Calculate NextBeginDate as dadd(kDay,1,EndDate)
Default
Calculate EndDate as pEndDate
Calculate NextBeginDate as dadd(kDay,1,EndDate)
End Switch
; If the end date is greater than pDateTo, cut it back.
If EndDate>pEndDate
Calculate EndDate as pEndDate
End If
; Move the end date to the last minute of the day.
Calculate EndDate as dadd(kDay,1,EndDate)
Calculate EndDate as dadd(kSecond,-1,EndDate)
; Execute the prepared SQL statement.
Do StmntObj.$execute() Returns FlagOK
If FlagOK
; Fetch the selected records.
Do StmntObj.$fetch(FetchList,kFetchAll) Returns FetchStatus
If FetchStatus=kFetchError
Calculate FlagOK as kFalse
End If
End If
If not(FlagOK)
Calculate Mssg as con("SQL Error occured while compiling Web App stats.",kCr,StmntObj.$nativeerrortext)
Do errhndlr.$logError($cmethod,Mssg)
Break to end of loop
Else
; Summarize the stats as per the specified subtotal period.
Do method compileStatsList (BeginDate,EndDate,FetchList) Returns RetStatsList
If StatsList.$linecount=0
Calculate StatsList as RetStatsList
Else
Do StatsList.$merge(RetStatsList)
End If
End If
; Move the begin date to the 'next' begin date.
Calculate BeginDate as NextBeginDate
End While
If not(FlagOK)
Do StatsList.$define()
End If
End If
Quit method StatsList
; Define the stats list.
If iEmptyStatsList.$colcount=0
Do iEmptyStatsList.$definefromsqlclass('sWebStatsSummary_listdef')
End If
Calculate StatsList as iEmptyStatsList
Calculate MasterList as pfFetchList
; Set any event code to value of 1 (evBusy or evRejected)
Do MasterList.$sendall($ref.EventCode.$assign(pick(len(MasterList.EventCode)>0,0,1)))
Calculate TempList as MasterList
; Total connections
Do StatsList.$add()
Do StatsList.$line.$assign($ref.$linecount)
Calculate StatsList.BeginDate as pBeginDate
Calculate StatsList.EndDate as pEndDate
Calculate StatsList.FailedConnections as TempList.$cols.EventCode.$total()
Calculate StatsList.TotalConnections as TempList.$linecount-StatsList.FailedConnections
Calculate StatsList.MaxResponseSeconds as TempList.$cols.ResponseSeconds.$maximum()
Calculate StatsList.MinResponseSeconds as TempList.$cols.ResponseSeconds.$minimum()
Calculate StatsList.AvgResponseSeconds as TempList.$cols.ResponseSeconds.$average()
; Connections by client address.
Calculate TempList as MasterList
While TempList.$linecount
; Select the clientaddress lines matching the first line.
Do TempList.$search($ref.ClientAddress=TempList.1.ClientAddress)
Do StatsList.$add()
Do StatsList.$line.$assign($ref.$linecount)
Calculate StatsList.BeginDate as pBeginDate
Calculate StatsList.EndDate as pEndDate
Calculate StatsList.FailedConnections as TempList.$cols.EventCode.$total(kTrue)
Calculate StatsList.TotalConnections as TempList.$cols.ConnectionTime.$count(kTrue)-StatsList.FailedConnections
Calculate StatsList.MaxResponseSeconds as TempList.$cols.ResponseSeconds.$maximum(kTrue)
Calculate StatsList.MinResponseSeconds as TempList.$cols.ResponseSeconds.$minimum(kTrue)
Calculate StatsList.AvgResponseSeconds as TempList.$cols.ResponseSeconds.$average(kTrue)
Calculate StatsList.ClientAddress as TempList.1.ClientAddress
; Delete the selected clientaddress lines.
Do TempList.$remove(kListDeleteSelected)
End While
; Connections by remote task class.
Calculate TempList as MasterList
While TempList.$linecount
; Select the remote task class lines matching the first line.
Do TempList.$search($ref.RemoteTaskClassName=TempList.1.RemoteTaskClassName)
Do StatsList.$add()
Do StatsList.$line.$assign($ref.$linecount)
Calculate StatsList.BeginDate as pBeginDate
Calculate StatsList.EndDate as pEndDate
Calculate StatsList.FailedConnections as TempList.$cols.EventCode.$total(kTrue)
Calculate StatsList.TotalConnections as TempList.$cols.ConnectionTime.$count(kTrue)-StatsList.FailedConnections
Calculate StatsList.MaxResponseSeconds as TempList.$cols.ResponseSeconds.$maximum(kTrue)
Calculate StatsList.MinResponseSeconds as TempList.$cols.ResponseSeconds.$minimum(kTrue)
Calculate StatsList.AvgResponseSeconds as TempList.$cols.ResponseSeconds.$average(kTrue)
Calculate StatsList.RemoteTaskClassName as TempList.1.RemoteTaskClassName
; Delete the selected remote task class lines.
Do TempList.$remove(kListDeleteSelected)
End While
Quit method StatsList
We can test the $retWebStatsList method from the of the menu.
Calculate BeginDate as fday(kMonth,#D)
Calculate EndDate as lday(kMonth,#D)
Do webmon.$retWebStatsList(BeginDate,EndDate) Returns #L1
The web stats list could be put into a report, an HTML table, or converted to text.
We'll add a method to oWebMonitor to convert the web stats list to text.
; Total connections.
Calculate List as pfWebStatsList
Do List.$search($ref.ClientAddress<>''|$ref.RemoteTaskClassName<>'')
Do List.$remove(kListDeleteSelected)
Do List.$sort($ref.BeginDate)
Calculate Text as con("Total Connections")
For List.$line from 1 to List.$linecount step 1
Calculate Text as con(Text,kCr,List.BeginDate," - ",List.EndDate," : ",List.TotalConnections)
If List.FailedConnections>0
Calculate Text as con(Text," (",List.FailedConnections," Failed)")
End If
End For
; Connections by Client IP Address
Calculate List as pfWebStatsList
Do List.$search($ref.ClientAddress<>'')
Do List.$remove(kListKeepSelected)
Do List.$sort($ref.BeginDate)
Calculate Text as con(Text,kCr,kCr,"Connections by Client IP Address")
While List.$linecount
Do List.$search($ref.ClientAddress=List.1.ClientAddress)
Calculate NumConn as List.$cols.TotalConnections.$total(kTrue)
Calculate Text as con(Text,kCr,List.BeginDate," - ",List.EndDate," - ",List.1.ClientAddress," : ",NumConn)
Calculate FailedNum as List.$cols.FailedConnections.$total(kTrue)
If FailedNum>0
Calculate Text as con(Text," (",FailedNum," Failed)")
End If
Do List.$remove(kListDeleteSelected)
End While
; Connections by Remote Task
Calculate List as pfWebStatsList
Do List.$search($ref.RemoteTaskClassName<>'')
Do List.$remove(kListKeepSelected)
Do List.$sort($ref.BeginDate)
Calculate Text as con(Text,kCr,kCr,"Connections by Remote Task Class")
While List.$linecount
Do List.$search($ref.RemoteTaskClassName=List.1.RemoteTaskClassName)
Calculate NumConn as List.$cols.TotalConnections.$total(kTrue)
Calculate Text as con(Text,kCr,List.BeginDate," - ",List.EndDate," - ",List.1.RemoteTaskClassName," : ",NumConn)
Calculate FailedNum as List.$cols.FailedConnections.$total(kTrue)
If FailedNum>0
Calculate Text as con(Text," (",FailedNum," Failed)")
End If
Do List.$remove(kListDeleteSelected)
End While
Quit method Text
We can test the $convertWebStatsListToText method from the of the Contacts menu.
Calculate BeginDate as fday(kMonth,#D)
Calculate EndDate as lday(kMonth,#D)
Do webmon.$retWebStatsList(BeginDate,EndDate) Returns #L1
Do webmon.$convertWebStatsListToText(#L1) Returns #S1
OK message {[#S1]}
First we will create the remote task that responds to the request.
; Run the superclass code which set the task variables.
Do inherited Returns FlagOK
If FlagOK
; Convert the string text dates to dates vars.
Calculate BeginDate as dat(pParamsRow.BeginDate,'y-M-D')
Calculate EndDate as dat(pParamsRow.EndDate,'y-M-D')
Do webmon.$retWebStatsList(BeginDate,EndDate) Returns List
If List.$colcount=0
Calculate FlagOK as kFalse
Else
Do webmon.$convertWebStatsListToText(List) Returns Text
If len(Text)
Calculate Text as replaceall(Text,kCr,'<br />')
Do ioHTMLTools.$retHTMLPageTemplate Returns HTML
; Replace the placeholders with content.
Calculate HTML as replaceall(HTML,'##LINK##','')
Calculate HTML as replaceall(HTML,'##JAVASCRIPT##','')
Calculate HTML as replaceall(HTML,'##TITLE##','Web App Stats')
Calculate HTML as replaceall(HTML,'##BODY##',Text)
; Add the HTTP content header.
Do ioHTMLTools.$addHTTPContentHeader(HTML) Returns FlagOK
End If
End If
End If
If not(FlagOK)
; An error occurred. Get the last error as an HTML page.
Do ioHTMLTools.$retLastErrorHTML() Returns HTML
End If
Quit method HTML
We will now create a web page for getting the web apps stats.
<html>
<head>
<title>Web App Stats</title>
<link rel="stylesheet" type="text/css" href="http://localhost/css/master.css" />
<script type="text/javascript" src="../js/webappstats.js"></script>
</head>
<body>
<div class="container"> <!-- open container div -->
<div class="title">Web App Stats</div> <!-- title div -->
<div class="search"> <!-- open search div -->
<p>
Enter the date range for the web stats which you would like to view
and then click the 'View Stats' button
</p>
<table>
<tr>
<td>Begin Date</td>
<td><input type="text" id="BeginDate" name="BeginDate" value="2007-01-01" size="15" /></td>
<td>yyyy-mm-dd</td>
</tr>
<tr>
<td>End Date</td>
<td><input type="text" id="EndDate" name="EndDate" value="2007-12-31" size="15" /></td>
<td>yyyy-mm-dd</td>
</tr>
<tr>
<td></td>
<td><input type="button" value="View Stats" onclick="submitRequestViaFrame()" /></td>
</tr>
</table>
</div> <!-- close search div -->
<iframe id="ResultsFrame" src="" width="100%" height="100%" scrolling="yes" frameborder="0"></iframe>
</div> <!-- close container div -->
<input type="hidden" id="WebAppServerCGI" value="http://localhost/cgi-bin/nph-omniscgi" />
<input type="hidden" id="OmnisServer" value="5912" />
<input type="hidden" id="OmnisLibrary" value="ContactsWeb" />
<input type="hidden" id="OmnisClass" value="rtWebAppStats" />
</body>
</html>
function pingFile() {
alert("Ping File");
}
function submitRequestViaFrame() {
// Gather the hidden inputs needed to assemble the URL
var CGI = document.getElementById("WebAppServerCGI").value
var OmnisServer = document.getElementById("OmnisServer").value
var OmnisLibrary = document.getElementById("OmnisLibrary").value
var OmnisClass = document.getElementById("OmnisClass").value
var BeginDate = document.getElementById("BeginDate").value
var EndDate = document.getElementById("EndDate").value
var URL = CGI + "?" + "OmnisServer=" + OmnisServer + "&OmnisLibrary=" + OmnisLibrary + "&OmnisClass=" + OmnisClass;
//alert("URL = " + URL);
URL = URL + "&BeginDate=" + BeginDate + "&EndDate=" + EndDate ;
// Get a reference to the frame
var rFrame = document.getElementById("ResultsFrame");
// Point the frame to the URL
rFrame.src = URL ;
}
There you have it! The ability to get your web app stats on-line.
We could get much fancier with the format and presentation of the web app stats report by putting them into a couple of tables on the web page and tinkering with the CSS. I'll leave that for you to do in your spare time. :-)We could use the SMTPSend Omnis Command directly in our code, but that requires pulling together all of the parameters whenever we want to send an email. An easier way it to wrap the SMTPSend in an object class which we can initialize with the parameters that don't change and a few default parameters, then create a public $sendMail message with a reduced set of parameters. We can instantiate the oEmail object as a Startup_Task task variable, initialize it during startup, and then access it whenever we need to send an email from any method in our application.
Calculate iSMTPServer as pSMTPServer
Calculate iSMTPUser as pSMTPUser
Calculate iSMTPPassword as pSMTPPassword
Calculate iPOP3Server as pPOP3Server
Calculate iPOP3Password as pPop3Password
Calculate iPOP3User as pPOP3User
Calculate iDefaultFromEmail as pDefaultFromEmailAddr
Calculate iDefaultFromName as pDefaultFromName
Quit method kTrue
; Ping the SMTP server before we attempt to send an email.
Do method pingSMTPServer Returns FlagOK
If FlagOK
; Set the optional 'from' parameters
If len(pFromEmailAddr_opt)
Calculate FromName as pFromEmailAddr_opt
Else
Calculate FromName as iDefaultFromEmail
End If
If len(pFromName_opt)
Calculate FromName as pFromName_opt
Else
Calculate FromName as iDefaultFromName
End If
; Convert any To, Cc, Bcc string parameters to lists.
If pTo.$colcount
Calculate ToList as pTo
Else
Do method convertCSVToList (pTo) Returns ToList
End If
If pCc_opt.$colcount
Calculate CcList as pCc_opt
Else
Do method convertCSVToList (pCc_opt) Returns CcList
End If
If pBcc_opt.$colcount
Calculate BccList as pBcc_opt
Else
Do method convertCSVToList (pBcc_opt) Returns BccList
End If
; Add some extra header information to reduce the chance that this is classified as spam.
Do XtraHdrsList.$define(HeaderType,Value)
Do XtraHdrsList.$add('Content-Type','text/plain; charset=US-ASCII; format=flowed')
Do XtraHdrsList.$add('Content-Transfer-Encoding','7bit')
Do XtraHdrsList.$add('Mime-Version','1.0')
; Send the email
; SMTPSend (iSMTPServer,FromEmailAddr,ToList,pSubject,pBody,CcList,...
; ...BccList,FromName,,,XtraHdrsList,iSMTPUser,iSMTPPassword) Returns ErrCode
SMTPSend (iSMTPServer,FromEmailAddr,ToList,pSubject,pBody,CcList,BccList,FromName,,,XtraHdrsList,iSMTPUser,iSMTPPassword) Returns ErrCode
If ErrCode<>0
Calculate Mssg as con("SMTPSend Error - Status error code = ",ErrCode)
Do errhndlr.$logError($cmethod,Mssg)
Calculate FlagOK as kFalse
End If
End If
Quit method FlagOK
Calculate TextString as pfTextString
Do List.$cols.$add('value',kCharacter,kSimplechar,1000000)
While len(TextString)
Calculate Value as trim(strtok('TextString',','))
If len(Value)
Do List.$add(Value)
End If
End While
Quit method List
We will instantiate and initialize the oEmail object from the Startup_Task class.
; Initialize the web monitoring object.
Do webmon.$initialize() Returns FlagOK
If FlagOK
; Initialize the email object.
; Do eml.$initialize(SMTPServer,SMTPUser,SMTPPassword,POP3Server,POP3User,...
; ...POP3Password,DefaultFromEmailAddr,DefaultFromName) Returns FlagOK
Do eml.$initialize(SMTPServer,SMTPUser,SMTPPassword,POP3Server,POP3User,POP3Password,DefaultFromEmailAddr,DefaultFromName) Returns FlagOK
End If
Quit method FlagOK
You can test the oEmail object by sending an email to yourself using the .
Calculate Subject as 'Test Message from oEmail'
Calculate Body as 'This is a test'
Calculate To as 'Your Name <your_email_address>'
Do eml.$sendMail(Subject,Body,To) Returns FlagOK
Now that we have the oEmail object working we can set up a timer object to email us web stats at the end of every day, week, month, year.
We need to make sure the
external component is being loaded on startup.Create an object class that is subclassed from the timer external component.
The timer object superclass has several public methods which are inherited by our oWebStatsEmailTimer object.
; Set the properties.
Calculate $cinst.$autoreset as kTrue
Calculate $cinst.$reentrant as kFalse
Calculate $cinst.$useseconds as kTrue
Calculate $cinst.$timervalue as 60*60 ;; Hourly
; Copy the parameter values to ivars.
Calculate iToEmailAddr as pToEmailAddr
Calculate ikInterval as pkInterval
; Set the begin and the end period for the current interval period.
Calculate iEndDay as #D
Calculate iEndWeek as lday(kWeek,#D)
Calculate iEndMonth as lday(kMonth,#D)
Calculate iEndYear as lday(kYear,#D)
Quit method kTrue
The $timer method is called each time the timer reaches the specified $timervalue duration.
; Is there another method currently running?
Calculate StackList as sys(192)
Calculate FlagOK as kTrue ;; Default the flag to true.
If StackList.$linecount>1
; Do nothing, another method is running.
Else
; Have we started the day after the current end date?
If #D>iEndDay
If ikInterval=kDay ;; kWeek, kMonth, kYear
; Time to send a web stats email.
Calculate Interval as 'Daily'
Do $cinst.$sendWebStatsEmail(iEndDay,iEndDay,Interval) Returns FlagOK
End If
If FlagOK
; Set the end day to today
Calculate iEndDay as #D
End If
If FlagOK
; Have we started the day after the current end week?
If #D>iEndWeek
; Check to make sure the interval is not monthly or yearly.
If ikInterval<>kMonth&ikInterval<>kYear
; Time to send a web stats email.
Calculate BeginIntervalDate as fday(kWeek,iEndWeek)
Calculate Interval as 'Weekly'
Do $cinst.$sendWebStatsEmail(BeginIntervalDate,iEndWeek,Interval) Returns FlagOK
End If
If FlagOK
Calculate iEndWeek as dadd(kWeek,1,iEndWeek)
End If
End If
End If
If FlagOK
; Have we started the day after the current end week?
If #D>iEndMonth
; Check to make sure the interval is not yearly.
If ikInterval<>kYear
; Time to send a web stats email.
Calculate BeginIntervalDate as fday(kMonth,iEndMonth)
Calculate Interval as 'Monthly'
Do $cinst.$sendWebStatsEmail(BeginIntervalDate,iEndMonth,Interval) Returns FlagOK
End If
If FlagOK
Calculate iEndMonth as lday(kMonth,iEndDay)
End If
End If
End If
If FlagOK
; Have we started the day after the current end year?
If #D>iEndYear
; Time to send a web stats email.
Calculate BeginIntervalDate as fday(kYear,iEndYear)
Calculate Interval as 'Yearly'
Do $cinst.$sendWebStatsEmail(BeginIntervalDate,iEndYear,Interval) Returns FlagOK
If FlagOK
Calculate iEndYear as lday(kMonth,iEndDay)
End If
End If
End If
Else
; Do nothing, autoreset will call the method again later.
Calculate FlagOK as kTrue
End If
End If
If not(FlagOK)
; We have to report an error to the user.
; Since this is a web server, we can't prompt the user.
; Send the error to the trace log.
Do errhndlr.$getonceLastError(Mssg,Method)
Send to trace log {----- START ERROR MESSAGE ---- [#D] ---- [$cmethod().$name] ----- [$ctask().$name] -----}
Send to trace log {----- The '[Method]' method logged the following message:}
Send to trace log {----- [Mssg]}
Send to trace log {----- END ERROR MESSAGE ----}
End If
Quit method FlagOK
; Get the web stats for the current period.
Do webmon.$retWebStatsList(pBeginDate,pEndDate) Returns StatsList
If StatsList.$colcount
; Convert the list to text for the email body.
Do webmon.$convertWebStatsListToText(StatsList) Returns Body
If len(Body)
; Send the email.
Calculate Subject as con("Web App Server Stats - ",pBeginDate," to ",pEndDate)
If len(pInterval)>0
Calculate Subject as con(pInterval," ",Subject)
End If
Calculate Body as con(kCr,Subject,kCr,kCr,Body)
Do eml.$sendEmail(Subject,Body,iToEmailAddr) Returns FlagOK
End If
End If
Quit method FlagOK
We will instantiate and initialize the oWebStatsEmailTimer object from the oWebMonitor object class.
Do iRow.$definefromsqlclass('tWebappstat')
Do iRow.$sessionobject.$assign($ctask.dbsessionobj)
; Default flag to true.
Calculate FlagOK as kTrue
; Initialize the oEmailWebStatsTime object if a 'To' email address has been provided.
If len(pToEmailAddrWebStats)
Do ioWebStatsEmailTimer.$initialize(pToEmailAddrWebStats,pkBaseIntervalEmailWebStats) Returns FlagOK
If FlagOK
; Start the timer.
Do ioWebStatsEmailTimer.$starttimer()
End If
End If
Quit method FlagOK
Do ioWebStatsEmailTimer.$sendWebStatsEmail(pBeginDate,pEndDate) Returns FlagOK
Quit method FlagOK
We need to modify the $construct method of the Startup_Task to send the parameters we added to the $initialize method of oWebMonitor.
; Initialize the web monitoring object.
Calculate ToEmailAddr as 'Your_Name <your_email_address>'
Do webmon.$initialize(ToEmailAddr,kDay) Returns FlagOK
If FlagOK
; Initialize the email object.
Do eml.$initialize(SMTPServer,SMTPUser,SMTPPassword,POP3Server,POP3User,POP3Password,DefaultFromEmailAddr,DefaultFromName)
End If
Quit method FlagOK
Test the oWebStatsEmailTimer object using the .
Calculate BeginDate as fday(kMonth,#D)
Calculate EndDate as lday(kMonth,#D)
Do webmon.$sendWebStatsEmail(BeginDate,EndDate) Returns FlagOK
Well that wraps up the
tutorial. I hope this tutorial was helpful to extending your understanding of web app monitoring, sending emails from Omnis Studio, and using timer objects.If this tutorial has been helpful please send an emai to doug@vencor.ca. It's always encouraging to hear from developers who have benefited from these tutorials. Be sure to include any suggestions for improvements or additional topics you would like to see covered.
Visit www.studiotips.net to find out more and to become a . Your support is greatly appreciated!
Happy coding!
Doug Kuyvenhoven