W . A . X . O
ncc-1701
LINUX - UNIX




MRTG - Multi Router Traffic Grapher

PRINCIPE et CONFIGURATION

  • Site officiel de MRTG : oss.oetiker.ch/mrtg/
  • L'executable mrtg est lancé avec /etc/mrtg.cfg comme argument.
  • Le fichier de configuration mrtg.cfg liste des rubriques pour chaque élément (cpu, process, température, etc).
  • Chaque rubrique renvoie à un script, téléchargé et rendu exécutable.
  • A l'exécution de mrtg, chaque script produit des graphiques et des pages HTML dans le répertoire indiqué dans la configuration (WorkDir?: /var/www/mrtg).
  • L'executable "indexmaker" permet aussi de produire la page générale en index dans le répertoire de mrtg.

OPTIMISATION DES GRAPHIQUES

  • Les paramètres de configuration se trouvent dans le fichier /etc/mrtg.cfg
  • Le principe est le suivant : afin d'obtenir des graphiques les plus précis possibles, il faut ajuster les valeurs d'ordonnées aux caractéristiques de la machine.
  • PARAMETRES A AJUSTER :
    • Mémoire : pour 6,5 Go de RAM : MaxBytes[mem]: 6500000000
    • MySQL : pour un debit MySQL de 7000 q/m : AbsMax[myserver.MySQL]: 7000
    • Disques durs : pour un disque de 250 Go : MaxBytes[sda1]:250000

INSTALLATION

  • On installe les packages et on configure le script principal et le script de génération du fichier index.html
    sudo apt-get install snmp mrtg mrtg-contrib lm-sensors
    sudo vi /etc/mrtg.cfg
    sudo vi /usr/bin/indexmaker
    

LANCER MRTG

  • On teste l'installation de mrtg en faisant tourner le système à vide pour vérifier qu'il n'y ait pas d'erreurs :
    sudo env LANG=C /usr/bin/mrtg /etc/mrtg.cfg
    

CREATION DU FICHIER INDEX DE MRTG

indexmaker --output /var/www/mrtg/index.html --section=title /etc/mrtg.cfg

PERSONNALISATION DES RAPORTS MRTG

  • Changer les infos dans /etc/mrtg.cf
  • Changer les infos dans le fichier /usr/bin/indexmaker

LECTURE DES RESULTATS

  • Les résultats de MRTG sont produits en HTML. Un simple vhost permet de lire tout cela.
            Alias /mrtg/ "/var/www/mrtg/"
            Directory /var/www/mrtg/>
                    Options Indexes FollowSymLinks MultiViews
                    AllowOverride None
                    Order allow,deny
                    allow from all
            /Directory>
    

ECRIRE SES PROPRES SCRIPTS MRTG

  • Le principe : écrire un script (shell, perl ou autre) qui fournit des valeurs qui vont servir à produire des graphiques. Les valeurs fournies seront lu via une rubrique de "mrtg.cfg"
  • MRTG Reference
  • Exemple de script supplémentaire ci-dessous. Une horoge MRTG, c'est un peu bizarre comme service, mais finalement cela peut être utile en cas de pb de cron ou de système !

MRTG exemple de script - Horloge MRTG

EXEMPLE DE SERVICE MRTG (/etc/mrtg.conf)

#---------HEURES--------------------
PNGTitle[heure]: Horloge MRTG
Target[heure]: `/home/admin/mrtg/heure`
Options[heure]: nopercent, growright, gauge, noinfo, nobanner, transparent
Unscaled[heure]:dwmy
MaxBytes[heure]: 60
YLegend[heure]: Heure - Minute
LegendI[heure]: Heure(s)
LegendO[heure]: Minute(s)
Title[heure]: Horloge MRTG
PageTop[heure]: Horloge MRTG
WithPeak[heure]:wmy
#--------end disk hda1-----------------------------
SCRIPT DE L'EXEMPLE (/home/admin/mrtg/heure)

#!/bin/sh
HOUR=$(date +"%H")
MIN=$(date +"%M")
echo $HOUR
echo $MIN

Autres informations

Une petite astuce pour voir le nombre de connexions et de processus Apache :

