#!/usr/bin/perl -w # Author: Nicolas Mendoza - 2008-06-18 # Raphaƫl Droz - 2016-01-08 # # Monitors the average time requests matching a custom regexp takes # For instance monitor time execution of files in http://example.com/foo/bar, # requests from google, images etc. # # Simply add an entry in the 'type' hashref and modify the description fields # for munin, and make the 'matches' member contain a subref that returns # true if a request matches, parameters are a list containing the request # split on spaces. # # NOTE: You need to add a field in your Apache logs showing time executed. # This is normally done using the %T (seconds) or %D (microseconds) # For instance: # LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\" %T %v" # Check http://httpd.apache.org/docs/2.2/mod/mod_log_config.html#formats for more info # # Configurable variables # fieldno - Override the default field number # linecount - How many last request to consider # Multiples instances for specific log files could be created by suffixing a configuration group. # Eg: ln -s apache_average_time_last_n_requests apache_average_time_last_n_requests_vhost1 # Then: # [apache_average_time_last_n_requests] # logfile_vhost1 /var/log/apache/vhost1.log # #%# family=auto use strict; $0 =~ /apache_average_time_last_n_requests_(.+)*$/; my $name = $1; my $LAST_N_REQUESTS = exists $ENV{'linecount'} ? $ENV{'linecount'} : 100000; # calculate based on this amount of requests my $TIME_FIELD_INDEX = exists $ENV{'fieldno'} ? $ENV{'fieldno'} : -2; # second last field my $ACCESS_LOG_PATTERN; # log pattern, if globbing is used, it will take the last one. if (! $name) { $ACCESS_LOG_PATTERN = exists $ENV{'logfile'} ? $ENV{'logfile'} : '/var/log/apache2/access.log.*'; } elsif (exists $ENV{'logfile_' . $name}) { $ACCESS_LOG_PATTERN = $ENV{'logfile_' . $name}; } else { $ACCESS_LOG_PATTERN = '/var/log/apache2/access.log.*'; } my $config =<< "CONFIG" graph_title Apache average seconds last $LAST_N_REQUESTS requests graph_args --base 1000 graph_scale no graph_vlabel Average request time graph_category webserver graph_info This graph shows average request times for the last $LAST_N_REQUESTS requests CONFIG ; my $types = { # any kind of request total => { munin_fields => { label => 'All requests', draw => 'LINE2', info => 'Average seconds per any request', }, sum => 0, lines => 0, matches => sub { return 1; }, }, # image requests images => { munin_fields => { label => 'Image requests', draw => 'LINE2', info => 'Average seconds per image request', }, sum => 0, lines => 0, matches => sub { my ($fields) = @_; my $script; ($script = $fields->[6]) =~ s/\?.*\z //mx; return $script =~ m{ \.(png|jpe?g|gif|tiff|ilbm|tga) \z }mx; }, }, }; if (@ARGV && $ARGV[0] eq 'config') { print $config; foreach my $type (keys %{$types}) { foreach my $key (keys %{$types->{$type}->{'munin_fields'}}) { printf "%s.%s %s\n", ($type, $key, $types->{$type}->{'munin_fields'}->{$key}); } } exit(0); } my $config_file = `ls -1 $ACCESS_LOG_PATTERN | tail -n 1`; chomp $config_file; my @lines = `tail -n $LAST_N_REQUESTS "$config_file"`; FOO: { foreach my $line (@lines) { foreach my $type (keys %{$types}) { my @fields = split /\s+/, $line; if ($types->{$type}->{'matches'}(\@fields)) { if ($fields[$TIME_FIELD_INDEX] !~ m/^[0-9]+$/) { last FOO; } $types->{$type}->{'sum'} += $fields[$TIME_FIELD_INDEX]; $types->{$type}->{'lines'}++; } } } } foreach my $type (keys %{$types}) { my $value = $types->{$type}->{'lines'} ? $types->{$type}->{'sum'} / $types->{$type}->{'lines'} : 'U'; printf "%s.value %s\n", ($type, $value); }