Listing 14.4. GD_Logfile.pm.
package Logfile::GD_Logfile;
=head1 NAME
GD_Logfile - add a graphing feature the Logfile class, a single method to
allow bar graph generation of log data. Uses the GD module to produce the
graph.
=head1 SYNOPSYS
Logfile::GD_Logfile::graph($l,Group => File,
Sort => Records,
ImSize => [640,480],
Font => `gdSmallFont'
);
Where $l is a Logfile object, ImSize is the output image size, and Font is
a font from the GD module. All other parameters to the Logfile::report()
method may be included, but only one List variable may be passed in.
=head1 AUTHOR
Bill Middleton - wjm@best.com
=cut
use GD;
sub graph{
my $self = shift;
my %par = @_;
my $group = $self->group($par{Group});
my $sort = $par{Sort} || $group;
my $font = $par{Font};
my $rever = (($sort =~ /Date|Hour/) xor $par{Reverse});
my $list = $par{List};
my ($keys, $key, $val, %keys);
my $direction = ($rever)?'increasing':'decreasing';
my (@list, %absolute);
my (@sorted, $rec_total, $largest, $list_total);
my ($width, $ht, $color, $black, $white);
my ($im, $i, $inc);
my($top,$bottom,$left,$right);
my($color_inc,$title);
my($third,$fourth,$current);
# Instantiate a new GD image based on args or default
if(ref($par{ImSize})){
$im = new GD::Image(@{$par{ImSize}});
$right = $par{ImSize}->[0] - 30;
$top = $par{ImSize}->[1] - 30 ;
$left = $par{ImSize}->[0] / 2;
$bottom = $par{ImSize}->[1] /10;
}
else{ # defaults to 640x480
$im = new GD::Image(640,480); # default
$right = 610;
$top = 450;
$left = 320;
$bottom = 48;
}
# Set up a few basic colors and sizes
$width = $right - $left;
$ht = $top - $bottom ;
$white = $im->colorAllocate(255, 255, 255);
$black = $im->colorAllocate(0 , 0, 0);
$im->transparent($white);
# Graphs of this sort only make sense with single variable
if ($list) {
if (ref($list)) {
die "Sorry, graphs may have only one List variable\n"
}
} else {
$list = "Records";
}
# Sum things up
while (($key,$val) = each %{$self->{$group}}) {
$keys{$key} = $val->{$sort};
$rec_total+=1;
$list_total += $val->{$list};
}
(defined $par{Top}) and $rec_total = $par{Top};
# Graph outline
$im->line($left,$top,$right,$top,$black);
$im->line($left,$top,$left,$bottom,$black);
# Graph Title
$title = "Percentages of $list by $group";
$im->string(gdLargeFont,$left,10,$title,$black);
$title = "Total $list = $list_total";
$im->string(gdMediumBoldFont,$left,
($top + $bottom/4),$title,$black);
# $i will be our color increment variable for grayscale
$i = 200;
$color_inc = 100 / $rec_total;
$top = $bottom + ($ht / $rec_total);
# A couple of text layout variables
$fourth= (($ht / $rec_total) / 4);
$third = (($ht / $rec_total) / 3);
# Main loop iterates over items, draws the text field and
# rectangle representing the percentage of total for each
for $key ( sort
{&Logfile::Base::srt($rever, $keys{$a}, $keys{$b})}
keys %keys){
my $val = $self->{$group}->{$key};
next unless defined($val);
$color = $im->colorAllocate($i, $i, $i);
if ($key =~ /$;/) {
die "Sorry, graphs may have only one key\n";
}
$current = $top - $fourth * 3;
$im->string(&{$font},10,$current,$key,$black);
$title = sprintf("%s(%4.2f%%)",' ` x 5,
($val->{$list}/$list_total * 100));
$current = $top - $third;
$im->string(&{$font},10,$current,$title,$black);
$right = $left + ($width * $val->{$list} / $list_total);
$im->rectangle($left,$top,$right,$bottom,$black);
$im->fill(($left+1),($bottom+1),$color);
$bottom = $top;
$top += $ht / $rec_total;
last if defined $par{Top} && --$par{Top} <= 0;
$i -= $color_inc;
}
# Dump the GIF to stdout
print $im->gif;
}
1;
Now you can produce a nice, two-dimensional graph of your log file data with Listing 14.5.