O R G A N I C / F E R T I L I Z E R: process and memory monitoring in mom 2005 [revisited]…

Jul 2, 2008

process and memory monitoring in mom 2005 [revisited]…

awhile back, a long while back, as it turns out, i wrote a couple of scripts that you could inject as responses in mom 2005 to generate a list of top cpu or memory processes.  here are the links to the old posts, in case you’ve forgotten about it.

mom: monitoring cpu spikes the right way
mom: memory processes

anyway, i realized today while daydreaming in between meetings and outage summaries, that i could write the information directly to the alert stream.  it’s so simple i could kick myself.

all i needed was one additional line.  now look at this… this is the old way i did it.

sMessage = "The processes using greater than " & Z & "k of memory are:" & VbCrLf & VbCrLf
For i = 0 To x - 1
    If aProcess(0,i) > z Then
        sMessage = sMessage & aProcess(1,i) & " : " & aProcess(0,i) & VbCrLf
     End If
Next
sMessage = sMessage & VbCrLf & "(There are " & x & " processes running at this time.)"

CreateEvent 40150,EVENT_TYPE_INFORMATION,"Memory Processes Script",sMessage

basically, you’d run this as a response script to a condition that was occurring.  you’d have to look at both alerts to see what was going on.  however, i found that since it’s executing as a response, it’s a part of the overall alert.  i’m sure someone had already written about that… but it just now made sense. 

here it is revised:

Set oAlert = ScriptContext.Alert

...

sMessage = "The processes using greater than " & Z & "k of memory are:" & VbCrLf & VbCrLf
For i = 0 To x - 1
    If aProcess(0,i) > z Then
        sMessage = sMessage & aProcess(1,i) & " : " & aProcess(0,i) & VbCrLf
     End If
Next
sMessage = sMessage & VbCrLf & "(There are " & x & " processes running at this time.)"

oAlert.Description = oAlert.Description & VbCrLf & VbCrLf & "[Top Memory Processes]" & VbCrLf & sMessage

as you can see, i had to create the object for scriptcontext.  instead of using the createevent function, i just write the alert object’s description with my additional information i’ve captured.  :)  instead of the standard, crappy information i get back from a mom performance counter, i now get back something that looks a little more polished…

Memory: Available MBytes: value = 276

[Top Memory Processes]
The processes using greater than 14681k of memory are:

myAntiVirus.exe : 119680
mySearch.exe : 284836
myPretendTestApp.exe : 16680
myApp1.exe : 53008
myApp2.exe : 28356
MOMService.exe : 17124

(There are 43 processes running at this time.)

 

 

i’ll post the links for the new scripts soon.  in the mean time, here are the scripts, if you want to pull them off the site:

TOP MEMORY:

'==========================================================================
'NAME        : Display Memory Processes
'AUTHOR        : Marcus C. Oh
'DATE        : 7/2/2008
'COMMENT        : Run as a response script to a rule that checks CPU utilization
'            : Lists processes utilizing % value of CPU over threshold
'            : Updated to write the memory information into the alert stream
'==========================================================================
Const EVENT_TYPE_SUCCESS = 0
Const EVENT_TYPE_ERROR = 1
Const EVENT_TYPE_WARNING = 2
Const EVENT_TYPE_INFORMATION = 4
Const EVENT_TYPE_AUDITSUCCESS = 8
Const EVENT_TYPE_AUDITFAILURE = 16

Set oAlert = ScriptContext.Alert
Set oWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & ScriptContext.TargetNetbiosComputer & "\root\cimv2")
Set oProcesses = oWMIService.ExecQuery("SELECT * FROM Win32_Process")

Dim aProcess()

x = 0
For Each oProcess In oProcesses
    ReDim Preserve aProcess(2,x)    ' ReDim can only update the last dimension
    aProcess(0,x) = oProcess.WorkingSetSize / 1024
    aProcess(1,x) = oProcess.Name
    x = x + 1
Next

