#!/usr/bin/perl # # $Header: //guest/robert_duff/p4scripts/monitor/p4listener.pl#2 $ # $Date: 2003/12/14 $ # $Author: robert_duff $ # # Description: Server side of p4monitor.pl use strict; use Socket; my $server_port=""; my $output_html=""; my $output_xml=""; my $output=""; my $temp_file="/usr/tmp/p4l-xml-".int(rand(1000)).".tmp"; my $temp_file2="/usr/tmp/p4l-html-".int(rand(1000)).".tmp"; my $dot=0; # Variables to import from XML. my %col; my $pid; my $date; my %uptime; my %uname; my %proc_time; my %proc_cpu; my %proc_mem; my %proc_pid; my %proc_user; my %proc_client; my %proc_op; my %proc_ip; my %proc_parent; my %proc_message; my $progname; ($progname = $0) =~ s#^.*/##; my $usage = <<USAGE; Usage: $progname [ -h -p port -html htmlfile -xml xmlfile -dot] This script listens for the output of p4monitor, processes it, and then prints the information out to an HTML file for serving on a web page. Parameters: -h, -?, help Print this help message. -p <port> Designates the port to listen for xml data. -html <htmlfile> The directory and file you want to serve as a web page. -xml <xmlfile> The directory and file you want to put the XML in. -dot Print a dot for every time the file(s) are written. USAGE my $parameter = 0; while($parameter <= $#ARGV) # For as many parameters there are, run this loop. { if($ARGV[0] eq "-h" or $ARGV[0] eq "-?" or $ARGV[0] eq "help" or $ARGV[0] eq "--help") # Print the usage information if -h was found, and then exit. { print STDERR $usage; exit 1; } elsif($ARGV[$parameter] eq "-p") { $parameter++; $server_port=$ARGV[$parameter]; } elsif($ARGV[$parameter] eq "-html") # Get the parameter for the html file, and then check to see if we can write to it. { $parameter++; $output_html=$ARGV[$parameter]; open(HTMLFILE, ">$output_html") or die "Cannot write to file $output_html: $!\n"; open(HTMLTEMP, ">$temp_file2") or die "Cannot write to file $temp_file2: $!\n"; close(HTMLFILE); close(HTMLTEMP); } elsif($ARGV[$parameter] eq "-xml") { $parameter++; $output_xml=$ARGV[$parameter]; open(XMLFILE, ">$output_xml") or die "Cannot write to file $output_xml: $!\n"; open(XMLTEMP, ">$temp_file") or die "Cannot write to file $temp_file: $!\n"; close(XMLFILE); close(XMLTEMP); } elsif($ARGV[$parameter] eq "-dot") { $dot=1; } else { die "Parameter: $ARGV[$parameter] is not recognized. Use the -h parameter for usage.\n"; } $parameter++; # On to the next parameter... } if($server_port == 0 or ($output_xml eq "" and $output_html eq "")) # If these parameters are blank, warn and exit. { if($server_port == 0) { print STDERR "Error: port must be between 1025 and 9999\n"; } if($output_xml eq "" and $output_html eq "") { print STDERR "Error: you must specify either an HTML or an XML file\n"; } print STDERR $usage; exit 1; } socket(Server, PF_INET, SOCK_STREAM, getprotobyname('tcp')); setsockopt(Server, SOL_SOCKET, SO_REUSEADDR, 1); my $my_addr = sockaddr_in($server_port, INADDR_ANY); bind(Server, $my_addr) or die "Couldn't bind to port $server_port: $!\n"; listen(Server, SOMAXCONN) or die "Couldn't listen on port $server_port: $!\n"; print "Listening for XML data on port: $server_port\n"; while (accept(Client, Server)) # When we accept a client, do this... { $| = 1; # autoflush if($output_xml) # Let the user know you're writing to the files s/he requested. { $output=$output_xml; } elsif($output_html) { $output=$output_html; } elsif($output_html and $output_xml) { $output=$output_xml." and ".$output_html; } print "Server (local) received connection from client. Sending output to: $output\n"; while(my $input = <Client>) # For as long as we're receiving data from a client... { if ("$input" eq "<?xml version=\"1.0\" ?>\n") # This should signify the beginning of the message. { if($dot==1) # Print a dot for every time we find the beginning of the message if -dot was a parameter. { print "."; } if ($output_xml) # If we are writing to XML, do this... { open(XMLTEMP, ">$temp_file") or die "Cannot write to file $temp_file: $!"; print XMLTEMP "<?xml version=\"1.0\" ?>\n"; } if ($output_html) # If we are writing to HTML, do this... { open(HTMLTEMP, ">$temp_file2") or die "Cannot write to file $temp_file2: $!"; print HTMLTEMP "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">\n<HTML>\n<HEAD>\n\n"; print HTMLTEMP "<!--\n Robert Duff\n p4monitor script output for Perforce.\n-->\n\n"; print HTMLTEMP "<TITLE>P4 Load Snapshot</TITLE>\n\n<META HTTP-EQUIV=\"REFRESH\" CONTENT=\"5\">\n"; print HTMLTEMP "</HEAD>\n\n<BODY>\n\n"; print HTMLTEMP "<CENTER><TABLE ALIGN=CENTER BORDER=0>\n<TR><TH>"; print HTMLTEMP "<FONT SIZE=+1 FACE=\"Tahoma, Arial, Helvetica\">\nPerforce Load Snapshot<BR><HR WIDTH=60%></TH>\n\n"; print HTMLTEMP "<TR><TD>\n"; print HTMLTEMP "<PRE>\n\n"; } } elsif ("$input" eq "</snapshot>\n") # This should signify the end of the message. Clean up and close files now. { if ($output_xml) { print XMLTEMP "</snapshot>\n"; close(XMLTEMP); `mv -f $temp_file $output_xml`; } if ($output_html) { printf HTMLTEMP "Machine Name: %-40s %s %s\n",$uname{machine_name}, "Load Average (one minute):", $uptime{load_one}; printf HTMLTEMP "OS Type: %-40s %s %s\n",$uname{os}, "Load Average (five minutes):", $uptime{load_five}; printf HTMLTEMP "OS Release: %-40s %s %s\n",$uname{release}, "Load Average (fifteen minutes):", $uptime{load_fifteen}; printf HTMLTEMP "Date and Time: %-40s %s %s\n\n",$date,"Machine has been up for:", $uptime{up}; printf HTMLTEMP "%9s %7s %5s %6s %15s\@%-30s %s\n", $col{start}, $col{mem}, $col{cpu}, $col{pid}, $col{user}, $col{client}, $col{op}; print HTMLTEMP "----------------------------------------------------------------------------------------------------------------------------------------------------\n"; foreach my $key (keys %{proc_time}) { if($proc_message{$key}) { printf HTMLTEMP "%9s %7s %5s %6s %s\n", $proc_time{$key}, $proc_mem{$key}, $proc_cpu{$key}, $proc_pid{$key}, $proc_message{$key}; delete $proc_time{$key}; delete $proc_mem{$key}; delete $proc_cpu{$key}; delete $proc_pid{$key}; delete $proc_message{$key}; } else { printf HTMLTEMP "%9s %7s %5s %6s %15s\@%-30s %s\n", $proc_time{$key}, $proc_mem{$key}, $proc_cpu{$key}, $proc_pid{$key}, $proc_user{$key}, $proc_client{$key}, $proc_op{$key}; delete $proc_time{$key}; delete $proc_mem{$key}; delete $proc_cpu{$key}; delete $proc_pid{$key}; delete $proc_user{$key}; delete $proc_client{$key}; delete $proc_op{$key}; } } print HTMLTEMP "\n</PRE>\n</TD></TR></TABLE>\n</BODY>\n</HTML>\n"; close(HTMLTEMP); `mv -f $temp_file2 $output_html`; } } else # This takes care of everything in between the beginning and the end. { if ($output_xml) # If we want XML, just print what we have, because it's already in XML. { print XMLTEMP $input; } if ($output_html) # If we want HTML, we have to do some fancy work. { chomp($input); $input =~ s#\s*(<\S*>)\s*(.*)\s*(</\S*>)\s*#$1$2$3#; $input =~ s#(<\S*>.*)\s+(</\S*>)#$1$2#; # Strip off the trailing spaces # Please excuse my change in formatting here. These if statements took too many lines for my taste. if ($input =~ /<col_start>/) { $col{start} = $input; $col{start} =~ s#<col_start>(\S*)</col_start>#$1#; } if ($input =~ /<col_mem>/) { $col{mem} = $input; $col{mem} =~ s#<col_mem>(\S*)</col_mem>#$1#; } if ($input =~ /<col_cpu>/) { $col{cpu} = $input; $col{cpu} =~ s#<col_cpu>(\S*)</col_cpu>#$1#; } if ($input =~ /<col_pid>/) { $col{pid} = $input; $col{pid} =~ s#<col_pid>(\S*)</col_pid>#$1#; } if ($input =~ /<col_user>/) { $col{user} = $input; $col{user} =~ s#<col_user>(\S*)</col_user>#$1#; } if ($input =~ /<col_client>/) { $col{client} = $input; $col{client} =~ s#<col_client>(\S*)</col_client>#$1#; } if ($input =~ /<col_op>/) { $col{op} = $input; $col{op} =~ s#<col_op>(.*)</col_op>#$1#; } if ($input =~ /<up>/) { $uptime{up} = $input; $uptime{up} =~ s#<up>(.*)</up>#$1#; } if ($input =~ /<load_fifteen>/) { $uptime{load_fifteen} = $input; $uptime{load_fifteen} =~ s#<load_fifteen>(\S*)</load_fifteen>#$1#; } if ($input =~ /<load_five>/) { $uptime{load_five} = $input; $uptime{load_five} =~ s#<load_five>(\S*)</load_five>#$1#; } if ($input =~ /<load_one>/) { $uptime{load_one} = $input; $uptime{load_one} =~ s#<load_one>(\S*)</load_one>#$1#; } if ($input =~ /<os>/) { $uname{os} = $input; $uname{os} =~ s#<os>(\S*)</os>#$1#; } if ($input =~ /<machine_name>/) { $uname{machine_name} = $input; $uname{machine_name} =~ s#<machine_name>(\S*)</machine_name>#$1#; } if ($input =~ /<release>/) { $uname{release} = $input; $uname{release} =~ s#<release>(\S*)</release>#$1#; } if ($input =~ /<date>/) { $date = $input; $date =~ s#<date>(.*)</date>#$1#; } if ($input =~ /<process pid/) { # Make a hash for each process element, with the key being the pid. chomp($pid = $input); $pid =~ s#\s*<process pid="(\d*)">#$1#; } if ($input =~ /<proc_time>/) { $proc_time{$pid} = $input; $proc_time{$pid} =~ s#<proc_time>\s*(\S*)\s*</proc_time>#$1#; } if ($input =~ /<proc_mem>/) { $proc_mem{$pid} = $input; $proc_mem{$pid} =~ s#<proc_mem>\s*(\S*)\s*</proc_mem>#$1#; } if ($input =~ /<proc_cpu>/) { $proc_cpu{$pid} = $input; $proc_cpu{$pid} =~ s#<proc_cpu>\s*(\S*)\s*</proc_cpu>#$1#; } if ($input =~ /<proc_pid>/) { $proc_pid{$pid} = $input; $proc_pid{$pid} =~ s#<proc_pid>\s*(\S*)\s*</proc_pid>#$1#; } if ($input =~ /<proc_user>/) { $proc_user{$pid} = $input; $proc_user{$pid} =~ s#<proc_user>\s*(\S*)\s*</proc_user>#$1#; } if ($input =~ /<proc_client>/) { $proc_client{$pid} = $input; $proc_client{$pid} =~ s#<proc_client>\s*(\S*)\s*</proc_client>#$1#; } if ($input =~ /<proc_op>/) { $proc_op{$pid} = $input; $proc_op{$pid} =~ s#<proc_op>\s*(.*)\s*</proc_op>#$1#; } if ($input =~ /<proc_ip>/) { $proc_ip{$pid} = $input; $proc_ip{$pid} =~ s#<proc_ip>\s*(\S*)\s*</proc_ip>#$1#; } if ($input =~ /<proc_parent>/) { $proc_parent{$pid} = $input; $proc_parent{$pid} =~ s#<proc_parent>\s*(\S*)\s*</proc_parent>#$1#; } if ($input =~ /<proc_message>/) { $proc_message{$pid} = $input; $proc_message{$pid} =~ s#<proc_message>\s*(.*)\s*</proc_message>#$1#; } } } } print STDOUT "Client closed connection.\n"; print STDOUT "Listening for XML data on port: $server_port\n"; } close(Server); print "Server is closed.\n";
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#2 | 4029 | Robert Duff |
p4listener.pl does not need to be restarted every time the client script ends now. It will now listen for a client after one finishes. p4monitor.pl now has a working DTD... It was horribly incorrect. |
||
#1 | 3332 | Robert Duff |
P4 Monitor is a script that matches Perforce's log output and ps information and displays it in XML format. This should allow people to easily write frontends to show the data in a nice, clean format. It also allows you to pipe the data over a network port for a listener on another machine. P4 Listener is a simple script that takes the output of P4 Monitor and formats it into a webpage. This allows you to do the monitoring on the Perforce server, but have the users hit another web server to view the data, easing the load on the Perforce server. |