Jump to content

Perl subroutine: Watch Remote Server

- - - - -

  • Please log in to reply
No replies to this topic

#1
phpforfun

phpforfun

    Speaks fluent binary

  • Members
  • PipPipPipPipPipPipPipPip
  • 1,236 posts
So for my hosting company, every now and then someones dedicated server will crash, its not really our job to find out why, unless they pay extra, we just get it booted up and let them troubleshoot. Reason why we can't do it for free, is because we cant just sit there and watch RDP for an hour when we have other customers in line. So what I did was I wrote a Perl script that will watch a remote server, and alert you when the CPU/Memory limits are at a certain level.

This isnt so much a tutorial, as it is just a script, but I added a ton of comments for ya, let me know how ya like it.

*NOTE* Unfortunately, the company I work for is mostly windows, thus, this only works on a windows machine, and can only monitor a windows machine, which you have access to and have permissions to specific WMI Namespaces. But you can try it on Localhost if you wish.

use Win32::OLE qw( in );
use Win32::Service;
use Win32::Process;
use POSIX qw/floor/;
use Switch;

# READY! CLEAR!
system("cls");

###################################
# CATCHING CTRL + C
$SIG{INT} = \&CTRLC;
sub CTRLC
{
    &SVR_START;
}

###################################
# SUB SUB_HELP: DISP HELP
sub SUB_HELP
{
    print "\nJust type 'watch localhost'\n\n";
    &SVR_START;
}

# START THE PROGRAM! Every sub goes to SVR_START, Its how we make the loop.
&SVR_START;

###################################
# SUB SVR_START: MONITOR THE SERVER
sub SVR_START
    {
    print "Input> ";
    chomp($input = <>);
    @args = split(" ", $input);
    $do = $args[0];

        switch ($do)
        {
                    #########################################
                    # CASE EXIT
                    #########################################
                    case "exit"
                        {
                            die();
                        }
                        
                    #########################################
                    # CASE WATCH
                    #########################################
                    case "watch"
                        {
                            print "\n";
                            if($args[1]){
                                #SETTING THE VARIABLES
                                
                                # What to watch, this will be watch $server
                                $server     = $args[1];
                                # CPU Limit, I set it as 90%
                                $cpu_limit     = 90;
                                # MEM Limit, I like it at 80%
                                $mem_limit     = 80;
                                # Check every x amount of seconds. NOTE: This is 2 seconds between each run, dosnt include how long it takes to run it.
                                $sleep         = 2;
                            } else {
                                &SUB_HELP;
                            }
                            
                            print "ctrl+c to stop watching..\n\n";
                            
                            # Not going to lie, Im not 100% sure what the following is for, I googled the sh*t out of it, couldnt find much
                            # But its required for all WMI Objects
                            use constant wbemFlagReturnImmediately => 0x10;
                            use constant wbemFlagForwardOnly => 0x20;
                            
                            # This is almost a sin! Im using a GOTO statement... Reason why is because I couldnt get it to display resunts within a sub routine
                            WATCH_START:
                            
                            # Create the WMI Service Object, calling from the CIMV2 namespace
                            $objWMIService = Win32::OLE->GetObject("winmgmts:\\\\$server\\root\\CIMV2") or $error = 1;
                            
                            #Did the computer refuse us?
                            if($error eq 1){
                                print "\nWMI connection failed to $computer.\n";
                                &SVR_START;
                            }
                            
                            # Run the WMI Query (Windows Query Language format), throw the results in a var. This is for the Processor Info
                            $colItems = $objWMIService->ExecQuery("SELECT * FROM Win32_Processor", "WQL", wbemFlagReturnImmediately | wbemFlagForwardOnly);
                            
                            foreach $objItem (in $colItems) {
                                # Clear the CMD window for each refresh
                                system ("cls");
                                # Is the CPU limit over the load limit?
                                if($objItem->{LoadPercentage} > $cpu_limit){
                                    # yes it is, BEEP!
                                    print "\a"
                                }
                                print "CPU: LoadPercentage: ". $objItem->{LoadPercentage} ."%\n";
                                
                            }
                            
                            # New query! Lets get the memory info..
                            $colItems = $objWMIService->ExecQuery("Select * from Win32_OperatingSystem");
                            print "MEM: ";
                            foreach my $objItem ( in $colItems ) {
                                $total_physical    = $objItem->{TotalVisibleMemorySize};
                                $free_physical    = $objItem->{FreePhysicalMemory};
                                $total_virtual    = $objItem->{TotalVirtualMemorySize};
                                $free_virtual    = $objItem->{FreeVirtualMemory};
                                $used_mem        = $total_physical - $free_physical;
                                $mem_percent     = $used_mem / $total_physical  * 100;
                                
                                if($mem_percent > $mem_limit){
                                    print "\a";
                                }
                                
                                $mem_percent    = floor($mem_percent);
                                
                                # Printf .. lets make it look pretty
                                printf("%-5s %-20s %-25s %-25s\n",  $mem_percent."%,", $total_physical . " Total,", $free_physical . " Free Physical,", $free_virtual . " Free Virtual");
                            }
                            
                            # SHOW TOP 10 PROGRAMS USING MEMORY over 20000000
                            # NOTE: Only reason the WMI query selects working sets over > 20000000, is because they
                            # Dont support the "order by" clause, hence I cant just order by WOrkingSetSize, and
                            # Return the first 10 results. So this only shows the first 10 results if they are over
                            # 20000000 k
                            print "\n\tTop 10 memory usage programs\n";
                            use constant wbemFlagReturnImmediately => 0x10;
                            use constant wbemFlagForwardOnly => 0x20;    

                            $colItems = $objWMIService->ExecQuery("SELECT * FROM Win32_Process WHERE WorkingSetSize > 20000000", "WQL", wbemFlagReturnImmediately | wbemFlagForwardOnly);

                            # START AN EMPTY ARRAY FOR TE PROCESSES
                            $aa = ();
                            
                            # LOOP THROUGH PROCESS RESULTS
                            foreach my $objItem (in $colItems) {
                                # Change $memory to something more readable
                                $memory = $objItem->{WorkingSetSize}/1024;
                                
                                # Push results into an array
                                push @aa, [$objItem->{ProcessId}, $objItem->{ParentProcessId}, $objItem->{KernelModeTime}, $memory, $objItem->{Caption}];
                            }
                            
                            # Sort the array by $aa[3] (The memory, highest on top)
                            @aa = sort{$b->[3] <=> $a->[3]} @aa;

                            $current     = 0;
                            $list         = 10;
                            
                            print "\n";
                            printf("%-6s %-6s %-15s %-10s %-15s %-10s\n", "PID", "PPID", "Time", "Mem (K)", "Name");
                            print "\n";
                            while ($current < $list){
                                printf("%-6s %-6s %-15s %-10s %-15s %-10s\n", $aa[$current][0], $aa[$current][1], $aa[$current][2], $aa[$current][3], $aa[$current][4]);
                                $current++;
                            }
                            sleep($sleep);
                            undef @aa;
                            goto WATCH_START;
                        }
                        
                        else
                        {
                            &SUB_HELP;
                        }
        }
}

Checkout my new forum! http://adminreference.com/




1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users