Monitor CPU on up to for Windows Systems
"Russell Every" <[email protected]>
| Newsgroups | gmane.comp.python.pythoncard |
|---|---|
| Message-ID | <[email protected]> |
Ever wondered how your windows-based web server, application server, and database server are performing but you can't see them all at once? The attached files contain a simple CPU monitoring program developed using PythonCard that displays the CPU utilisation of up to four systems. By design, the first system is the one from which the monitor is launched (for me that is my PC) and the other three (or less) are listed in the configuration file. You will need to edit the configuration file to record the names of the systems you wish to monitor and the application should work straight away. The development was in Python 2.5.1 and PythoCard 0.8.2 and the Inno Setup Compiler is version 5.1.11. If you want an associated icon, edit the SystemMonitor.rsrc.py file on line 10 to remove the leading ### and replace the *** YOUR ICON FILENAME *** with the name of your icon file. There is a setup.py file to create an executable and, as this is expecting the name of the icon file, it will require editing before setup can be run. When running the setup, I used the python setup.py py2exe --bundle=2 command. There is also an Inno Setup file SystemMonitor.iss that will require some heavy modification for your program location and the icon file name (again). I hope it works on your system and that you find it useful. I expect that it could be significantly improved, both in functionality and implementation. However, it works well for me... Russell ------------------------------------------------------------------------- This SF.net email is sponsored by DB2 Express Download DB2 Express C - the FREE version of DB2 express and take control of your XML. No limits. Just data. Click to get it now. http://sourceforge.net/powerbar/db2/ _______________________________________________ Pythoncard-users mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/pythoncard-users
SystemMonitor.py
(text/x-python, 7.2 KB)
""" System Monitor
A system monitoring utility that shows the CPU activity for four systems
with the first of these being the system from which the monitor was launched
There is a configuration file that lists the names of the servers
to be monitored and the interval for each refresh of the display
"""
from PythonCard import model
from PythonCard.components import staticbox, bitmapcanvas, button
import wx
import time, random
from configobj import ConfigObj
import PerformanceCounter
import win32api
HOST = 0
GRAPH = 1
GAUGE = 2
HEIGHT = 3
WIDTH = 4
MAX_X = 5
POINTS = 6
CPU_DATA = 7
STATIC_TEXT = 8
X_COORDS = 9
class SystemMonitor(model.Background):
def on_initialize(self, event):
self.statusBar.text = "Starting data collection (it can take a while)"
"""Content on plotList is:
HOST Hostname
GRAPH Graph bitmap
GAUGE Gauge bitmap
HEIGHT Height of Graph and Gauge -- might delete this
WIDTH Width of Graph -- might delete this
MAX_X Maximum X coordinate of the Graph -- might delete this
POINTS Points to be plotted on the Graph
CPU_DATA Current CPU Utilisation (as a percentage)
STATIC_TEXT Label for the Graph and Gauge
X_COORDS x coordinates for each graph
"""
self.plotList = {}
config = ConfigObj("SystemMonitor.config")
machines = config["MACHINES"]["machines"]
self.interval = float(config["MACHINES"]["interval"])
# Build the list of machines. The first machine in the list is the current computer
current = win32api.GetComputerName()
self.plotList[current] = [current, self.components.bmpPlot1,
self.components.gInstant1, 0, 0, 0, [], 0, self.components.stbBox1, []]
numMc = len(machines)
if numMc > 0:
self.plotList[machines[0]] = [machines[0], self.components.bmpPlot2,
self.components.gInstant2, 0, 0, 0, [], 0, self.components.stbBox2, []]
if numMc > 1:
self.plotList[machines[1]] = [machines[1], self.components.bmpPlot3,
self.components.gInstant3, 0, 0, 0, [], 0, self.components.stbBox3, []]
if numMc > 2:
self.plotList[machines[2]] = [machines[2], self.components.bmpPlot4,
self.components.gInstant4, 0, 0, 0, [], 0, self.components.stbBox4, []]
# Setup the graphs and gauges for each machine
for key, details in self.plotList.iteritems():
details[GRAPH].autoRefresh = False
details[GRAPH].backgroundColor = "black"
details[GRAPH].clear()
details[GRAPH].enabled = True
details[GAUGE].autoRefresh = False
details[GAUGE].backgroundColor = "black"
details[GAUGE].clear()
details[GAUGE].enabled = True
# Remove These at some stage
details[WIDTH], details[HEIGHT] = details[GRAPH].size
details[MAX_X] = details[WIDTH] - 1
# End of Remove These
details[STATIC_TEXT].label = details[HOST]
# Setup the counter for this machine
details[CPU_DATA] = PerformanceCounter.HostCPU(details[HOST])
points = []
points.append(details[CPU_DATA].getUsage()*details[HEIGHT]//100)
details[POINTS] = points
# Set up the x coordindates as they don't vary (except for the range used)
xCoords = []
for x in xrange(details[WIDTH]):
xCoords.append(x)
details[X_COORDS] = xCoords
wx.Yield()
self.go = True
self.statusBar.text = ""
# Plot the points on an ongoing basis
while self.go:
time.sleep(self.interval)
for key, details in self.plotList.iteritems():
points = details[POINTS]
canvas = details[GRAPH]
gauge = details[GAUGE]
maxX = details[MAX_X]
xCoords = details[X_COORDS]
canvas.autoRefresh = False
canvas.clear()
# Draw the grid on an empty canvase
self.DrawGrid(canvas, "forest green", "forest green", 1, 10, 10)
# Add the new point to be added to the list and check ths list is not too long
cpuUsage = details[CPU_DATA].getUsage()
value = cpuUsage*details[HEIGHT]//100
points.append(value)
if len(points) > maxX:
points = points[1:]
details[POINTS] = points
# Now draw the line -- as you have to draw the line somewhere :-)
self.DrawLineSegment(canvas, points, "green", 1, maxX, xCoords)
# Update the instantaneous gauge (and value)
gauge.autoRefresh = False
gauge.clear()
self.UpdateGauge(gauge, cpuUsage, "forest green")
# Display the canvas now
canvas.refresh(True)
gauge.refresh(True)
wx.SafeYield(self)
def DrawGrid(self, canvas, xColour, yColour, thickness, xSpacing, ySpacing):
canvas.thickness = thickness
width, height = canvas.size
# Vertical grid lines
for x in xrange(canvas.size[0]/xSpacing):
canvas.foregroundColor = xColour
canvas.drawLine((x*xSpacing, 0), (x*xSpacing, height))
canvas.drawLine((width, 0), (width, height))
# Horizontal grid lines
for y in xrange(canvas.size[1]/ySpacing):
canvas.foregroundColor = yColour
canvas.drawLine((0, y*ySpacing), (width, y*ySpacing))
canvas.drawLine((0, height), (width, height))
def DrawLineSegment(self, canvas, points, colour, thickness, maxX, xCoords):
# This routine requires line segments so build them now
width, height = canvas.size
lines = []
numPoints = len(points)
startX = maxX - numPoints
for ptr in xrange(numPoints - 1):
x1 = xCoords[startX] + ptr
y1 = points[ptr]
y2 = points[ptr + 1]
segment = (self.TransformPoints(x1, y1, x1 + 1, y2, height))
lines.append(segment)
canvas.foregroundColor = colour
canvas.thickness = thickness
# Draw the lines now!
canvas.drawLineList(lines)
def TransformPoints(self, x1, y1, x2, y2, height):
# The wxBitmap origin is at the top left, so need to transform y coordinates
return (x1, height - y1, x2, height - y2)
def UpdateGauge(self, gauge, value, colour):
width, height = gauge.size
gauge.foregroundColor = colour
gauge.fillColor = colour
graphHeight = height - 20
topY = (100 - value)*graphHeight//100
sideY = graphHeight - topY
gauge.drawRectangle((5, topY), (width - 10, sideY))
gauge.foregroundColor = "green"
text = "%s%%" % value
gauge.drawText("%s%%" % value, (width//2 - 15, height - 15))
def on_btnExit_mouseClick(self, event):
self.go = False
self.close()
if __name__ == '__main__':
app = model.Application(SystemMonitor)
app.MainLoop()
PerformanceCounter.py
(text/x-python, 608 B)
import time
import win32pdh
class HostCPU:
def __init__(self, machine=None):
path = win32pdh.MakeCounterPath((machine, "Processor", "_Total", None, -1, "% Processor Time"))
self.base = win32pdh.OpenQuery()
self.counter = win32pdh.AddCounter(self.base, path)
self.reset()
#
def reset(self):
win32pdh.CollectQueryData(self.base)
#
def getUsage(self):
win32pdh.CollectQueryData(self.base)
# Get the formatted value of the counter
return win32pdh.GetFormattedCounterValue(self.counter, win32pdh.PDH_FMT_LONG)[1]
SystemMonitor.rsrc.py
(text/x-python, 3.1 KB)
{'application':{'type':'Application',
'name':'Minimal',
'backgrounds': [
{'type':'Background',
'name':'bgMin',
'title':'System Monitor, V0.0.1',
'size':(665, 630),
'statusBar':1,
# Enter the name of your icon file here
### 'icon':'*** YOUR ICON FILENAME ***',
'menubar': {'type':'MenuBar',
'menus': [
{'type':'Menu',
'name':'menuFile',
'label':'&File',
'items': [
{'type':'MenuItem',
'name':'menuFileExit',
'label':'E&xit\tAlt+X',
'command':'exit',
},
]
},
]
},
'components': [
{'type':'StaticBox',
'name':'stbBox4',
'position':(350, 270),
'size':(285, 230),
'label':'No 4',
},
{'type':'BitmapCanvas',
'name':'bmpPlot4',
'position':(420, 290),
'size':(200, 200),
'backgroundColor':(255, 255, 255, 255),
'enabled':False,
},
{'type':'BitmapCanvas',
'name':'gInstant4',
'position':(360, 290),
'size':(39, 200),
'backgroundColor':(255, 255, 255, 255),
'font':{'faceName': 'Verdana', 'family': 'sansSerif', 'size': 8},
},
{'type':'BitmapCanvas',
'name':'bmpPlot3',
'position':(90, 290),
'size':(200, 200),
'backgroundColor':(255, 255, 255, 255),
'enabled':False,
},
{'type':'StaticBox',
'name':'stbBox3',
'position':(20, 270),
'size':(285, 230),
'label':'No 3',
},
{'type':'BitmapCanvas',
'name':'gInstant3',
'position':(30, 290),
'size':(39, 200),
'backgroundColor':(255, 255, 255, 255),
'font':{'faceName': 'Verdana', 'family': 'sansSerif', 'size': 8},
},
{'type':'BitmapCanvas',
'name':'gInstant2',
'position':(360, 30),
'size':(39, 200),
'backgroundColor':(255, 255, 255, 255),
'font':{'faceName': 'Verdana', 'family': 'sansSerif', 'size': 8},
},
{'type':'BitmapCanvas',
'name':'bmpPlot2',
'position':(420, 30),
'size':(200, 200),
'backgroundColor':(255, 255, 255, 255),
'enabled':False,
},
{'type':'StaticBox',
'name':'stbBox2',
'position':(350, 10),
'size':(285, 230),
'label':'No 2',
},
{'type':'StaticBox',
'name':'stbBox1',
'position':(20, 10),
'size':(285, 230),
'label':'No 1',
},
{'type':'Button',
'name':'btnExit',
'position':(560, 520),
'label':'Exit',
},
{'type':'BitmapCanvas',
'name':'gInstant1',
'position':(30, 30),
'size':(39, 200),
'backgroundColor':(255, 255, 255, 255),
'font':{'faceName': 'Verdana', 'family': 'sansSerif', 'size': 8},
},
{'type':'BitmapCanvas',
'name':'bmpPlot1',
'position':(90, 30),
'size':(200, 200),
'backgroundColor':(255, 255, 255, 255),
'enabled':False,
},
] # end components
} # end background
] # end backgrounds
} }
SystemMonitor.config
(application/octet-stream, 154 B) - not displayed
setup.py
(text/x-python, 1.8 KB)
# Setup for System Monitor
# This stuff makes the windows look like XP themes
manifest_template = '''
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity
version="5.0.0.0"
processorArchitecture="x86"
name="%(prog)s"
type="win32"
/>
<description>%(prog)s Program</description>
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="X86"
publicKeyToken="6595b64144ccf1df"
language="*"
/>
</dependentAssembly>
</dependency>
</assembly>
'''
RT_MANIFEST = 24
from distutils.core import setup
import py2exe
import os
import string
# find pythoncard resources, to add as 'data_files'
resources = []
for filename in os.listdir('.'):
if filename.find('.rsrc.') > -1:
resources += [filename]
# Add in the config file
for filename in os.listdir('.'):
if filename.find('.config') > -1:
resources += [filename]
# Add in the icon files
for filename in os.listdir('.'):
if filename.find('.ico') > -1:
resources += [filename]
# Relace "*** YOUR ICON FILENAME ***" with the name of your icon
setup(
windows=[{
"script": "SystemMonitor.py",
"icon_resources": [(1, "*** YOUR ICON FILENAME ***")],
"other_resources": [(RT_MANIFEST, 1, manifest_template % dict(prog="System Monitor"))]
}],
py_modules = (["PerformanceCounter"]),
options = {"py2exe": {
"dll_excludes": (["gdiplus.dll"]),
"excludes": (["Image"])
}
},
data_files = [("", resources)]
)
SystemMonitor.iss
(text/plain, 2 KB)
; Script generated by the Inno Setup Script Wizard.
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
#define MyAppName "System Monitor"
#define MyAppVerName "System Monitor V0.0.1"
#define MyAppPublisher "*** YOUR COMPANY NAME ***"
#define MyAppExeName "SystemMonitor.exe"
[Setup]
AppName={#MyAppName}
AppVerName={#MyAppVerName}
AppPublisher={#MyAppPublisher}
DefaultDirName={pf}\{#MyAppName}
DisableDirPage=yes
DefaultGroupName={#MyAppName}
OutputBaseFilename=System Monitor Setup V0.0.1
SetupIconFile=C:\Projects\Python\Tools\SystemMonitor\dist\*** YOUR ICON FILENAME ***
Compression=lzma
SolidCompression=yes
[Languages]
Name: english; MessagesFile: compiler:Default.isl
[Tasks]
Name: desktopicon; Description: {cm:CreateDesktopIcon}; GroupDescription: {cm:AdditionalIcons}; Flags: unchecked
[Files]
Source: C:\Projects\Python\Tools\SystemMonitor\dist\SystemMonitor.exe; DestDir: {app}; Flags: ignoreversion
Source: C:\Projects\Python\Tools\SystemMonitor\dist\*** YOUR ICON FILENAME ***; DestDir: {app}; Flags: ignoreversion
Source: C:\Projects\Python\Tools\SystemMonitor\dist\library.zip; DestDir: {app}; Flags: ignoreversion
Source: C:\Projects\Python\Tools\SystemMonitor\dist\MSVCR71.dll; DestDir: {app}; Flags: ignoreversion
Source: C:\Projects\Python\Tools\SystemMonitor\dist\python25.dll; DestDir: {app}; Flags: ignoreversion
Source: C:\Projects\Python\Tools\SystemMonitor\dist\SystemMonitor.config; DestDir: {app}; Flags: ignoreversion
Source: C:\Projects\Python\Tools\SystemMonitor\dist\SystemMonitor.rsrc.py; DestDir: {app}; Flags: ignoreversion
Source: C:\Projects\Python\Tools\SystemMonitor\dist\w9xpopen.exe; DestDir: {app}; Flags: ignoreversion
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
[Icons]
Name: {group}\{#MyAppName}; Filename: {app}\{#MyAppExeName}
Name: {commondesktop}\{#MyAppName}; Filename: {app}\{#MyAppExeName}; Tasks: desktopicon
[Run]
Filename: {app}\{#MyAppExeName}; Description: {cm:LaunchProgram,{#MyAppName}}; Flags: nowait postinstall skipifsilent