PROCESSUS
sudo ps fax|grep apache|nl|tail -1 ;  sudo netstat -laptu|grep apache|nl|tail -1
DEMANDES
sudo ps fax|grep apache|nl|tail -1 ;  sudo netstat -laptu|grep www|nl|tail -1
PROCESSUS ET DEMANDES
sudo ps fax|grep apache|nl|tail -1 ;  sudo netstat -laptu|grep apache|nl|tail -1 ; sudo netstat -laptu|grep www|nl|tail -1

SCRIPTS DE VEILLE

1 - Charge CPU
  • On commence par installer sysstat :
    $ sudo apt-get install sysstat
    
  • Pour pouvoir utiliser sar directement, il faut lancer une premiere fois sysstat :
    /usr/lib/sysstat/sa1
    
  • On active la collecte des données par sysstat en passant la variable ENABLED à true dans /etc/default/sysstat :
    # /etc/default/sysstat 
    ENABLED="true"
    OPTIONS="-F -L -"
    
  • Ensuite on récupère le petit script suivant :
    $ cat /home/admin/bin/cpustat
    #!/usr/bin/perl
    @line = `/usr/bin/sar | /usr/bin/tail -n 2 | /usr/bin/head -n 1 | /bin/sed 's/\ \ */ /g'`;
    @data = split(/ /, @line[0]);
    if (@data[2] eq "") {
    printf "0\n";
    }else {
    printf ("%3.0f\n", @data[2] + 0.5);
    }
    printf ("%3.0f\n", (@data[3])+(@data[2])+(@data[4]+0.5));
    $uptime = `/usr/bin/uptime | sed 's/\ \ */ /g'`;
    @uptime = split(/,/, $uptime);
    @uptime = split(/up/, @uptime[0]);
    $server = `/bin/uname -n`;
    printf "@uptime[1]\n";
    printf $server;
    
  • On ajoute la section suivante dans /etc/mrtg.conf :
    #---------CPU-------------------
    Target[cpu]: `/home/admin/cpustat`
    Options[cpu]: nopercent,growright,gauge,noinfo, nobanner
    #Unscaled[cpu]:dwmy
    MaxBytes[cpu]: 100
    YLegend[cpu]: % CPU
    ShortLegend[cpu]: % CPU
    Legend1[cpu]: % CPU Utilisateur
    Legend2[cpu]: % CPU Utilisateur + Système
    LegendI[cpu]: Utilisateur:
    LegendO[cpu]: Total:
    Title[cpu]: CPU
    PageTop[cpu]: CPU
    WithPeak[cpu]:wmy 
    Legend3[cpu]: Max % CPU Utilisateur 
    Legend4[cpu]: Max % CPU Utilisateur + Système
    #--------end CPU-----------------------------
    
