#!/usr/bin/perl -w
#
# perf_scan - list host/service latency/execution time culprits.
#
# Author: Daniel Jerverén <support@op5.com>
#
# Copyright(C) 2015 op5 AB
# All rights reserved.
#

use strict;
use Getopt::Std;
$Getopt::Std::STANDARD_HELP_VERSION = 1;
use vars qw(%host_lat %host_exec %svc_lat %svc_exec %opts $host $service %max_len);

&getopts('hl:s', \%opts);
print "perf_scan 0.1. For usage, see --help\n\n";


# Ask livestatus for latency/exec time for hosts and services.
open(IN, "mon query ls services -c host_name,host_latency," .
	"host_execution_time,description,latency,execution_time|") || die "$!";

while (<IN>) {
	chomp;
	my @str = split(';',$_);

	# Collect host check statistics.
	$max_len{h} = &get_len("h",$str[0]);
	$host_lat{$str[0]} = &sci2dec($str[1]);
	$host_exec{$str[0]} = &sci2dec($str[2]);

	# Collect service check statistics.
	$max_len{s} = &get_len("s","$str[0] $str[3]");
	$svc_lat{"$str[0] $str[3]"} = &sci2dec($str[4]);
	$svc_exec{"$str[0] $str[3]"} = &sci2dec($str[5]);
}
close(IN);


# Are we using default line count or user-defined?
my $count = 0;
my $limit = 5;
if (defined($opts{l})) {
	$limit = $opts{l};
}

# Use longest service line count format if we are listing both hosts and services.
$max_len{h} = $max_len{s} if ((defined($opts{s})) || (!defined($opts{s})) && (!defined($opts{h})));

# Print hosts if -h was defined, or if both -h and -s were omitted.
if ((defined($opts{h})) || (!defined($opts{s})) && (!defined($opts{h}))) {
	print "\nHost check execution time:\n";
	foreach my $h (sort { $host_exec{$b} <=> $host_exec{$a} } keys %host_exec) {
		$count++;
		last if ($count > $limit); 

		printf("%-$max_len{h}s %8.3f seconds\n", $h, $host_exec{$h});
	}

	$count = 0;
	print "\nHost check latency:\n";
	foreach my $h (sort { $host_lat{$b} <=> $host_lat{$a} } keys %host_lat) {
		$count++;
		last if ($count > $limit); 

		printf("%-$max_len{h}s %8.3f seconds\n", $h, $host_lat{$h});
	}
}

# Print services if -s was defined, or if both -h and -s were omitted.
if ((defined($opts{s})) || (!defined($opts{s})) && (!defined($opts{h}))) {
	$count = 0;
	print "\nService check execution time:\n";
	foreach my $s (sort { $svc_exec{$b} <=> $svc_exec{$a} } keys %svc_exec) {
		$count++;
		last if ($count > $limit);

		printf("%-$max_len{s}s %8.3f seconds\n", $s, $svc_exec{$s});
	}

	$count = 0;
	print "\nService check latency:\n";
	foreach my $s (sort { $svc_lat{$b} <=> $svc_lat{$a} } keys %svc_lat) {
		$count++;
		last if ($count > $limit); 

		printf("%-$max_len{s}s %8.3f seconds\n", $s, $svc_lat{$s});
	}
}


# Convert scientific to decimal notation.
sub sci2dec {
	my $val = sprintf("%.10g", $_[0]);
	return $val;
}

# Calculate host/service string lengths for output formatting.
sub get_len {
	my ($type,$val) = @_;

	my $len = length($val);
	if ((!defined($max_len{$type})) || ($len > $max_len{$type})) {
		return $len;
	} else {
		return $max_len{$type};
	}
}

# Internal GetOpt version sub.
sub VERSION_MESSAGE {
    print "perf_scan 0.2\n";
}

# Internal GetOpt help sub for --help.
sub HELP_MESSAGE {
    print "\nUsage: perf_scan [OPTIONS]\n\n" .
	"OPTIONS:\n" .
	"\t-h\t\tlist hosts\n" .
	"\t-s\t\tlist services\n" .
	"\t-l <num>\tnumber of hosts/services to show (default 5)\n\n"; 
}