y = 0
For j = 0 To x - 1
     y = y + aProcess(0,j)    ' Count up the total memory used
Next

z = Round(y/x)                ' Divide total memory used by total processed and round it up

sMessage = "The processes using greater than " & Z & "k of memory are:" & VbCrLf & VbCrLf
For i = 0 To x - 1
    If aProcess(0,i) > z Then
        sMessage = sMessage & aProcess(1,i) & " : " & aProcess(0,i) & VbCrLf
     End If
Next
sMessage = sMessage & VbCrLf & "(There are " & x & " processes running at this time.)"

oAlert.Description = oAlert.Description & VbCrLf & VbCrLf & "[Top Memory Processes]" & VbCrLf & sMessage

Sub CreateEvent(iEventNumber,iEventType,sEventSource,sEventMessage)
    Set oEvent = ScriptContext.CreateEvent()
    oEvent.EventNumber = iEventNumber
    oEvent.EventType = iEventType 
    oEvent.EventSource = sEventSource
    oEvent.Message = sEventMessage
    ScriptContext.Submit oEvent
End Sub

 

TOP CPU:

'=============================================================================
'NAME        : TopProcesses Script
'AUTHOR        : Marcus C. Oh
'DATE        : 7/2/2008
'COMMENT        : Run as a response script to a rule that checks CPU utilization
'            : Bastardized from Microsoft Windows Base OS CPU Overload Script
'            : Lists processes utilizing % value of CPU over threshold
'            : Modified to post to Alert stream
'=============================================================================
Const EVENT_TYPE_SUCCESS = 0
Const EVENT_TYPE_ERROR = 1
Const EVENT_TYPE_WARNING = 2
Const EVENT_TYPE_INFORMATION = 4
Const EVENT_TYPE_AUDITSUCCESS = 8
Const EVENT_TYPE_AUDITFAILURE = 16

Set oWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & ScriptContext.TargetNetbiosComputer & "\root\cimv2")
Set oAlert = ScriptContext.Alert
 
lNumProcessors = GetNumProcessors()
iPercentage = ScriptContext.Parameters.Get("Percentage")
sMessage = ListCriticalProcesses(iPercentage,lNumProcessors)
oAlert.Description = oAlert.Description & VbCrLf & VbCrLf & "[Top CPU Processes]" & VbCrLf & sMessage

Sub CreateEvent(iEventNumber,iEventType,sEventSource,sEventMessage)
    Set oEvent = ScriptContext.CreateEvent()
    oEvent.EventNumber = iEventNumber
    oEvent.EventType = iEventType 
    oEvent.EventSource = sEventSource
    oEvent.Message = sEventMessage
    ScriptContext.Submit oEvent
End Sub

Function WMIGetObject(ByVal sNamespace)
    Dim oWMI
    Dim e
    Set e = New Error
    On Error Resume Next
    Set oWMI = GetObject(sNamespace)
    e.Save
    On Error Goto 0
    If IsEmpty(oWMI) Then
        ThrowScriptError "Unable to open WMI Namespace '" & sNamespace & "'.  Check to see if the WMI service is enabled and running, and ensure this WMI namespace exists.", e
    End If
    Set WMIGetObject = oWMI
End Function

Function GetNumProcessors()
    Dim oReg, sValue
    Const HKEY_LOCAL_MACHINE = &h80000002
    Const REGPATH_NUMBER_OF_CPUS = "SYSTEM\CurrentControlSet\Control\Session Manager\Environment\"
    Const REGKEY_NUMBER_OF_CPUS = "NUMBER_OF_PROCESSORS"
    Set oReg = WMIGetObject("winmgmts://" & ScriptContext.TargetNetbiosComputer & "/root/default:StdRegProv")
    oReg.GetStringValue HKEY_LOCAL_MACHINE, REGPATH_NUMBER_OF_CPUS, REGKEY_NUMBER_OF_CPUS, sValue
    GetNumProcessors = sValue
End Function

