mpstat.pl to HTML.

index -|- end

Generated: Mon Aug 29 19:34:49 2016 from mpstat.pl 2015/12/23 25.9 KB. text copy

#!/usr/bin/perl -w
#################################################################
# from : http://pigeond.net/git/?a=project_list;pf=flightgear
# git: git://pigeond.net/flightgear/fgmap.git - hmpstat.bat
# AIM: Read a fmgs log file, and extract pilot records
#################################################################
use strict;
use warnings;
use Time::Local;
use POSIX qw(strftime);
use Getopt::Std;
use File::Basename;  # split path ($name,$dir,$ext) = fileparse($file [, qr/\.[^.]*/] )

# FIXME
my $SERVER_LOCAL = 'mpserver14 (UK)';
my $SERVER_TZ = -8;
my @CALLSIGNS_IGNORE = ('mpdummy', 'obscam', '', '');
my $TOP = 20;


my %pilots = ();

my %crafts_used = ();
my %crafts_used_pilots = ();
my %crafts_duration = ();

my $join_cnt = 0;
my @join_hashes = ();
my %join_duration = ();

my %current = ();

my %server_used = ();
my %server_callsign = ();

my $log_start_time = undef;
my $log_end_time = undef;

my $flight_duration = 0;

my $debug = 0;

#my($KEY) = "::";
my $KEY = ":";

#my($SEP) = ",";
my $SEP = " ";

my ($BN,$BP) = fileparse($0);

my %opts;
my $arg_start;
my $arg_end;
getopt('s:e:o:', \%opts);

if( $opts{'s'} && $opts{'s'} =~ /(\d\d\d\d)(\d\d)(\d\d)/)
{
    $arg_start = timelocal(0, 0, 0, $3, $2 - 1, ($1 - 1900));
}

if ( $opts{'e'} && $opts{'e'} =~ /(\d\d\d\d)(\d\d)(\d\d)/)
{
    $arg_end = timelocal(59, 59, 23, $3, $2 - 1, ($1 - 1900));
}

if ($arg_start && $arg_end && ($arg_end < $arg_start))
{
    print(STDERR $BN.": start time greater than end time\n");
    exit(-1);
}