2 - Network
#-----Local Network by netstat----------------------
Target[lan]: `/home/admin/mrtg/netstat lan eth0`
Options[lan]: nopercent,growright,noinfo, nobanner
MaxBytes[lan]: 12500000
Kilo[lan]:1024
Ylegend[lan]: octets/s
ShortLegend[lan]: o/s
Legend1[lan]: Debits locaux en entr
Legend2[lan]: Debits locaux en sortie
LegendI[lan]: Entree:
LegendO[lan]: Sortie:
Title[lan]: Traffic reseau local
PageTop[lan]: Traffic reseau local
WithPeak[lan]: wmy
Legend3[lan]:Debits locaux max en entr
Legend4[lan]:Debits locaux max en sortie
#---------End Local Network----------------
#!/bin/sh
grep="/bin/grep"
cut="/usr/bin/cut"
uptime="/usr/bin/uptime"
devsta="/proc/net/dev"
# netstat name interface
name=$1
interface=$2
line=`/bin/cat $devsta | $grep "$interface"`
line=`echo $line | $cut -d":" -f 2`
ibytes=`echo $line | $cut -d" " -f 1`
obytes=`echo $line | $cut -d" " -f 9`
uptim=`$uptime | $cut -d"," -f1`
uptim=`echo $uptim | $cut -d" " -f3,4`
echo $ibytes
echo $obytes
echo $uptim
echo $name
3 - Connexions TCP/IP
#-----Nombre de connexions TCP----------------------
Target[tcp]: `netstat -tn | grep ^tcp | wc -l ; netstat -tn | grep ^tcp | wc -l`
Options[tcp]: gauge,growright,nopercent
MaxBytes[tcp]: 1000000000
Title[tcp]: Nombre de connexions TCP
PageTop[tcp]: Nombre de connexions TCP
YLegend[tcp]: TCP
ShortLegend[tcp]: TCP
Legend1[tcp]: Nombre de connexions TCP serveur
Legend2[tcp]: Nombre de connexions TCP serveur
LegendI[tcp]: SERV:
WithPeak[tcp]: wmy
LegendO[tcp]: SERV:
#-----END Nombre de connexions TCP----------------------
4 - Load Average
#---------LOAD AVERAGE-------------------
Target[loadavg]: `echo \`cat /proc/loadavg | cut -f2 -d' '\` \* 100 | bc | cut -f1 -d.;echo \`cat /proc/loadavg | cut -f3 -d' '\` \* 100 | bc | cut -f1 -d.`
Options[loadavg]: gauge,growright,nopercent,noinfo,nolegend
MaxBytes[loadavg]: 100000
Title[loadavg]: Charge CPU
PageTop[loadavg]: Charge CPU
YLegend[loadavg]: Charge CPU
ShortLegend[loadavg]: loadavg
Legend1[loadavg]: Charge CPU sur 5 minutes
Legend2[loadavg]: Charge CPU sur 15 minutes
LegendI[loadavg]: Charge CPU:
WithPeak[loadavg]: wmy
LegendO[loadavg]: Charge CPU:
#---------LOAD AVERAGE-------------------
6 - Mémoire
#---------Memory--------------------
Target[mem]: `/home/admin/mrtg/mem`
Options[mem]: nopercent,growright,gauge,noinfo, nobanner
Unscaled[mem]:dwmy
MaxBytes[mem]: 536387584
Kilo[mem]:1024
YLegend[mem]: RAM
ShortLegend[mem]: o
Legend1[mem]: Memoire libre
Legend2[mem]: Memoire utilis
LegendI[mem]: Mem. Libre:
LegendO[mem]: Mem. Utilis?e:
Title[mem]: Memoire
PageTop[mem]: Memoire
WithPeak[mem]:wmy
Legend3[mem]: Memoire libre max
Legend4[mem]: Memoire utilis?e max
#--------end Memory-----------------------------
#!/bin/sh
# Thierry Nkaoua tnkaoua@yahoo.fr
USED=`free -b|grep cache:|cut -d ":" -f2|cut -c1-11`
FREE=`free -b|grep cache:|cut -d ":" -f2|cut -c12-22`
echo $FREE
echo $USED
7 - Nombre de processus
#--------------Number of processes----------------
Target[procs]: `/home/admin/mrtg/stat.pl procs`
Options[procs]: nopercent,growright,gauge,noinfo, nobanner, noi
Title[procs]: Process
MaxBytes[procs]: 1000000
YLegend[procs]: Process
ShortLegend[procs]: procs
LegendO[procs]: Procs:
Legend2[procs]: Nombre de process
PageTop[procs]: Process
WithPeak[procs]:wmy
Legend4[procs]: Nombre max de process
#------------End number of processes------------------
8 - Fichiers ouverts par processus
Target[files-procs]: `cat /proc/sys/fs/file-nr | cut -f2;expr \`ps ax | wc -l\` - 3`
Options[files-procs]: gauge,growright,nopercent,noinfo,noborder,nolegend
MaxBytes[files-procs]: 1000000000
Title[files-procs]: Nombre de fichiers/processus
PageTop[files-procs]: Nombre de fichiers/processus
YLegend[files-procs]: files/procs
ShortLegend[files-procs]: files/procs
Legend1[files-procs]: Nombre de Fichiers
Legend2[files-procs]: Nombre de Processus
LegendI[files-procs]: Fichiers:
LegendO[files-procs]: Processus:
9 - Fichiers ouverts
#------ number of open files-----------
Target[files]: `/home/admin/mrtg/files.pl`
Options[files]: gauge,noinfo, nopercent, growright, nobanner, noi
Title[files]: Fichiers
MaxBytes[files]: 1000000
AbsMax[files]: 1000000
YLegend[files]: Fichiers
ShortLegend[files]: Fichiers
LegendO[files]:  Fichiers:
Legend2[files]: Nombre de fichiers ouverts
PageTop[files]: Nombre de fichiers ouverts
WithPeak[files]: wmy
Legend4[files]: Nombre max de fichiers ouverts
#---- end open files
#!/usr/bin/perl
# Calcul acces Fichiers par O_be_one
$lsof = `lsof 2>/dev/null | wc -l`;
$files = int($lsof);
print "$files\n";
print "$files\n";
10 - Disque dur
#---------Espace libre disk hda1--------------------
Target[hda1]: `/home/admin/mrtg/checkdisk hda1`
Options[hda1]: nopercent,growright,gauge,noinfo, nobanner
MaxBytes[hda1]:57700
Unscaled[hda1]:dwmy
kMG[hda1]:M,G,T,P
YLegend[hda1]: octets
ShortLegend[hda1]: o
Kilo[hda1]:1024
Legend1[hda1]: Espace disponible
Legend2[hda1]: Espace utilis
LegendI[hda1]: Espace dispo :
LegendO[hda1]: Espace Utilis
Title[hda1]: Espace serveur RACINE
PageTop[hda1]: Espace serveur RACINE
#--------end disk hda1-----------------------------
#!/bin/sh
df="/bin/df"
cut="/usr/bin/cut"
grep="/bin/grep"
part=$1
line=`$df -m -x nfs| grep "$part"`
libre=`echo $line|$cut -d" " -f 4`
utilise=`echo $line|$cut -d" " -f 3`
echo $libre
echo $utilise
11 - Uptime
#---------uptime---------------------------
#Target[uptime]: .1.3.6.1.4.1.2021.8.1.101.1&.1.3.6.1.4.1.2021.8.1.101.1:public@localhost
Target[uptime]: `/home/admin/mrtg/uptime.pl`
Suppress[uptime]: d
Options[uptime]: gauge,noinfo, nopercent, growright, nobanner, noi
Title[uptime]: Uptime
MaxBytes[uptime]: 1000000
YLegend[uptime]: jours
ShortLegend[uptime]: jours
LegendO[uptime]: Uptime:
Legend2[uptime]: Uptime en jours de 31143
PageTop[uptime]: Uptime de 31143
#-------End uptime------------------------------
#!/usr/bin/perl
$uptime = `uptime`;
$uptime =~ /up (.*?) day/;
$up = int($1);
print "$up\n";
print "$up\n";
12 - Température
#---------TEMPERATURE CPU--------------------
PNGTitle[temperature]: Temperatures du CPU 
Target[temperature]: `/home/admin/mrtg/temperature.sh`
Options[temperature]: nopercent, growright, gauge, noinfo, nobanner, transparent
Unscaled[temperature]:dwmy
MaxBytes[temperature]: 60
YLegend[temperature]: Degres Celsius
LegendI[temperature]: Core 0
ShortLegend[temperature]: Degres Celsius 
Title[temperature]: Temperatures du CPU
PageTop[temperature]: Temperature du CPU
WithPeak[temperature]:wmy
#--------end temperature cpu-----------------------------
#!/bin/bash 
ligne=$(sensors|grep "Core 0")
	ligne2=${ligne#*+}
	core0=${ligne2%%.*}
ligne=$(sensors|grep "Core 1")
	ligne2=${ligne#*+}
	core1=${ligne2%%.*}
ligne=$(sensors|grep "Core 2")
	ligne2=${ligne#*+}
	core2=${ligne2%%.*}
ligne=$(sensors|grep "Core 3")
	ligne2=${ligne#*+}
	core3=${ligne2%%.*}
let "core=$core0+$core1+$core2+$core3"
let "core=$core/2"
echo $core
core2=0
echo $core2
5 - MySQL
#---------MYSQL-------------------
Target[myserver.MySQL]: `/home/admin/mrtg/mysql -u root -p xxxxxxxx -h localhost`
Options[myserver.MySQL]: perminute, growright, nopercent, integer
MaxBytes[myserver.MySQL]: 200
AbsMax[myserver.MySQL]: 2000
Unscaled[myserver.MySQL]: dwmy
Title[myserver.MySQL]: MySQL
PageTop[myserver.MySQL]: MySQL
YLegend[myserver.MySQL]: # of questions
ShortLegend[myserver.MySQL]: q/m
Legend1[myserver.MySQL]: # of questions
Legend2[myserver.MySQL]: # of slow queries
Legend3[myserver.MySQL]: Maximal # of questions per min.
Legend4[myserver.MySQL]: Maximal # of slow queries per min.
LegendI[myserver.MySQL]:  # of questions:
LegendO[myserver.MySQL]:  # of slow queries:
#---------END MYSQL-------------------
#!/usr/bin/perl -w
##################################################################
# $Id: mrtg-mysql-load,v 1.9 2002/02/01 13:43:56 carsten Exp $
#
# Copyright (c) 2001 Carsten H. Pedersen .
# All Rights Reserved.
#
# Losely based on mrtg-ping-probe 1.2 Copyright (c) 1997-2001
# Peter W. Osel .
#
# Copyright Carsten H. Pedersen  2001.
# This file is released under the GNU General Public License.
# See file COPYRIGHT for details
#
##################################################################
require 5.003;
use Getopt::Std;
use File::Basename;
use Config;

sub dbg_print;
sub read_config;
sub get_questions;
sub get_slow_queries;
sub get_uptime;
sub get_version;
sub write_output;

# prevent warnings for command-line variables which
# Perl thinks we only use once.
$opt_o = "";
$opt_v = "";

$Prog_name = basename($0);              # Who I am

# Usage message

$Usage = "$Prog_name: Outputs the number of questions and slow queries since
last restart of the MySQL server. The output is formatted according to
mrtg requirements.

Usage: $Prog_name [-h host] [-P port] [-u username] [-ppassword]
          [-c /path/to/config.file] [-d] [-v] [-l filename]

    Options -h, -P, -u and -p are equivalent (and map directly) to the
        same options for mysqladmin.
    -l: Write a copy of the output to file filename
    -c: Read all the options from config file. Command line flags
        override options in config file.
    -o: Print command and options used when calling mysqladmin; exit
    -d: Print lots of ugly debugging messages to STDERR
    -v: Output version info; exit
"; # end $Usage

# Version message

$version = "1.02";
$dispversion = "[mrtg-mysql-load v. $version]";
$Version = "mrtg-mysql-load v. $version
Copyright (c) 2001-2002 Carsten H. Pedersen .
All Rights Reserved.
"; # end version


# Parse Command Line:
if (!getopts('h:P:u:p:t:c:l:dvo')) {
    $output = $Usage;
    write_output;
    die $output;
}

# if debug is turned on, tell us so
if ($opt_d) {
    dbg_print "Debugging is on";
}

dbg_print "Done parsing command line";

# if -v: Echo version info and exit
if ($opt_v) {
    dbg_print "Version info requested";
    print $Version;
    exit(0);
} else {
        dbg_print "Version info not requested";
}

# reset all variables to known values
$host = "";
$port = "";
$username = "";
$password = "";
$logfile = "";

# If the config file has been specified, read the options from that
# first.
if ($opt_c) {
    read_config($opt_c);
} else {
    dbg_print "Config file NOT specified";
}

# Other command line options. They may already
# have been specified in a config file, but we
# override if they are defined on the command line.
$host     = defined($opt_h) ? $opt_h : $host;
$port     = defined($opt_P) ? $opt_P : $port;
$username = defined($opt_u) ? $opt_u : $username;
$password = defined($opt_p) ? $opt_p : $password;
$logfile  = defined($opt_l) ? $opt_l : $logfile;

if (@ARGV > 0) {
    print STDERR "$Prog_name: ERROR: ignoring superfluous arguments\n";
    print STDERR "$Usage";
}

# construct command used for calling mysqladmin
$cmd = "mysqladmin ".
    ($host ? "-h $host " : "").
    ($port ? "-P $port " : "").
    ($username ? "-u $username " : "").
    ($password ? "-p$password " : "").

    # Note that we use the "version" command rather than
    # the "status" command, as version returns the same
    # status info plus the version number, albeit formatted
    # somewhat differently. As a plus, it also returns the
    # uptime info in a much more human-readable format.
    "version ".

    # we need to redirect stderr to catch error messages
    "2>&1 ".
    "";

# If command line option -o is given, display $cmd and exit
if ($opt_o) {
    print "$cmd\n";
    exit(0);
}

unless (open(MYSQLA, "$cmd |")) {
    print STDERR "${Prog_name}: ERROR: Can't open $cmd: $!";
    exit(1);
}

$mysqladmin_output = join('', );
close MYSQLA;

# A better error handling could probably be implemented.
# For now, we simply check whether mysqladmin returns the
# string "mysqladmin: " as the first part of either stderr
# or stdout if an error occurs. In that case, we assume
# that something odd happened.

if ($mysqladmin_output =~ /^.mysqladmin:/) {
    $output =
        "ERROR: mysqladmin returned an error message:\n$mysqladmin_output";
    write_output;
    die $output;
}

get_questions;
get_slow_queries;
get_uptime;
get_version;

# Now we have all the data we need to output to mrtg:

# The external mrtg probe returns up to 4 lines of output:
#       1. Line: current state of the 'incoming bytes counter'
#       2. Line: current state of the 'outgoing bytes counter'
#       3. Line: string, telling the uptime of the target.
#       4. Line: telling the name of the target.

$output = sprintf("%d\n%d\n%s\n%s", $questions, $slow_queries,
                  $uptime, $version);

write_output;

exit(0);

# dbg_print: Print string to STDERR if debug is turned on

sub dbg_print {
    if ($opt_d) {
        print STDERR "$Prog_name-dbg: ";
        print STDERR "@_\n";
    }
}

# read_config: Attempt to read in the configuration file and set
# variables accordingly. The format of the config file is:
# # - comment, ignored
# var=value
# where var is one of 'host', 'port', 'username' or 'password'
# and value is the corresponding value, no quotation

sub read_config {
    my $configfile = $_[0];
    my $lnum = 0;

    if (!open(CFG, "<$configfile")) {
        $output =
            "ERROR: Unable to read config file $configfile";
        write_output;
        die $output;
    }
    dbg_print("Reading config from file $configfile");
    for $line () {
        $lnum++;
        chomp $line;
        if ($line !~ /^$/ ) { # ignore empty lines
            if ($line=~/(host|port|username|password|logfile)=(.{1,})/ ) {
                dbg_print("Got value $2 for parameter $1");
                $ {$1} = $2;
            } else {
                # a comment or an error?
                if ($line =~ /^#/ ) {
                    dbg_print "Ignored comment: $line";
                } else {
                    print STDERR "$Prog_name: Error: I don't understand line ".
                        "$lnum of $configfile\n";
                    exit(1);
                }
            }
        }
    }
    dbg_print("Done reading config file");
}


# get_questions: Extract "Questions: NNNN" from $mysqladmin_output and
# tie the value to $questions

sub get_questions {
    if ($mysqladmin_output !~ /Questions: ([0-9]+)/ ) {
        $output = "ERROR: could not find match for 'Questions:' in ".
            "mysqladmin output\n\n:$mysqladmin_output";
        write_output;
        die $output;
    }
    dbg_print "Questions: $1";
    $questions = $1;
}

# get_slow_queries: Extract "Questions: NNNN" from $mysqladmin_output and
# tie the value to $slow_queries

sub get_slow_queries {
    if ($mysqladmin_output !~ /Slow queries: ([0-9]+)/ ) {
        $output = "ERROR: could not find match for 'slow queries:' in ".
            "mysqladmin output\n\n:$mysqladmin_output";
        write_output;
        die $output;
    }
    dbg_print "Slow queries: $1";
    $slow_queries = $1;
}

# get_uptime: Extract "Uptime:[\t\ ]+dd days hh hours mm min ss sec
# from $mysqladmin_output, convert it all to seconds, and tie the
# final value to $version

sub get_uptime {
    # Catch "xx day(s) xx hour(s) xx min xx sec" line from output.
    # mysqladmin outputs no data for days, hours, minutes until the
    # values is at least 1.
    if ($mysqladmin_output !~ /Uptime:\s+(\d+.+)/ ) {
        $output = "ERROR: could not find match for 'Uptime:' in ".
            "mysqladmin output\n\n:$mysqladmin_output";
        write_output;
        die $output;
    }
    $uptime_s = $1;
    dbg_print "Caught Uptime line: '$uptime_s'";

    $uptime = $1;
}

# get_version: Extract "Server version[\t\ ]+x.yy.zz ... \n" from
# $mysqladmin_output and tie the value to $version

sub get_version {
    if ($mysqladmin_output !~ /Server version[ \t]+([^\n]+)/ ) {
        $output = "ERROR: could find match for 'Server version' in\n".
            "mysqladmin output\n\n:$mysqladmin_output";
        write_output;
        die $output;
    }
    dbg_print "Version: $1";
    $version = "MySQL version $1 $dispversion";
}

# write_output: write $output to stdout. If a logfile has been specified,
# output to that as well. In this implementation, it's expected that
# writing of output happens only once during the execution of the program.

sub write_output {
    # If we are to write to a log file, do it now.
    # The format of the log file is -- (dash-dash), timestamp, --, ,
    #   the output, 
    if ($logfile) {
        ($t_sec, $t_min, $t_hour, $t_mday, $t_mon, $t_year,
         $t_wday, $t_yday, $t_isdst) = localtime(time);
        unless (open(LOGFILE, ">>$logfile")) {
            print STDERR "${Prog_name}: ".
              "ERROR: Can't open logfile $logfile: $!";
            exit(1);
        }
        $t_year += 1900;
        print LOGFILE "--$t_year-$t_mon-$t_mday $t_hour:$t_min:$t_sec--\n";
        print LOGFILE "$output\n";
        close LOGFILE;
        # hmmm... need to do something with these in order
        # not to get warnings...
        $t_wday = 0; $t_yday = 0; $t_isdst = 0;
    }

    # Now, output to stdout:
    printf $output;
}

__END__

=head1 NAME

mrtg-mysql-load - a MySQL load analysis fetcher for MRTG

=head1 SYNOPSIS

B
[ B<-h> I ]
[ B<-P> I ]
[ B<-u> I ]
[ B<-p> I ]
[ B<-c> I ]
[ B<-o> ]
[ B<-d> ]
[ B<-v> ]
[ B<-l> I ]

=head1 DESCRIPTION

B runs B (which is assumed to be
available on the host), passing the I<-h, -P, -u> and I<-p> options
as they are given. On normal exit, B writes each
of the values of I and I
to stdout, one line per value.

It is meant to be called by the Multi Router Traffic Grapher (MRTG).

=head1 INSTALLING

Please see the file INSTALLING for examples.

=head1 OPTIONS

=over 8

=item B<-h>

the hostname to query (as I<-h> for mysqladmin).

=item B<-P>

The port on which to talk with the MySQL server
(as I<-P> for mysqladmin).

=item B<-u>

The MySQL username to use

=item B<-p>

The password to use when calling mysqladmin. Note that
B, unlike I, doesn't care whether
you put whitespace between the B<-p> and the password or not.

=item B<-c>

Read the values for host, port, username and password
from a configuration file. The configuration file consists of
lines of the form I,
where I is one of 'host', 'port', 'username' or 'password'
and I is the (unquoted) corresponding value.
Blank lines may be added to the configuration file for readability,
and comments may be entered on separate lines starting with '#'.

If the same value is defined in the configuration file and on
the command line, the value on the command line takes precence.

=item B<-o>

Print the command that would have been used to call mysqladmin
using the given options and configuration file, then exit.

=item B<-d>

Will print a lot of very ugly debugging info to stderr. Mostly good
for demonstrating the programmer's lack of trust in his Perl skills.

=item B<-v>

Print version information to stdout, then exit.

=item B<-l>

The name of an optional log file. This file will log all output (including
error messages) generated by the program to that file.

=back


=head1 RETURN VALUE

The program exits with an exit value 0, if it believes it was
successful.

=head1 USING CONFIGURATION FILES

When using B with B, there are several places
that may define the parameters used for connection. As noted above,
B is a wrapper around the B program.
B will first search for its parameters from the files
B and B<~/my.cnf>, having options in the latter overriding
those of the first.

B uses the command line of B to specify
the parameters, and these will override any options set by B's
configuration files. Thus, parameters set in B's
configuration file will override any options set in
B and/or B<~/my.cnf>.

Any options set on the command line of B will override
any other options set by one of the previous methods. The command line
switches are most frequently used directly in the B config file,
when specifying the B option:

=over 4

=item C

=back

To sum up, the parameters used when specifying the parameters for
making a connection to the MySQL server may be specified in no
less than 4 places, which are, in increasing order of precedence,

=over 4

=item *

/etc/my.cnf

=item *

~/my.cnf

=item *

a configuration file for B specified by the -c
parameter

=item *

switches set on the command line (or, more frequently,
in the B config file).

=back

=head1 EXAMPLES

=over 4

=item B

This is the most basic way to call mrtg-mysql-load. It will work,
too, if run on the same host as mysqld and mysqld is configured to
let local users connect. (By default, it does, though I believe this
is a really stupid decision on the part of the developers. You
really should set permissions in MySQL to disallow this.

=item B -u  -p  >

The format you would most likely use for calling mrtg-mysql-load.

=back

=over 4

=item *

An example B configuration file, mrtg-cfg.example,
is provided in the document directory of the distribution.

=item *

An example B configuration file,
mysql-load-cfg.example, is provided in the document directory of
the distribution.

=back

=head1 FILES

B uses B, which is assumed to be
available in the path of the user running the program.

=head1 SEE ALSO

mrtg(1), mrtg-cfg.example, mysql-load-cfg.example

http://www.mrtg.org/

http://www.bitbybit.dk/mysqlfaq/mrtg-mysql-load/

=head1 DIAGNOSTICS

=over 4

=item ERROR: ignoring superfluous arguments

B doesn't take any command-line arguments. If you
get this message, you most likely forgot to specify a switch name.

=item ERROR: Can't open mysqladmin ...

B could not be run. Check that mysqladmin is available
and that the user running B has the proper permissions.

=item ERROR: mysqladmin returned an error message: ...

B did run, but hit a snag, probably when connecting to the
server. Check the displayed error message, and/or check whether you
have specified the correct host, username and password.

=item ERROR: Unable to read config file ...

B could not open the config file specified by the
B<-c> switch. Make sure the file exists and that the user running
mrtg-mysql-load has the permissions to read it.

=item Error: I don't understand line xx of EconfigfileE

There was an error on line xx of the configuration file. Each
line must either be blank, start with a '#' to mark it as a
comment, or have the form I,
where I is one of 'host', 'port', 'username' or 'password'
and I is the (unquoted) corresponding value.

=item ERROR: could not find match for 'xxx' in mysqladmin output ...

B returned some output, but it was not formatted as expected.
Your particular version of mysqladmin may not match the author's.
The current version of B was written for mysql v. 3.23.35;
Please contact the author with more information, and he'll try to make
it match your particular version.

=back

=head1 RESTRICTIONS

B is a Perl script. It has been created with and
tested on Perl v. 5.6.0-i386-linux. Minimum requirement is Perl 5.003.

B relies on access to B. If mysqladmin is
not installed on the machine, or the user running mrtg-mysql-load
does not have the proper permissions to run mysqladmin, the program
will fail.

The  server must be configured with a user capable of connecting
to the server and retrieve the information.

=head1 BUGS

The -t option which was available in previous versions, has now been
removed. It seems to have been removed from recent versions of mysqladmin,
and it caused a lot of trouble anyway -- at least according to users on
the MySQL mailing list.

Most error messages are written to stdout as well as stderr. This may cause
some confusion, if the program is run from the console.

=head1 COPYRIGHT

Copyright (c) 2001 Carsten H. Pedersen .
All Rights Reserved.

See the file COPYRIGHT in the distribution for the exact terms.

=head1 AUTHOR

Written by Carsten H. Pedersen Ecarsten.pedersen@bitbybit.dkE.