#! /usr/bin/env perl ##************************************************************** ## ## Copyright (C) 1990-2007, Condor Team, Computer Sciences Department, ## University of Wisconsin-Madison, WI. ## ## Licensed under the Apache License, Version 2.0 (the "License"); you ## may not use this file except in compliance with the License. You may ## obtain a copy of the License at ## ## http://www.apache.org/licenses/LICENSE-2.0 ## ## Unless required by applicable law or agreed to in writing, software ## distributed under the License is distributed on an "AS IS" BASIS, ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ## See the License for the specific language governing permissions and ## limitations under the License. ## ##************************************************************** use warnings; use strict; sub ParseHex($); sub DumpHistories( $$ ); sub DumpHistory( $$$ ); sub Usage ( $$ ); sub Help ( $ ); my %Config = ( HistMin => 0, HistMax => 99999, Long => 0, SummaryOnly => 0, UpdateInterval => 0, DumpTime => 1, ); my $Program = "condor_updates_stats"; my $RevisionString = '$Revision: 1.5 $'; my $CondorVersion = '$CondorVersion$'; my $CondorPlatform = '$CondorPlatform$'; my %Help = ( Usage => "$Program [options]", Options => { "[--long|-l]" => "Enable long output ", "[--summary|-s]" => "Summary-only mode ", "[--history=[min][-max]]" => "Set history range from min to max", "[--[no]time]" => "Enable / disable time output (if available) ", "[--interval=seconds]" => "Force ad update interval to seconds ", "[--version]" => "Displays version information ", "[--help|-h]" => "Dump help", }, ); # Parse command line... foreach my $Arg ( @ARGV ) { if ( $Arg =~ /^--history=(\d*)(-(\d+))?$/ ) { $Config{HistMin} = $1 if ( $1 ne "" ); $Config{HistMax} = $3 if ( defined $3 && $3 ne "" ); } elsif ( $Arg =~ /^--interval=(\d+)/ ) { $Config{UpdateInterval} = $1; $Config{DumpTime} = 1; } elsif ( $Arg eq "--summary|-s" or $Arg eq "-s" ) { $Config{SummaryOnly} = 1; } elsif ( $Arg eq "--time" ) { $Config{DumpTime} = 1; } elsif ( $Arg eq "--notime" ) { $Config{DumpTime} = 0; } elsif ( ( $Arg eq "--long" ) || ( $Arg eq "-l" ) ) { $Config{Long} = 1; } elsif( $Arg eq "--version" ) { if ( length( $CondorVersion ) > 20 ) { print "$CondorVersion\n"; print "$CondorPlatform\n"; } elsif ( open( CV, "condor_version|" ) ) { while( ) { print; } close( CV ); } else { if ( $RevisionString =~ /([\d\.]+)/ ) { $RevisionString = $1; } print "$Program version: $RevisionString\n"; } exit 0; } elsif( ( $Arg eq "--help" ) || ( $Arg eq "-h" ) ) { Help( \%Help ); exit 0; } else { Usage( \%Help, $Arg ); exit 1; } } $#ARGV = -1; # Just pull from stdin... my %AdInfo; my %UpdateTypes; my $UpdateHistories = 0; while( <> ) { chomp; if ( /(\w*)\s*=\s*\"(.*)\"$/ ) { my $Attr = $1; my $Value = $2; $AdInfo{$Attr} = $Value; if ( $Attr =~ /^UpdatesHistory/ ) { $UpdateHistories++; } elsif ( $Attr =~ /^Updates.*_(.*)/ ) { $UpdateTypes{$1} = 1; } } elsif ( /(\w*)\s*=\s*(.*)$/ ) { my $Attr = $1; my $Value = $2; $AdInfo{$Attr} = $Value; if ( $Attr =~ /^UpdatesHistory/ ) { $UpdateHistories++; } elsif ( $Attr =~ /^Updates.*_(.*)/ ) { $UpdateTypes{$1} = 1; } } else { DumpHistories( \%AdInfo, \%UpdateTypes ) if ( $UpdateHistories ); %AdInfo = (); %UpdateTypes = (); $UpdateHistories = 0; } } # Dump all history info sub DumpHistories( $$ ) { my $Ad = shift; my $Types = shift; my $Name = "*Unknown*"; my $MyType = "*Unknown*"; # Pull out the name, etc. if ( exists $Ad->{Name} ) { $Name = $Ad->{Name}; } elsif ( exists $Ad->{Machine} ) { $Name = $Ad->{Machine}; } $MyType = $Ad->{MyType} if ( exists $Ad->{MyType} ); my $NameStr = "*** Name/Machine = '$Name' MyType = '$MyType' ***"; if ( DumpHistory( $NameStr, $Ad, undef ) ) { $NameStr = ""; } foreach my $Type ( keys %{$Types} ) { DumpHistory( $NameStr, $Ad, $Type ); } } # Dump history info sub DumpHistory( $$$ ) { my $NameStr = shift; my $Ad = shift; my $Type = shift; my $UpdateInterval = $Config{UpdateInterval}; my %Updates; if ( ! defined $Type ) { if ( exists $Ad->{UpdatesTotal} ) { $Updates{Total} = $Ad->{UpdatesTotal}; $Updates{Seq} = $Ad->{UpdatesSequenced}; $Updates{Lost} = $Ad->{UpdatesLost}; } if ( exists $Ad->{UpdatesHistory} ) { $Updates{Hist} = $Ad->{UpdatesHistory}; } } else { if ( exists $Ad->{"UpdatesTotal_".$Type} ) { $Updates{Total} = $Ad->{"UpdatesTotal_".$Type}; $Updates{Seq} = $Ad->{"UpdatesSequenced_".$Type}; $Updates{Lost} = $Ad->{"UpdatesLost_".$Type}; } if ( exists $Ad->{"UpdatesHistory_".$Type} ) { $Updates{Hist} = $Ad->{"UpdatesHistory_".$Type}; } } #Anything to do? if ( ( scalar keys %Updates ) < 0 ) { return 0; } # Extract the update interval if it exists... if ( exists $Ad->{UpdateInterval} && ( $Ad->{UpdateInterval} =~ /^\d/ ) ) { $UpdateInterval = $Ad->{UpdateInterval}; } # Dump the title string print "$NameStr\n" if ( $NameStr ne "" ); print " Type: " . ( ( defined $Type ) ? "$Type" : "Main" ) . "\n"; # Dump the "summary" info if ( exists $Updates{Total} ) { my $LostPercent = "0.00"; if ( $Updates{Seq} ) { $LostPercent = sprintf( "%.2f", 100.0 * $Updates{Lost} / $Updates{Seq} ); } print " Stats: Total=$Updates{Total}, Seq=$Updates{Seq}, ". "Lost=$Updates{Lost} ($LostPercent\%)\n"; } # Summary mode: we're done return 1 if ( $Config{SummaryOnly} ); # Dump the "History" info if ( exists $Updates{Hist} ) { my @History = ParseHex( $Updates{Hist} ); my $UpdateNum = 0; my $LastStatus = -1; my $Repeats = 0; my $Time = time( ); $Time = $Ad->{LastHeardFrom} if ( exists $Ad->{LastHeardFrom} ); foreach my $Sample ( 0 .. $#History ) { if ( ( $Sample >= $Config{HistMin} ) && ( $Sample <= $Config{HistMax} ) ) { my $Status = $History[$Sample]; if ( ( ! $Config{Long} ) && ( $Status == $LastStatus ) && ( $Sample < $#History ) ) { print " ...\n" if ( ! $Repeats ); $Repeats++; } else { $Repeats = 0; my $TimeStr = ""; if ( $UpdateInterval && $Config{DumpTime} ) { $TimeStr = " @ " . localtime( $Time ); } printf " %4d%s: %s\n", $UpdateNum, $TimeStr, $Status ? "Ok" : "Missed"; } $LastStatus = $Status; } $Time -= $UpdateInterval; $UpdateNum++; } print "\n"; } return 1; } # Parse the hex string into array of ints sub ParseHex( $ ) { my $Hex = shift; $Hex =~ s/^0x//i; my @History; my $Len = length( $Hex ) - 1; foreach my $Offset ( 0 .. $Len ) { my $HexChar = substr( $Hex, $Offset, 1 ); my $Value = hex( $HexChar ); foreach my $Mask ( 0x8, 0x4, 0x2, 0x1 ) { my $Bit = ( $Mask & $Value ) ? 0 : 1; push( @History, $Bit ); } } @History; } # ****************************************************** # Dump out usage # ****************************************************** sub Usage ( $$ ) { my $Help = shift; my $Unknown = shift; print "$Program: unknown argument: '$Unknown'\n" if ( $Unknown ne "" ); printf "usage: " . $Help->{Usage} . "\n"; print "use '-h' for more help\n"; exit 1; } # usage () # ****************************************************** # ****************************************************** # Dump out help # ****************************************************** sub Help ( $ ) { my $Help = shift; my ($opt, $text); printf "usage: " . $Help->{Usage} . "\n"; foreach $opt (sort {lc($a) cmp lc($b) } keys %{$Help->{Options}}) { printf (" %32s : %-40s\n", $opt, $Help->{Options}{$opt} ); } exit 0; } # help () # ******************************************************