Beefy Boxes and Bandwidth Generously Provided by pair Networks
Keep It Simple, Stupid
 
PerlMonks  

System usage monitor

by bofh_of_oz (Hermit)
on May 31, 2005 at 13:27 UTC ( [id://462045]=sourcecode: print w/replies, xml ) Need Help??
Category: Win32 Stuff
Author/Contact Info Eugene Michtchenko
BOFH_of_OZ
michtch(at)hotmail(dot)com

Description: The script is monitorint the usage of CPU, memory, and hard drive (or rather, logical drives) on a Win32 computer.

When you run it for the first time, it gathers essential server data (hostname, logical drives, total memory) and uses it to populate the central logging database. After this is done, the script continues to run but now it updates the database with the actual usage data.

The HDD (or partition/logical drive) usage is collected daily since it does not change very often. The memory usage stats are updated every minute. The CPU usage is calculated as average for all processors on a computer. The CPU usage stats are collected every second; however, to reduce the number of update queries to database (and the network load as well), we store them internally and do a batch update once a minute.

use DBI;
use DBD::mysql;
use Win32::API;
use Win32::PerfMon;
use Win32::DriveInfo;
use Sys::Hostname;

my @drives;
my %hdds;

my ($sec,$min,$hour,$mday,$month,$year, $wday,$yday,$isdst);
my ($bmem, $mem, $host, $dbh, $serverID, $usedMB, $logdate, $t, $cpulo
+ad);
my ($TotalNumberOfBytes, $totalMB, $volume, $drive, $sth, $ref);
my ($TotalNumberOfFreeBytes);
my ($len, $load, $totalphys, $availphys, $totalpage, $availpage, $tota
+lvirt, $availvirt);
my $grabInterval = 60;
my $hddcounter = 1440;
my $strSQL = '';
my $logserver = '10.1.1.1';


#---------------------------- Get server_id --------------------------
+----------
$host = hostname;
$dbh = DBI->connect("DBI:mysql:database=performance;host=$logserver",
                    "username", "password", {'RaiseError' => 1});

$sth = $dbh->prepare("SELECT server_id FROM servers WHERE server_name 
+= \'$host\'");
$sth->execute();
$ref = $sth->fetchrow_hashref();
$sth->finish();
$serverID = $ref->{'server_id'};
if (! defined $ref->{'server_id'}) #This server is not in database - u
+pdate DB
{
   $dbh->do("INSERT INTO servers (server_name) VALUES (" . $dbh->quote
+("$host") . ")");

   my $sth = $dbh->prepare("SELECT server_id FROM servers WHERE server
+_name = \'$host\'");
   $sth->execute();
   my $ref = $sth->fetchrow_hashref();
   $serverID = $ref->{'server_id'};
   $sth->finish();

   $bmem = " " x 32;
   $mem = new Win32::API('kernel32', 'GlobalMemoryStatus', 'P', 'N');
   $mem->Call($bmem);
   ($len, $load, $totalphys, $availphys, $totalpage, $availpage, $tota
+lvirt,
    $availvirt) = unpack('IIIIIIII', $bmem);
   $totalMB = int($totalphys/1024/1024);
   $dbh->do("INSERT INTO mem VALUES ($serverID, $totalMB, 80)");

   @drives = Win32::DriveInfo::DrivesInUse();
   foreach $drive (@drives)
   {
      if (Win32::DriveInfo::DriveType($drive) == 3 )  #If the disk is 
+HDD
      {
         $TotalNumberOfBytes = (Win32::DriveInfo::DriveSpace($drive ))
+[5];
         $totalMB = int($TotalNumberOfBytes / 1048576);
         $dbh->do("INSERT INTO hdd (server_id, volume_name, capacityMB
+, threshold) " .
                  "VALUES ($serverID, ".$dbh->quote("$drive").", $tota
+lMB, 70)");
      }
   }
}


$sth = $dbh->prepare("SELECT volume_id, volume_name FROM hdd WHERE ser
+ver_id = \'$serverID\'");
$sth->execute();
while ($ref = $sth->fetchrow_hashref()) 
{
   $hdds{$ref->{'volume_name'}} = $ref->{'volume_id'};
}
$sth->finish();

  

#---------------------------------------------------------------------
+----------

my $PerfObj = Win32::PerfMon->new(".");
$PerfObj->AddCounter("Processor","% Processor Time", "_Total");

while (1)  #Main loop, infinite...
{
   #Calculate the CPU load
   for (1..$grabInterval)
   {
      #Calculate the date for logging into database
      ($sec,$min,$hour,$mday,$month,$year, $wday,$yday,$isdst) = local
+time time;
      $month++;
      foreach $t ($mday, $month, $hour, $min, $sec)
      {
         if ($t < 10) {$t = '0' . $t;}
      }
      $year=substr($year,1);
      $year="20".$year if length($year)==2;
      $logdate="$year-$month-$mday $hour:$min:$sec";

      # Populate the counters from perfmon
      $PerfObj->CollectData();
      $cpuload = $PerfObj->GetCounterValue("Processor","% Processor Ti
+me", "_Total");
                
      # Do something with $value - e.g. store it in a DB
      $strSQL .= " (\'$logdate\', $serverID, $cpuload),";

      sleep 1;
   }
   #Dump the gathered CPU load data into the database
   chop $strSQL;
   $dbh->do("INSERT INTO cpu_usage VALUES $strSQL");
   $strSQL = ''; #Clear the variable for the next cycle
   
   #Calculate the memory usage
   $bmem = " " x 32;
   $mem = new Win32::API('kernel32', 'GlobalMemoryStatus', 'P', 'N');
   $mem->Call($bmem);
   ($len, $load, $totalphys, $availphys, $totalpage, $availpage, $tota
+lvirt,
       $availvirt) = unpack('IIIIIIII', $bmem);
   $usedMB = int(($totalphys-$availphys)/1024/1024);  #Store used memo
+ry in MB

   #Log the usage into the database
   $dbh->do("INSERT INTO mem_usage VALUES (".$dbh->quote("$logdate")."
+, $serverID, $usedMB)");
   
   
   #HDD usage logging
   if ($hddcounter == 1440)
   {
      $hddcounter = 0;

      foreach $drive (keys %hdds)
      {
         $TotalNumberOfFreeBytes = (Win32::DriveInfo::DriveSpace($driv
+e ))[6];
         $TotalNumberOfBytes = (Win32::DriveInfo::DriveSpace($drive ))
+[5];
         $usedMB = int(($TotalNumberOfBytes - $TotalNumberOfFreeBytes)
+/1048576);

         #Create SQL statement
         $logdate="$year-$month-$mday";
         $volume = $hdds{$drive};
         $dbh->do("INSERT INTO hdd_usage VALUES (\'$logdate\', \'$volu
+me\', $usedMB)");
      }
   }else
   {
      $hddcounter++;
   }
}

$dbh->disconnect();
Replies are listed 'Best First'.
Re: System usage monitor
by ghenry (Vicar) on May 31, 2005 at 13:44 UTC

    P.S. I hope this works with use strict; and use warnings;

    I presume so ;-)

    Walking the road to enlightenment... I found a penguin and a camel on the way.....
    Fancy a yourname@perl.me.uk? Just ask!!!
      It did on Win2K and WinXP Pro computers... In fact, I deleted those two lines from the code when posting as I've seen somewhere that they shouldn't be in production code...

      --------------------------------
      An idea is not responsible for the people who believe in it...

        You should definitely have strict in production code, but I think warnings can be dropped after development.

        Anyone care to back me up?

        Walking the road to enlightenment... I found a penguin and a camel on the way.....
        Fancy a yourname@perl.me.uk? Just ask!!!

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: sourcecode [id://462045]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others pondering the Monastery: (6)
As of 2024-04-19 14:12 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found