Function ListCriticalProcesses(Percentage,lNumProcessors)
    On Error Resume Next
    Dim oDictionary, oProcesses, oProcess
    Set oDictionary = CreateObject("Scripting.Dictionary")
    Set oProcesses = oWMIService.ExecQuery("SELECT * FROM Win32_PerfRawData_PerfProc_Process")
    For Each oProcess in oProcesses
        oDictionary.Item(oProcess.Name & oProcess.IDProcess & "%") = oProcess.PercentProcessorTime
        oDictionary.Item(oProcess.Name & oProcess.IDProcess & "#") = oProcess.Timestamp_Sys100NS
    Next
    Set oProcesses = Nothing

    ScriptContext.Sleep(500)

    Dim sProcesses, lNumProcesses
    Set oProcesses = oWMIService.ExecQuery("SELECT * FROM Win32_PerfRawData_PerfProc_Process")

    For Each oProcess In oProcesses
        lNumProcesses = lNumProcesses + 1
        Dim fPercentProcessor
        If oDictionary.Exists(oProcess.Name & oProcess.IDProcess & "%") Then
            fPercentProcessor = (oProcess.PercentProcessorTime - CDbl(oDictionary.Item(oProcess.Name & oProcess.IDProcess & "%"))) / _ 
            (oProcess.Timestamp_Sys100NS - CDbl(oDictionary.Item(oProcess.Name & oProcess.IDProcess & "#"))) * 100
            If (fPercentProcessor > (Percentage * lNumProcessors)) And (oProcess.IDProcess <> 0) Then
                sProcesses = sProcesses & oProcess.Name & " (" & oProcess.IDProcess & ") :" & _
                CInt(fPercentProcessor / lNumProcessors) & "%" & VbCrLf
            End If
        End If
    Next
    Set oProcesses = Nothing

    If Len(sProcesses) > 0 Then
        ListCriticalProcesses = "The processes using greater than " & Percentage & "% CPU at present are:" & vbCrLf & _
                                sProcesses & VbCrLf & _
                                "(There are " & lNumProcesses & " running at this time.)"
    End If
    Set oDictionary = Nothing
End Function

Function ThrowScriptErrorNoAbort(ByVal sMessage, ByVal oErr)
    Dim sErrDescription, sErrNumber
    sErrDescription = oErr.Description
    sErrNumber = oErr.Number
    On Error Resume Next
    Dim oScriptErrorEvent
    Set oScriptErrorEvent = ScriptContext.CreateEvent()
    With oScriptErrorEvent
        .EventNumber = 40000
        .EventType = EVENT_TYPE_ERROR
        .Message = sMessage
        .SetEventParameter """Top Processes"""
        .SetEventParameter sMessage
        .SetEventParameter sErrDescription
        .SetEventParameter sErrNumber
    End With
    ScriptContext.Submit oScriptErrorEvent
    ScriptContext.Echo "ThrowScriptError('" & sMessage & "')"
End Function

Class Error
    Private m_lNumber
    Private m_sSource
    Private m_sDescription
    Private m_sHelpContext
    Private m_sHelpFile
    Public Sub Save()
        m_lNumber = Err.number
        m_sSource = Err.Source
        m_sDescription = Err.Description
        m_sHelpContext = Err.HelpContext
        m_sHelpFile = Err.helpfile
    End Sub
    Public Sub Raise()
        Err.Raise m_lNumber, m_sSource, m_sDescription, m_sHelpFile, m_sHelpContext
    End Sub
    Public Sub Clear()
        m_lNumber = 0
        m_sSource = ""
        m_sDescription = ""
        m_sHelpContext = ""
        m_sHelpFile = ""
    End Sub
    Public Default Property Get Number()
        Number = m_lNumber
    End Property
    Public Property Get Source()
        Source = m_sSource
    End Property
    Public Property Get Description()
        Description = m_sDescription
    End Property
    Public Property Get HelpContext()
        HelpContext = m_sHelpContext
    End Property
    Public Property Get HelpFile()
        HelpFile = m_sHelpFile
    End Property    
End Class