#!/usr/bin/perl
#
# Program: Apache Request Viewer By Browser <browserreqs.pl>
#
# Author: Matty <matty91 at gmail dot com>
#
# Current Version: 0.1a
#
# Revision History:
#  Version 0.1a
#
# Last Updated: 11-25-2005
#
# Purpose: Prints the number of requests processed by an
#          Apache web server, and lists them by browser
#
# Installation:
#   Copy the shell script to a suitable location
#
# CDDL HEADER START
#  The contents of this file are subject to the terms of the
#  Common Development and Distribution License, Version 1.0 only
#  (the "License").  You may not use this file except in compliance
#  with the License.
#
#  You can obtain a copy of the license at Docs/cddl1.txt
#  or http://www.opensolaris.org/os/licensing.
#  See the License for the specific language governing permissions
#  and limitations under the License.
# CDDL HEADER END
#
# Example:
# $ browserreqs.pl -d 30
# Sampling browser data for 30 seconds...
# Browser    GETs  POSTs  HEADs TRACEs
# Epiphany   6     0      0      0
# Firefox    100   0      0      0
# Wget       1056  0      0      0

### Standard includes
use Getopt::Std;
use POSIX;

# Process the command line arguments
%options=();
getopts("d:",\%options);

my $delay = $options{d} || 60;

### Global variables
my %methods = ( GET   => 0,
                POST  => 0,
                HEAD  => 0,
                TRACE => 0);

$dtrace = <<END;
/usr/sbin/dtrace -Z -q -32 -n'
::apache_log_request:log-request
{
   /* The Method (r->method) is offset 72-bytes in a 32-bit Apache */
    this->method  = copyinstr(*(uintptr_t *)copyin(arg0 + 72,sizeof(uintptr_t)));

    /* The User-Agent is made available by using an Apache table lookup in teh probe */
    this->browser = copyinstr(arg1);

    \@methods[this->method, this->browser] = count();
}

profile:::tick-${delay}sec
{
   printa("%s %\@d %s DONE",\@methods);
   printf("\\n");
   trunc(\@methods);
}'
END

open(DTRACE,"$dtrace |") || die "cannot open dtrace $@\n";

print "Sampling browser data for $delay seconds...\n";

while (<DTRACE>) {
    chomp;

    @chunked = split(/DONE/);

    while (@chunked > 0) {
        ($method, $count, $useragent) = split(' ', shift(@chunked), 3);

        # RFC 2616 defines User-Agent as:
        #   User-Agent     = "User-Agent" ":" 1*( product | comment )
        if ($useragent =~ /MSIE/) {
            $useragent = "MSIE";
        } elsif ($useragent =~ /Firefox/) {
            $useragent = "Firefox";
        } elsif ($useragent =~ /Safari/) {
            $useragent = "Safari";
        } elsif ($useragent =~ /Epiphany/) {
            $useragent = "Epiphany";
        } elsif ($useragent =~ /curl/) {
            $useragent = "Curl";
        } elsif ($useragent =~ /Wget/) {
            $useragent = "Wget";
        } else {
            $useragent = "Other";
        }

        $counts{$useragent}{$method} += $count;
    }

    print "Browser     GETs  POSTs  HEADs TRACEs\n";
    
    foreach $useragent (sort keys %counts) {
        printf("%-10s  %-4d  %-5d  %-5d  %-6d\n", $useragent,
                                         $counts{$useragent}{GET},
                                         $counts{$useragent}{POST},
                                         $counts{$useragent}{HEAD},
                                         $counts{$useragent}{TRACE});
    }

    print "\n";
    undef %counts;
    exit(0);
}
