#!/usr/bin/perl =head1 # Log vhost port method response_bytes response_time status CustomLog "|/usr/share/munin/apache_pipelogger" "%v %p %m %B %D %s" =cut # write every n seconds to shared memory local $nsec=7; local $debug=undef; use Storable qw(freeze thaw); use List::Util qw(min max); use IPC::ShareLite ':lock'; require Data::Dumper if $debug; use Munin::Plugin; local $share = IPC::ShareLite->new( -key => 'mapl', -create => 1, -destroy => 1, -exclusive => 0, -mode => '0666' ) or die $!; local $SIG{'ALRM'}=\&periodic_write; alarm $nsec; # drop stored data on reload local %temp=(); while () { my ($vhost,$port,$method,$bytes,$time,$status)=split(/\s/,$_); # sanity check next unless m/^([\d\w\.\-_]+\s){5}([\d\w\.\-_]+$)/; # escaped "." and "-" # sitename to munin fieldname my $vpm=clean_fieldname($vhost); $temp{$vpm}{'label'}=$vhost; $temp{$vpm}{'label'}=~s/www\.//; # count all requests $temp{$vpm}{'requests'}++; if ($bytes) { $bytes=~s/-/0/; # bytes transmitted $temp{$vpm}{'bytes'}+=$bytes; # max bytes $temp{$vpm}{'max_bytes'}=max($temp{$vpm}{'max_bytes'},$bytes); # average bytes $temp{$vpm}{'avg_bytes'}=$temp{$vpm}{'bytes'}/$temp{$vpm}{'requests'} || 0 if ($bytes); } # count by status / error code $temp{$vpm}{"status"}{$status}++ if $status; if ($time) { # min/max execution time $temp{$vpm}{'max_time'}=max($temp{$vpm}{'max_time'},$time); # cumulative and average execution time $temp{$vpm}{'cml_time'}+=$time; # average time $temp{$vpm}{'avg_time'}=$temp{$vpm}{'cml_time'}/$temp{$vpm}{'requests'} || 0 if ($time); } }; sub periodic_write { # begin transaction $share->lock(LOCK_EX); # get data (may be updated by other loggers too) my %old=eval{%{thaw($share->fetch)}}; # using eval to suppress thaw error on empty string at the first run foreach my $vpm (keys %temp){ # merge values $old{$vpm}{'bytes'}+=$temp{$vpm}{'bytes'} if $temp{$vpm}{'bytes'}; $old{$vpm}{'requests'}+=$temp{$vpm}{'requests'} if $temp{$vpm}{'requests'}; $old{$vpm}{'time'}+=$temp{$vpm}{'time'} if $temp{$vpm}{'time'}; $old{$vpm}{'label'}=$temp{$vpm}{'label'}; $old{$vpm}{'avg_time'}=sprintf("%d",(($old{$vpm}{'avg_time'}+$temp{$vpm}{'avg_time'})/2)/1000); $old{$vpm}{'max_time'}=max($old{$vpm}{'max_time'},$temp{$vpm}{'max_time'})/1000; $old{$vpm}{'max_bytes'}=max($temp{$vpm}{'max_bytes'},$temp{$vpm}{'max_bytes'}); $old{$vpm}{'avg_bytes'}=sprintf("%d",($old{$vpm}{'avg_bytes'}+$temp{$vpm}{'avg_bytes'})/2); # reset local counters foreach my $check (qw(requests bytes time cml_time max_bytes avg_bytes max_time avg_time)) { $temp{$vpm}{$check}=0; } # reset status counts foreach my $val (keys %{$temp{$vpm}{'status'}}) { $old{$vpm}{'status'}{$val}+=$temp{$vpm}{'status'}{$val}; $temp{$vpm}{'status'}{$val}=0; } }; # save to shm # print Data::Dumper::Dumper(%old) if $debug; $share->store( freeze \%old ); # end transaction $share->unlock; # parse/write every n seconds alarm $nsec; }