egilhComTracker: Free component to track com+ call times with
The Component Services Console displays all sort of useful information like the number of objects in call, average call time etc. But, there is no official way to get the com+ call timers directly. You have to do the dirty work yourself and calculate the average call times. There is an official way and documented way to do this but it takes a lot of code and work. I found a way to get the com+ call times the unofficial way which is a lot simpler. The egilh COM+ tracker gives you access to all the hidden statistics in COM+.
The egilh COM+ tracker download contains the com+ call time tracker and a VBScript example client. You can do a lot of neat stuff with it:
- Use it a ASP page to monitor the call time of your components live
- Use Cacti to show how average call time changes during the day.
- Use the COM+ Admin API to automatically shut down/recycle components with high call times
Installation
- Download the egilh Com+ Tracker
- Extract the files
- Register the DLL in COM+ or run regsvr32 EgilhComTracker.dll in the directory where you extracted the files
Usage
The egilh.ComTracker object only has one method: string getStatistics()
It returns a xml formatted string that contains information about all the running applications. The XML has the following layout:
/applications
/application
/classes
/class
Example:
<applications>
<application>
<guid>{98CDBB6E-3CAF-46F2-ABE6-EABECD6AA4EB}< SPAN>guid>
<ID>10< SPAN>ID>
<processID>1792< SPAN>processID>
<statistics>
<callsPerSecond>0< SPAN>callsPerSecond>
<totalCalls>0< SPAN>totalCalls>
<totalClasses>1< SPAN>totalClasses>
<totalInstances>1< SPAN>totalInstances>
< SPAN>statistics>
<classes>
<class>
<progID>Test.Sleep.1< SPAN>progID>
<bound>1< SPAN>bound>
<inCall>0< SPAN>inCall>
<pooled>-1< SPAN>pooled>
<references>1< SPAN>references>
<responseTime>120< SPAN>responseTime>
<callsCompleted>0< SPAN>callsCompleted>
<callsFailed>0< SPAN>callsFailed>
< SPAN>class>
< SPAN>classes>
< SPAN>application>
< SPAN>applications>
Test client
The following VB code shows the call times for all classes registered in com+ on the local machine.
Dim oTracker 'As Object
Dim sResult 'As String
Dim oDOM 'As DOMDocument30
Dim oNode 'As MSXML2.IXMLDOMNode
'Get the com+ call times
Set oTracker = CreateObject("egilh.ComTracker")
sResult = oTracker.getStatistics()
Set oTracker = Nothing
'Display call times
Set oDOM = CreateObject("MSXML2.DomDocument.3.0")
oDOM.loadXML (sResult)
For Each oNode In oDOM.selectNodes("/applications/application/classes/class")
WScript.echo oNode.selectSingleNode("progID").Text & _
" call time: " & oNode.selectSingleNode("responseTime").Text
Next
With all the call information at hand, it is also possible to shut down components with high call times etc. The example below loads the XML returned by the COM+ tracker in a DOM using MSXML 3.0 and checks the responseTimes. It uses the COM+ Admin API to shut down the application if the call time is higher than the configured MAX_CALL_TIME and there are objects in call. The ShutDownApplication method works on Windows 2000 as well as Windows 2003. It has the same "brutal" effect as right clicking a COM+ application and selecting "shut down"; clients currently in call will get a COM+ error. With Windows 2003 it is possible to use recycling which routes new request to a new application instance but lets existing calls finish.
Option Explicit
Const MAX_CALL_TIME = 10000 'Max allowed call time in miliseconds
Const CHECK_INTERVAL = 5000 'How often we should check the call times
Const RECYCLE_REASON = 408 'The reason for the recyle. Any number is OK
'Never ending main loop that monitors the call time
Do While True
checkCallTimes
WScript.Sleep(CHECK_INTERVAL)
Private Sub checkCallTimes()
'**
'Purpose: Check the call times and shut down applications that have too high call times
Dim oTracker 'As Object
Dim sResult 'As String
Dim oDOM 'As DOMDocument30
Dim oNode 'As MSXML2.IXMLDOMNode
Dim sProgID 'As String
Dim lResponseTime 'As Long
Dim lInCall 'As Long
Dim oApp 'As MSXML2.IXMLDOMNode
Dim bHighCallTimes 'As Boolean
'Get the com+ call times
oTracker = CreateObject("egilh.ComTracker")
sResult = oTracker.getStatistics()
oTracker = Nothing
bHighCallTimes = False
'Check call times
oDOM = CreateObject("MSXML2.DomDocument.3.0")
oDOM.loadXML(sResult)
For Each oNode In oDOM.selectNodes("/applications/application/classes/class")
lInCall = CLng(oNode.selectSingleNode("inCall").Text)
lResponseTime = CLng(oNode.selectSingleNode("responseTime").Text)
' Check if we should recycle
If lResponseTime > MAX_CALL_TIME And lInCall > 0 Then
'Log that we are recycling
sProgID = oNode.selectSingleNode("progID").Text
WScript.Echo(Now() & " Shutting down '" & sProgID & _
"' because of high call time: " & lResponseTime)
'We shut down the parent process: ../../processID
oApp = oNode.parentNode.parentNode
shutDownApplication(oApp.selectSingleNode("guid").Text)
bHighCallTimes = True
End If
Next
If Not bHighCallTimes Then WSCript.Echo(Now() & " Call Times OK")
End Sub
Private Sub shutDownApplication(ByVal appGuid)
'**
'Purpose: Shut down an application
'Description: Shuts down a com+ application identified by its guid.
Dim adminCatalog 'As COMAdmin.COMAdminCatalog
Dim appInstanceGUID 'As Object
adminCatalog = CreateObject("COMAdmin.COMAdminCatalog")
'ShutdownApplicationInstances
adminCatalog.shutDownApplication(appGuid)
adminCatalog = Nothing
End Sub