#!/usr/bin/perl
#############################################################################
# Author:  Luuk de Boer <luuk@pi.net>
#
# Updated: 	1997-01-12
#	- changed the number of questions to the not-buggy version of mysqld.
#	  patch for the good number of questions is mailed on the mailinglist.
#	- changed number of threads to 'not relative' ... so you can see now
#	  how many threads are running. 
#	- added the possibility for arguments (hostname and portnumber) so
#	  you can use one mysqlstatus script for several hosts where a mysql 
#	  db server is running
#	- set default values (all 0) so mrtg won't fail if mysql is down and
#	  uptime is set to Server is down when mysql is down.
#	- current number of questions is used when current number of questions
#	  is lower as the old number of questions (for example when you 
#	  shutdown and start the mysql server)
#
# Start-date:    1997-01-09
#	- initial release of mrtg-mysql .... but mysql 3.21.19 seems to give
#	  wrong number of questions so tried to program around it.
# 
# Fetches output from mysqladmin status either via TCP or via exec and
# feeds number ofThreads and changes on Questions to mrtg.
#############################################################################

use strict;
use Socket;

my($datafile, $host, $port, @mysqladminpaths, $oldquest, $oldthread,
   $quest, $thread, $day,$hour,$min,$sec, $newquest, $newthread, $uptime);

# Adjust this to your own database/mysql server.  Uses local mysqladmin status 
# if set to 'localhost'
$host	= shift || "localhost";
$port	= shift || 7257;

$datafile       = "/tmp/mysqlstatus.old";
@mysqladminpaths = ( "/usr/local/mysql/bin/mysqladmin", "/usr/local/bin/mysqladmin" );

# get the old stats from the $datafile ...
($oldquest, $oldthread) = getOldStats($datafile);

# get the new stats from $host - $port
($newquest, $newthread, $uptime) = getStats($host, $port);

# transfering time string to a nice time stamp ...
if ($uptime > 0) {
  $day = int($uptime / 86400); 
  $hour = int(($uptime - ($day * 86400)) / 3600);
  $min = int(($uptime - ($day*86400) - ($hour*3600))/60);
  $sec = int($uptime - ($day*86400)-($hour*3600)-($min*60));

  # get nice uptime format ... 0 days, 03:49:52
  $uptime = sprintf "%d days, %02d:%02d:%02d",$day,$hour,$min,$sec;  
} else {
  $uptime = "Server is down";
}

# write the new values to the $datafile
putOldStats($datafile, $newquest, $newthread) || warn "$0: Unable to save stats to $datafile";

# this is the entry for the buggy Questions (till verson mysql-3.21.19):
# $quest = int($newquest-$oldquest/1000000);
# $quest = -$quest if ($quest < 0);
# this is the entry for the good Questions: (hope it is:-))
if ($newquest >= $oldquest) { # the normal way ...
  $quest = int($newquest-$oldquest);
} else {  # if mysqld is restarted
  $quest = $newquest;  
}

# we want to know the number of threads running ...
# so we take the new value we get ... so you can see
# how many threads are running at that moment
$thread = $newthread;

# print the output for mrtg ....
print "$quest\n$thread\n$uptime\n$host\n"; 

# the end of the program .....
exit;

###
### Subroutines
###

##
## Returns first line of file given as param splittet on space
##
sub getOldStats {
  my($filename) = @_;
  open(OLD, $filename) || warn "Can't read $filename: $!\n";
  my($line) = <OLD>;
  close(OLD);
  chomp($line);
  return split(/ /, $line);
}

##
## Returns the mysqladmin executable
##
sub findFirstExecutable {
  my(@path) = @_;
  my($filename);
  foreach $filename (@path) {
    return $filename if ( -x $filename && ! -d $filename );
  }
}

##
## Get the values of $host and parse it
## Returns no. questions, no. threads, uptime
##
sub getStats {
  my($host, $port) = @_;
  my(@output, $proto, $iaddr, $paddr);
  my($curquest, $curthread, $uptime,$reload);

  if ( $host eq "localhost" ) {
    my($progpath) = findFirstExecutable(@mysqladminpaths);
    @output = `$progpath status`;
    chomp(@output);
  } else {
    $port = getservbyname ($port, 'tcp') if ($port =~ /\D/);
    die "$0: Bad port \"$port\"" unless ($port);
    $proto = getprotobyname ('tcp') || die "$0: Bad prototype tcp";

    $iaddr = inet_aton($host) or die "$0: no host \"$host\"";
    $paddr = sockaddr_in($port, $iaddr);

    socket (SOCK, PF_INET, SOCK_STREAM, $proto) or die "$0: socket error $!";
    connect (SOCK, $paddr) or die "$0: connect error $!";

    while (<SOCK>) {
      push(@output,$_);
    }
    close(SOCK) || warn "$0: socket close error $!";
  }

  $curquest = $curthread = $uptime = $reload = 0;
  foreach (@output) {
    chomp;
    ($uptime,$curthread,$curquest,$reload) = m/Uptime:\s+(\d+)\s+Running\s+threads:\s+(\d+)\s+Questions:\s+(\d+)\s+Reloads:\s+(\d+)/i;
  }
  return ($curquest, $curthread, $uptime);
}

##
## Print the found values in the $datafile
##
sub putOldStats {
  my($filename, $quest, $thread) = @_;
  open(STAT, ">$filename") || warn "Can't write to $filename: $!\n";;
  print STAT "$quest $thread\n";
  close(STAT);
  return "1";
}

# The end
# Luuk de Boer <luuk@pi.net> 1998-01-09

