The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#!/usr/bin/env perl
use strict;
use warnings;
use Carp;
use Getopt::Long;
use LWP::UserAgent;
use Ganglia::Gmetric::XS;
use Data::Dumper;
$Data::Dumper::Indent   = 1;
$Data::Dumper::Deepcopy = 1;

my $RCSID    = q$Id$;
my $REVISION = $RCSID =~ /,v ([\d.]+)/ ? $1 : 'unknown';
my $PROG     = substr($0, rindex($0, '/')+1);

my $Debug     = 0;
my $No_Daemon = 0;
my $INTERVAL  = $ENV{INTERVAL} || 60;

sub dprint (@) {
    return unless $Debug;
    my @m = @_;
    chomp @m;
    print STDERR 'DEBUG: ', @m,"\n";
}

sub dprint2(@) {
    dprint @_ if $Debug >= 2;
}

sub usage() {
    my $mesg = shift;

    print "[ERROR] $mesg\n" if $mesg;
    print "usage:\n";
    print "    $PROG [ -d ] [-X] url\n";
    print "

v$REVISION
";
    exit 1;
}

MAIN: {
    my %opt;
    Getopt::Long::Configure("bundling");
    GetOptions(\%opt,
               'nodaemon|X' => \$No_Daemon,
               'debug|d+'   => \$Debug,
               'help|h|?') or &usage();
    dprint "DEBUG MODE LEVEL=$Debug";

    my $url = $ARGV[0] ? shift @ARGV : 'http://localhost/server-status?auto';
    unless ($url) {
        &usage('missing arugment.');
    }
    dprint2 "url=$url";

    ### initialize
    my $ua = LWP::UserAgent->new(agent => "apache-status/$REVISION",
                                 timeout => 8,
                                );
    my $req = HTTP::Request->new(GET => $url);
    # $req->header(Host => 'example.org'); # set vhost name if you need

    my $gmetric = Ganglia::Gmetric::XS->new;

    for (;;) {
        ### get status data
        my $res = $ua->request($req);
        unless ($res->is_success) {
            carp "failed to get $url";
            sleep $INTERVAL;
            next;
        }

        my $content = $res->content;
        unless ($content) {
            carp "failed to get content of $url";
            sleep $INTERVAL;
            next;
        }
        dprint2 "content=$content";

        ### parse status data
        ## request per second (ExtendedStatus On)
        my $rps;
        if ($content =~ /^ReqPerSec:\s*([\d\\.]+)$/m) {
            $rps = $1;
        } else {
            $rps = -1;
        }
        $rps += 0;              # as numeric
        dprint2 "rps=$rps";

        ## process status
        my @sc_order = (
                       'waiting',
                       'starting',
                       'reading_request',
                       'sending_reply',
                       'keepalive',
                       'dns_lookup',
                       'closing',
                       'logging',
                       'gracefully_finishing',
                       'idle',
                       'open_slot',
                      );
        my %sc_byname = (
                         'waiting'              => '_',
                         'starting'             => 'S',
                         'reading_request'      => 'R',
                         'sending_reply'        => 'W',
                         'keepalive'            => 'K',
                         'dns_lookup'           => 'D',
                         'closing'              => 'C',
                         'logging'              => 'L',
                         'gracefully_finishing' => 'G',
                         'idle'                 => 'I',
                         'open_slot'            => '.',
                        );
        my %sc_bychar = reverse %sc_byname;
        my $score;
        if ($content =~ /^Scoreboard:\s*(.+)$/m) {
            $score = $1;
        } else {
            $score = "";
        }
        dprint2 "score=$score";

        my %scoreboard;
        map { $scoreboard{$_} = 0 } keys %sc_byname; # initialize
        map { $scoreboard{ $sc_bychar{$_} }++ } split //, $score;
        dprint2(Dumper(\%scoreboard));

        ### gmetric
        if ($rps >= 0) {
            $gmetric->send(
                name  => "ap_rps",
                value => $rps,
                type  => 'uint16',
                units => 'r/s',
               );
        }
        while (my ($k, $v) = each %scoreboard) {
            $gmetric->send(
                name  => "ap_${k}",
                value => $v,
                type  => 'uint16',
                units => 'proc',
               );
        }

        last if $No_Daemon;
        dprint2 "sleep $INTERVAL";
        sleep $INTERVAL;
    }

    exit 0;
}

__END__