if ($#ARGV < 0)
{
    print(STDERR "$BN: usage: $BN [-s YYYYMMDD] [-e YYYYMMDD] [-o output file or dir] <log files...>\n");
    print(STDERR "$BN: Error: Need an input of at least one fgms log file...\n");
    exit(-1);
}


my %model_lookup = (
"707" => "707/707-set.xml",
"737-300" => "737-300/737-300-set.xml",
"777-200" => "777-200/777-200-set.xml",
"787" => "787/787-set.xml",
"A-10-model" => "A-10/A-10-set.xml",
"a300b2" => "A300/A300-set.xml",

#"a320_100" => "A320-family/A320-111-set.xml",
#"a320_100" => "A320-family/A320-131-set.xml",
"a320_100" => "A320-family/A320-set.xml",

"a320-fb" => "A320/A320-set.xml",
"A380" => "A380/A380-set.xml",
"a4-blue" => "a4/a4-set.xml",
"a4-blue-uiuc" => "a4/a4-uiuc-set.xml",
"a4f-blue" => "a4/a4f-set.xml",
"a6m2-anim" => "A6M2/A6M2-set.xml",
"a6m2b-green" => "A6M2/A6M2b-set.xml",
"aerostar" => "Aerostar-700/aerostar700-set.xml",
"AN-225-model" => "AN-225/AN-225-set.xml",
"an2-model" => "an2/an2-set.xml",

"asw20-stuck-model" => "asw20/asw20-set.xml",
#"asw20-stuck-model" => "asw20/asw20-v1-nl-uiuc-set.xml",

"b1900d-anim" => "b1900d/b1900d-set.xml",

#"b29-model" => "b29/b29-jsbsim-set.xml",
#"b29-model" => "b29/b29-magic-set.xml",
"b29-model" => "b29/b29-set.xml",
#"b29-model" => "b29/b29-yasim-set.xml",

"B-52F-model" => "B-52F/B-52F-set.xml",
"BAC-TSR2-model" => "BAC-TSR2/BAC-TSR2-set.xml",
"baseline" => "f16/f16at-set.xml",
"beaufighter" => "beaufighter/beaufighter-set.xml",

#"beech99-model" => "beech99/beech99-v1-uiuc-set.xml",
#"beech99-model" => "beech99/beech99-yasim-set.xml",
"beech99-model" => "beech99/beech99-set.xml",

"bell206" => "bell206/bell206-set.xml",
"bf109" => "bf109/bf109-set.xml",
"bf109g-model" => "bf109/bf109g-set.xml",

#"bo105" => "as350/as350-set.xml",
"bo105" => "bo105/bo105-set.xml",
#"bo105" => "ch47/ch47-set.xml",
#"bo105" => "ch47/ch47-yasim-set.xml",

"Boeing314Clipper" => "Boeing314/Boeing314A-set.xml",
"boeing747-200" => "747-200/747-200-set.xml",

#"boeing747-400-jw" => "747/747-100-set.xml",
"boeing747-400-jw" => "747/747-set.xml",

"Bravo" => "Citation-Bravo/Bravo-set.xml",
"c150" => "c150/c150-set.xml",
"c172-dpm" => "c172r/c172r-set.xml",

#"c172p" => "c172p/c172p-2dpanel-set.xml",
"c172p" => "c172p/c172p-set.xml",

#"c182-dpm" => "c182/c182-2dpanel-set.xml",
"c182-dpm" => "c182/c182-set.xml",

"c182rg-dpm" => "c182rg/c182rg-set.xml",

#"c310-dpm" => "c310/c310dpm-3d-set.xml",
"c310-dpm" => "c310/c310-set.xml",

#"c310u3a" => "c310/c310-yasim-set.xml",
#"c310u3a" => "c310u3a/c310-ifr-set.xml",
"c310u3a" => "c310u3a/c310-set.xml",
#"c310u3a" => "c310u3a/c310u3a-jsbsim-set.xml",
#"c310u3a" => "c310u3a/c310u3a-set.xml",

"CanberraBI8-model" => "CanberraBI8/CanberraBI8-set.xml",
"ch53e-model" => "ch53e/ch53e-set.xml",
"Citation-II" => "Citation/Citation-II-set.xml",
"colditz-model" => "colditz/colditz-set.xml",
"ComperSwift-model" => "ComperSwift/ComperSwift-set.xml",
"Concorde_ba" => "Concorde/Concorde-set.xml",
"dc3-dpm" => "dc3/dc3-set.xml",
"dhc2floats" => "dhc2/dhc2F-set.xml",
"dhc2wheels" => "dhc2/dhc2W-set.xml",
"dhc6" => "dhc6/dhc6-set.xml",
"dr1" => "fkdr1/fkdr1-v1-nl-uiuc-set.xml",
"E3B" => "E3B/E3B-set.xml",
"ec135" => "ec135/ec135-set.xml",
"f104" => "f104/f104-set.xml",
"f15c" => "f15c/f15c-set.xml",

#"f16" => "f16/f16-3d-set.xml",
"f16" => "f16/f16-set.xml",

"f16klu" => "f16/f16-mlu-set.xml",
"f4u-model" => "F4U/f4u-set.xml",
"f80" => "F80C/F80C-set.xml",

"fgfs-tux-model" => "fgfs-tux/fgfs-tux-set.xml",
#"fgfs-tux-model" => "fgfs-tux/fgfs-tux-v1-nl-uiuc-set.xml",

"FINNAIRmd11" => "MD11/MD11-FINNAIR-set.xml",
"fokker100" => "fokker100/fokker100-set.xml",
"fokker50" => "fokker50/fokker50-set.xml",
"fokker70" => "fokker100/fokker70-set.xml",

"harrier-model" => "harrier/harrier-set.xml",

"hgldr-cs-model" => "airwaveXtreme150/airwaveXtreme150-set.xml",
#"hgldr-cs-model" => "airwaveXtreme150/airwaveXtreme150-v1-nl-uiuc-set.xml",

"hunter-model-2t" => "Hunter/hunter-2tanks-set.xml",
"hunter-model" => "Hunter/hunter-set.xml",
"hurricane_model" => "Hurricane/hurricaneIIb-set.xml",
"j22" => "j22/j22-set.xml",
"j3cub" => "j3cub/j3cub-set.xml",
"ju52" => "ju52/ju52-set.xml",
"KA6-D" => "KA6-D/KA6-D-set.xml",
"KC135" => "KC135/KC135-set.xml",
"ki-84" => "Ki-84/Ki-84-set.xml",
"KLMmd11" => "MD11/MD11-KLM-set.xml",

#"l410" => "l410/l410p-3d-jsbsim-set.xml",
"l410" => "l410/l410-set.xml",

"lightning-model" => "Lightning/lightning-set.xml",
"Lockheed1049_twa" => "Lockheed1049/Lockheed1049-set.xml",
"MD11" => "MD11/MD11-set.xml",
"MiG-15bis-model" => "MiG-15/MiG-15bis-set.xml",
"mirage2000" => "mirage2000/mirage2000-set.xml",

"opus-model" => "marchetti/marchetti-set.xml",
#"opus-model" => "marchetti/marchetti-v1-uiuc-set.xml",

"ornithopter-8-4-model" => "ornithopter/ornithopter-set.xml",

#"OV10" => "OV10/OV10_CDF-set.xml",
#"OV10" => "OV10/OV10_NASA-set.xml",
#"OV10" => "OV10/OV10_USAFE-set.xml",
"OV10" => "OV10/OV10-set.xml",

"p51d-jw" => "p51d/p51d-set.xml",
"pa24-250" => "pa24-250/pa24-250-set.xml",
"pa28-161" => "pa28-161/pa28-161-set.xml",

#"paraglider_model" => "paraglider/paraglider-jsbsim-set.xml",
"paraglider_model" => "paraglider/paraglider-set.xml",

"pc7" => "pc7/pc7-set.xml",

#"Rascal110" => "Rascal/Rascal110-JSBSim-set.xml",
#"Rascal110" => "Rascal/Rascal110-YASim-set.xml",
"Rascal110" => "Rascal/Rascal110-set.xml",

"Saab340-dpm" => "Saab340/Saab340dpm-3d-set.xml",
"santa" => "santa/santa-set.xml",
"seafire_model" => "Spitfire/seafireIIIc-set.xml",
"seahawk-3d-model" => "seahawk/seahawk-set.xml",
"sea-vixen-model" => "SeaVixen/sea-vixen-set.xml",

#"SenecaII" => "SenecaII/SenecaII-jsbsim-set.xml",
#"SenecaII" => "SenecaII/SenecaII-yasim-set.xml",
"SenecaII" => "SenecaII/SenecaII-set.xml",

#"sgs233" => "bocian/bocian-set.xml",
"sgs233" => "sgs233/sgs233-set.xml",

"sikorsky76c" => "Sikorsky-76C/s76c-set.xml",
"SinglePiston" => "ogel/ogel-set.xml",

"sopwithCamel-model" => "sopwithCamel/sopwithCamel-set.xml",
#"sopwithCamel-model" => "sopwithCamel/sopwithCamel-v1-nl-uiuc-set.xml",

"spitfire_model" => "Spitfire/spitfireIIa-set.xml",
"sr20" => "sr20/sr20-set.xml",
"SU-37-model" => "SU-37/SU-37-set.xml",
"t37" => "T37/T37-set.xml",
"T38-model" => "T38/T38-set.xml",
"TU-114-model" => "TU-114/TU-114-set.xml",
"tu154B" => "tu154/tu154-set.xml",
"ufo" => "ufo/ufo-set.xml",
"vulcanb2" => "vulcanb2/vulcanb2-set.xml",
"WrightFlyer-pb-jw" => "wrightFlyer1903/wrightFlyer1903-set.xml",
"X15_flight" => "X15/X15-set.xml",
"X15" => "X15/X15-new-set.xml",
"yardstik" => "YardStik/YardStik-set.xml",

#"YF-23-model" => "NTPS/NTPS-Eng-set.xml",
#"YF-23-model" => "NTPS/NTPS-HD1-set.xml",
#"YF-23-model" => "NTPS/NTPS-HD2-set.xml",
#"YF-23-model" => "NTPS/NTPS-OTW-HUD-set.xml",
#"YF-23-model" => "NTPS/NTPS-OTW-NOHUD-set.xml",
#"YF-23-model" => "YF-23/NTPS-set.xml",
"YF-23-model" => "YF-23/YF-23-set.xml",
);

sub array_max
{
    my(@arr) = @_;
    return (sort { $b <=> $a } @arr)[0];
}

sub hash_max
{
    my(%h) = @_;
    return (sort { $h{$b} <=> $h{$a} } keys(%h))[0];
}

sub escape_chars
{
    my($str) = @_;
    $str =~ s/[\[\]\(\)\^\$\/\.\*]/\\$&/g;
    return $str;
}

sub is_ignored
{
    my($callsign) = @_;
    return 1 if ($callsign =~ /Bad Client/i);
    return (scalar(grep(/^\Q${callsign}\E$/, @CALLSIGNS_IGNORE)));
}

sub dprint
{
    if($debug)
    {
        print(@_);
    }
}

sub min
{
    my($a, $b) = @_;
    return ($a < $b ? $a : $b);
}

sub max
{
    my($a, $b) = @_;
    return ($a > $b ? $a : $b);
}

sub datetime_to_epoch
{
    my($date, $time) = @_;
    my($ret);

    my($DD, $MM, $YY, $hh, $mm, $ss);

    ($DD, $MM, $YY) = split(/\./, $date);
    ($hh, $mm, $ss) = split(/\:/, $time);

    $ret = timelocal($ss, $mm, $hh, $DD, ($MM - 1), ($YY - 1900));
    $ret += ($SERVER_TZ * 3600);
    return $ret;
}


my %year_stats = ();
my %month_stats = ();
my %day_stats = ();
my %hour_stats = ();
my %dow_stats = ();

sub datetime_join
{
    my($t) = @_;
    my($dd, $mm, $yy, $hh, $dow) = (localtime($t))[3, 4, 5, 2, 6];
    $year_stats{$yy} += 1;
    $month_stats{$mm} += 1;
    $day_stats{$dd} += 1;
    $hour_stats{$hh} += 1;
    $dow_stats{$dow} += 1;
}


my %month_peak = ();
my %day_peak = ();
my %hour_peak = ();
my %dow_peak = ();

sub update_current_cnt
{
    my($cnt, $t) = @_;
    my($dd, $mm, $yy, $hh, $dow) = (localtime($t))[3, 4, 5, 2, 6];

    $month_peak{$mm} = max($cnt, $month_peak{$mm} || 0);
    $day_peak{$dd} = max($cnt, $day_peak{$dd} || 0);
    $hour_peak{$hh} = max($cnt, $hour_peak{$hh} || 0);
    $dow_peak{$dow} = max($cnt, $dow_peak{$dow} || 0);
}


sub model_lookup
{
    my($model) = @_;
    my($aircraft) = $model_lookup{$model};

    if(!$aircraft)
    {
        $model =~ s/-model$//g;
        $model =~ s/-anim$//g;
        $aircraft = $model."/".$model;
    }

    return $aircraft;
}


sub aircraft_path_split
{
    my($path) = @_;
    my($dir, $aircraft) = split(/\//, $path, 2);
    $aircraft =~ s/-set\.xml//g;
    return ($dir, $aircraft);
}

sub pilot_join
{
    my($callsign, $t, $mode, $model, $ip, $port) = @_;

    $join_cnt++;

    my(%join_hash);

    my($aircraft) = model_lookup($model);

    # key: callsign
    # value: (date,time,local/remote,model,ip,duration)
    %join_hash =
    (
        'callsign' => $callsign,
        'epoch' => $t,
        'mode' => $mode,
        'aircraft' => $aircraft,
        'model' => $model,
        'ip' => $ip,
        'port' => $port,
        'duration' => 0
    );

    dprint($callsign." joined\n");

    push(@join_hashes, \%join_hash);
    hash_push(\%pilots, $callsign, \%join_hash);

    crafts_used_pilots_add(\%crafts_used_pilots, $aircraft, $callsign);
    $crafts_used{$aircraft} += 1;

    if($mode eq 'LOCAL')
    {
        $server_used{'LOCAL'} += 1;
        $server_callsign{'LOCAL'}{$callsign} += 1;

    }
    elsif($mode eq 'REMOTE')
    {
        $server_used{$ip} += 1;
        $server_callsign{$ip}{$callsign} += 1;
    }

    datetime_join($t);

    my($ref);
    if($ref = $current{$callsign})
    {
        $ref->{'duration'} = $t - $ref->{'epoch'};
    }
    $current{$callsign} = \%join_hash;
}


sub pilot_part
{
    my($callsign, $t) = @_;

    my($ref);
    if($ref = $current{$callsign})
    {
        my($duration);

        $duration = $t - $ref->{'epoch'};

        $ref->{'duration'} = $duration;
        $crafts_duration{$ref->{'aircraft'}} += $duration;
        $join_duration{$callsign} += $duration;
        $flight_duration += $duration;

        dprint($callsign." parted\n");

        delete($current{$callsign});
    }
    else
    {
        # hmm...
        #print(STDERR "warning: $callsign parting without joining\n");
        dprint("warning: $callsign parting without joining\n");
    }
}


sub hash_push
{
    my($href, $key, $value) = @_;
    my($ref) = $href->{$key};

    dprint("key: $key\n");

    if($ref)
    {
        dprint("old ref find (@$ref)\n");
        push(@$ref, $value);
    }
    else
    {
        $href->{$key} = [ $value ];
        dprint("new ref (".$href->{$key}.")\n");
    }

}


sub crafts_used_pilots_add
{
    my($href, $aircraft, $callsign) = @_;

    if($href->{$aircraft})
    {
        $href->{$aircraft}->{$callsign} += 1;
    }
    else
    {
        $href->{$aircraft} = { $callsign => 1 };
    }
}


sub secs_to_dhms
{
    my($secs) = @_;
    my($str) = "";
    my($dd, $hh, $mm);
    $dd = int($secs / (24 * 60 * 60));
    $secs -= $dd * 24 * 60 * 60;
    $hh = int($secs / (60 * 60));
    $secs -= $hh * 60 * 60;
    $mm = int($secs / 60);
    $secs -= $mm * 60;

    if($dd > 0)
    {
        $str .= "${dd} day";
        $str .= "s" if($dd > 1);
    }
    if($hh > 0)
    {
        $str .= " " if($str ne '');
        $str .= "${hh} hour";
        $str .= "s" if($hh > 1);
    }
    if($mm > 0)
    {
        $str .= " " if($str ne '');
        $str .= "${mm} min";
        $str .= "s" if($mm > 1);
    }
    if($secs > 0)
    {
        $str .= " " if($str ne '');
        $str .= "${secs} sec";
        $str .= "s" if($secs > 1);
    }

    return $str;
}


dprint("pilots hash: ".\%pilots."\n");

my($f, $line);
my($main_t);
my $pilot_count = 0;
my $log_files = '';
# process the command line
foreach $f (@ARGV)
{
    if(! -f $f)
    {
        die("Cannot stat ".$f."\n");
        next;
    }

    open(IN, "<".$f) or die("Cannot open ".$f."\n");
    $log_files .= "$f ";
    while(<IN>)
    {
        $line = $_;
        chomp($line);


        my ($date, $time, $logline, $mode, $callsign, $model, $ip, $port);

        ($date, $time, $logline) =
            ($line =~ m/^\s*(\d+\.\d+\.\d\d\d\d)\s+(\d+:\d+:\d+)\s+(.*)$/);

        if(!defined($date) ||
            !defined($time) ||
            !defined($logline))
        {
            next;
        }

        my($t) = datetime_to_epoch($date, $time);

        if($arg_start && ($t < $arg_start))
        {
            next;
        }

        if($arg_end && ($t > $arg_end))
        {
            next;
        }

        $main_t = $t;

        if(!defined($log_start_time))
        {
            $log_start_time = $t;
        }

        if($logline =~
                /^New (.*?) Client: (.*?) (.*?):([0-9]+) \((.*?)\)$/)
        {
            # New pilot logging on
            $mode = $1;
            $callsign = $2;
            $ip = $3;
            $port = $4;
            $model = $5;

            if($model eq '' ||
                $model eq '* unknown *')
            {
                next;
            }

            if($model =~ /.*\/(.*?)$/)
            {
                $model = $1;
                if($model =~ /(.*?)\..*?$/)
                {
                    $model = $1;
                }
            }

            if(is_ignored($callsign))
            {
                next;
            }

            pilot_join($callsign, $t, $mode, $model, $ip, $port);
            $pilot_count++;

        }
        elsif($logline =~ /TTL exeeded, dropping pilot (.*?)  after/)
        {
            # Pilot logging off
            $callsign = $1;

            if($callsign eq "" || $callsign eq "* Bad Client *")
            {
                next;
            }

            if(is_ignored($callsign))
            {
                next;
            }

            pilot_part($callsign, $t);
        }
        elsif($logline =~ /current clients: (\d+) max: \d+/)
        {
            update_current_cnt($1, $t);
        }
        elsif($logline =~ /^# FlightGear Multiplayer Server .*? started$/)
        {
            my($k);
            foreach $k (keys(%current))
            {
                pilot_part($k, $t);
            }
        }
    }

    close(IN);

}
if ($pilot_count == 0) {
    print(STDERR "$BN: Error: Read logs $log_files, but found NO pilot records...\n");
    exit(-1);
}


# assuming the log is sequential in time
$log_end_time = $main_t;

my($k);

# Who hasn't parted yet?
foreach $k (keys(%current))
{
    my($ref) = $current{$k};
    my($duration) = $log_end_time - $ref->{'epoch'};
    $ref->{'duration'} = $duration;
    $crafts_duration{$ref->{'aircraft'}} += $duration;
    $join_duration{$k} += $duration;
    $flight_duration += $duration;
}

#foreach $k (keys(%pilots))
#{
#    my($a, $arr);
#    $arr = $pilots{$k};
#
#    print("$k:\n");
#
#    foreach $a (@$arr)
#    {
#        print("   ".$a->{'aircraft'}.":".$a->{'duration'}."\n");
#    }
#}
#print("\n\n");

if(!$log_start_time || !$log_end_time)
{
    print(STDERR "$BN: No data\n");
    exit(-1);
}

my($period_start) = strftime("%Y-%m-%d %H:%M:%S", localtime($log_start_time));
my($period_end) = strftime("%Y-%m-%d %H:%M:%S", localtime($log_end_time));
my($pilots_cnt) = scalar(keys(%pilots));
$flight_duration = secs_to_dhms($flight_duration);
my($generated) = strftime("%Y-%m-%d %H:%M:%S", localtime(time()));

my($XML) = <<XML;
<?xml version="1.0" encoding="utf-8"?>

<?xml-stylesheet type="text/xsl" href="mpstat.xsl"?>

<mpstat>

    <generated>${generated}</generated>
    <period-start>${period_start}</period-start>
    <period-end>${period_end}</period-end>
    <joins-count>${join_cnt}</joins-count>
    <pilots-count>${pilots_cnt}</pilots-count>
    <total-flight-time>${flight_duration}</total-flight-time>

XML



# server-stats

# TODO
my(%servernames) =
(
    '85.214.36.1' =>        'mpserver01 (Germany)',
    '202.65.223.218' =>     'mpserver02 (Hong Kong)',
    '62.75.184.124' =>      'mpserver03 (Germany)',
    '217.151.102.18' =>     'mpserver04 (U.K.)',
    '69.162.115.208' =>     'mpserver05 (Texas US)',
    '83.254.89.70' =>       'mpserver06 (Sweden)',
    '98.100.234.6' =>       'mpserver07 (Wisconsin US)',
    '217.172.186.31' =>     'mpserver08 (Germany)',
    '83.169.22.142' =>      'mpserver09 (Germany)',
    '194.9.62.110' =>       'mpserver10 (France)',
    '193.219.56.151' =>     'mpserver11 (Lithuania)',
    '62.129.133.10' =>      'mpserver12 (Netherlands)',
);

$XML .= "    <server-stats>\n";

sub servername_get
{
    my($ip) = @_;
    my($servername);

    if($ip eq 'LOCAL')
    {
        $servername = $SERVER_LOCAL;
    }
    elsif(!($servername = $servernames{$ip}))
    {
        $servername = $ip;
    }

    return $servername;
}

foreach $k (sort { servername_get($a) cmp servername_get($b) }
        (keys(%server_used)))
{
    my($servername) = servername_get($k);
    my($ref) = $server_callsign{$k};
    my($pilots) = scalar(keys(%$ref));

    if($servername =~ /\d+\.\d+\.\d+\.\d+/)
    {
        # Skip servers we don't know about
        next;
    }
    
    $XML .= <<XML;
        <server name="${servername}" ip="${k}" flights="$server_used{$k}" pilots="${pilots}" />
XML
}

$XML .= "    </server-stats>\n\n";


my (@truncated);

# aircraft-most-flight

@truncated = sort { $crafts_used{$b} <=> $crafts_used{$a} } keys(%crafts_used);
$#truncated = min($TOP - 1, scalar(@truncated) - 1);

$XML .= "    <aircraft-most-flight top=\"".scalar(@truncated)."\">\n";

foreach $k (@truncated)
{
    my($path, $aircraft) = aircraft_path_split($k);
    $XML .= <<XML;
        <aircraft aircraft="${aircraft}" path="${path}" flights="$crafts_used{${k}}" />
XML
}
$XML .= "    </aircraft-most-flight>\n\n";



# aircraft-most-pilot

sub crafts_used_pilots_func
{
    my($ha, $hb) = ($crafts_used_pilots{$a}, $crafts_used_pilots{$b});
    scalar(keys(%$hb)) <=> scalar(keys(%$ha));
}
@truncated = sort crafts_used_pilots_func keys(%crafts_used_pilots);
$#truncated = min($TOP - 1, scalar(@truncated) - 1);

$XML .= "    <aircraft-most-pilot top=\"".scalar(@truncated)."\">\n";

foreach $k (@truncated)
{
    my($h) = $crafts_used_pilots{$k};
    my($pilots) = scalar(keys(%$h));
    my($path, $aircraft) = aircraft_path_split($k);
    $XML .= <<XML;
        <aircraft aircraft="${aircraft}" path="${path}" pilots="${pilots}" />
XML
}

$XML .= "    </aircraft-most-pilot>\n\n";


# aircraft-longest-flight-total

@truncated = sort { $crafts_duration{$b} <=> $crafts_duration{$a} } keys(%crafts_duration);
$#truncated = min($TOP - 1, scalar(@truncated) - 1);

$XML .= "    <aircraft-longest-flight-total top=\"".scalar(@truncated)."\">\n";

foreach $k (@truncated)
{
    my($duration) = $crafts_duration{$k};
    $duration = secs_to_dhms($duration);
    my($path, $aircraft) = aircraft_path_split($k);
    $XML .= <<XML;
        <aircraft aircraft="${aircraft}" path="${path}" duration="${duration}" />
XML
}

$XML .= "    </aircraft-longest-flight-total>\n\n";



# pilots-most-flight

sub pilot_most_flight_func
{
    my($pa, $pb) = ($pilots{$a}, $pilots{$b});
    scalar(@$pb) <=> scalar(@$pa);
}
@truncated = sort pilot_most_flight_func keys(%pilots);
$#truncated = min($TOP - 1, scalar(@truncated) - 1);

$XML .= "    <pilots-most-flight top=\"".scalar(@truncated)."\">\n";

foreach $k (@truncated)
{
    my($ref) = $pilots{$k};
    my($flights) = scalar(@$ref);
    $XML .= <<XML;
        <pilot callsign="${k}" flights="${flights}" />
XML
}

$XML .= "    </pilots-most-flight>\n\n";



# pilots-longest-flight-single

@truncated = sort { $b->{'duration'} <=> $a->{'duration'} } @join_hashes;
$#truncated = min($TOP - 1, scalar(@truncated) - 1);

$XML .= "    <pilots-longest-flight-single top=\"".scalar(@truncated)."\">\n";

foreach $k (@truncated)
{
    my($duration) = secs_to_dhms($k->{'duration'});
    my($jointime) = strftime("%Y-%m-%d %H:%M:%S", localtime($k->{'epoch'}));
    my($path, $aircraft) = aircraft_path_split($k->{'aircraft'});
    $XML .= <<XML;
        <pilot callsign="$k->{'callsign'}" aircraft="${aircraft}" path="${path}" jointime="${jointime}" duration="${duration}" />
XML
}

$XML .= "    </pilots-longest-flight-single>\n\n";

# pilots-longest-flight-total

@truncated = sort { $join_duration{$b} <=> $join_duration{$a} } keys(%join_duration);
$#truncated = min($TOP - 1, scalar(@truncated) - 1);

$XML .= "    <pilots-longest-flight-total top=\"".scalar(@truncated)."\">\n";

foreach $k (@truncated)
{
    my($duration) = $join_duration{$k};
    $duration = secs_to_dhms($duration);
    $XML .= <<XML;
        <pilot callsign="${k}" duration="${duration}" />
XML
}

$XML .= "    </pilots-longest-flight-total>\n\n";

# month-stats

if(scalar(keys(%month_stats)) > 1)
{

    $XML .= "    <month-stats ".
        "max_flights=\"".$month_stats{hash_max(%month_stats)}."\" ".
        "max_peak=\"".$month_peak{hash_max(%month_peak)}."\" ".
        ">\n";

    my(@mon_strs) = ('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December');

    for($k = 0; $k < 12; $k++)
    {
        my($flights) = $month_stats{$k} || 0;
        my($peak) = $month_peak{$k} || 0;

        $XML .= <<XML;
        <month name="$mon_strs[${k}]" flights="${flights}" peak="${peak}" />
XML
    }
    $XML .= "    </month-stats>\n\n";
}


# day-stats

$XML .= "    <day-stats ".
        "max_flights=\"".$day_stats{hash_max(%day_stats)}."\" ".
        "max_peak=\"".$day_peak{hash_max(%day_peak)}."\" ".
        ">\n";

for($k = 1; $k <= 31; $k++)
{
    my($flights) = $day_stats{$k} || 0;

    my($dd_str) = $k;

    if($k == 1 || $k == 21 || $k == 31)
    {
        $dd_str .= 'st';
    }
    elsif($k == 2 || $k == 22)
    {
        $dd_str .= 'nd';
    }
    elsif($k == 3 || $k == 23)
    {
        $dd_str .= 'rd';
    }
    else
    {
        $dd_str .= 'th';
    }

    my($peak) = $day_peak{$k} || 0;

    $XML .= <<XML;
        <day name="${dd_str}" flights="${flights}" peak="${peak}" />
XML
}
$XML .= "    </day-stats>\n\n";


# hour-stats

$XML .= "    <hour-stats ".
    "max_flights=\"".$hour_stats{hash_max(%hour_stats)}."\" ".
    "max_peak=\"".$hour_peak{hash_max(%hour_peak)}."\" ".
    ">\n";

for($k = 0; $k < 24; $k++)
{
    my($flights) = $hour_stats{$k} || 0;
    my($hstr) = $k < 10 ? '0'.$k : $k;
    my($peak) = $hour_peak{$k} || 0;

    $XML .= <<XML;
        <hour hour="${hstr}" flights="${flights}" peak="${peak}" />
XML
}
$XML .= "    </hour-stats>\n\n";


# dow-stats

my(@dows) = ('Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday');

$XML .= "    <dow-stats ".
    "max_flights=\"".$dow_stats{hash_max(%dow_stats)}."\" ".
    "max_peak=\"".$dow_peak{hash_max(%dow_peak)}."\" ".
    ">\n";

for($k = 0; $k < 7; $k++)
{
    my($flights) = $dow_stats{$k} || 0;
    my($peak) = $dow_peak{$k} || 0;

    $XML .= <<XML;
        <dow day="$dows[$k]" flights="${flights}" peak="${peak}" />
XML
}
$XML .= "    </dow-stats>\n\n";




$XML .= <<XML;
</mpstat>

XML



my($outfile);
my($outdir) = "";

if($opts{'o'})
{
    ($outfile) = ($opts{'o'} =~ /([0-9a-zA-Z_\-\.\/]+)/);

    if(-d ${outfile})
    {
        $outdir = $outfile."/";
        $outfile = "";
    }
}

if(!$outfile || $outfile eq '')
{
    my($outfile_prefix) = 'mpstat-';
    my($outfile_suffix) = '.xml';

    my($start_date) = strftime("%Y-%m-%d", localtime($log_start_time));
    my($end_date) = strftime("%Y-%m-%d", localtime($log_end_time));

    $outfile = $outdir.
        $outfile_prefix.$start_date."-".$end_date.$outfile_suffix;
    print($outfile."\n");
}

my($out);
open($out, ">".$outfile);
print($out $XML);
close($out);

exit(0);

# eof

index -|- top

checked by tidy  Valid HTML 4.01 Transitional