| 1 | #!/usr/bin/perl -w |
|---|
| 2 | |
|---|
| 3 | # Movable Type (r) Open Source (C) 2001-2008 Six Apart, Ltd. |
|---|
| 4 | # This program is distributed under the terms of the |
|---|
| 5 | # GNU General Public License, version 2. |
|---|
| 6 | # |
|---|
| 7 | # $Id$ |
|---|
| 8 | |
|---|
| 9 | package MT::Tool::ReportSlowRequest; |
|---|
| 10 | use strict; |
|---|
| 11 | |
|---|
| 12 | use lib "./lib"; |
|---|
| 13 | use base qw( MT::Tool ); |
|---|
| 14 | |
|---|
| 15 | use List::Util qw( min ); |
|---|
| 16 | use Time::HiRes qw( time ); |
|---|
| 17 | use MT; |
|---|
| 18 | use MT::Util::LogProcessor; |
|---|
| 19 | use Data::Dumper; |
|---|
| 20 | |
|---|
| 21 | my ($arg_day, $arg_logdir, $arg_sample, $arg_slow, $arg_debug, $arg_dump); |
|---|
| 22 | |
|---|
| 23 | sub help { |
|---|
| 24 | return q{ |
|---|
| 25 | --logdir <dir> Look for logs in directory <dir>. By default, logs |
|---|
| 26 | in the current directory are analyzed. |
|---|
| 27 | --sample <num> ? |
|---|
| 28 | --slow <secs> Number of seconds after which a request is listed |
|---|
| 29 | as one of the slowest. By default, requests over 2 |
|---|
| 30 | seconds are considered the slowest. |
|---|
| 31 | --day <name> The name of the day to examine; either 'today', |
|---|
| 32 | 'yesterday', or a date in the format YYYY-MM-DD. |
|---|
| 33 | --debug Enable debugging output. |
|---|
| 34 | --dump ? |
|---|
| 35 | }; |
|---|
| 36 | } |
|---|
| 37 | |
|---|
| 38 | sub usage { |
|---|
| 39 | } |
|---|
| 40 | |
|---|
| 41 | sub options { |
|---|
| 42 | return ( |
|---|
| 43 | 'logdir=s' => \$arg_logdir, |
|---|
| 44 | 'sample=i' => \$arg_sample, |
|---|
| 45 | 'slow=i' => \$arg_slow, |
|---|
| 46 | 'day=s' => \$arg_day, |
|---|
| 47 | 'debug' => \$arg_debug, |
|---|
| 48 | 'dump' => \$arg_dump, |
|---|
| 49 | ); |
|---|
| 50 | } |
|---|
| 51 | |
|---|
| 52 | sub main { |
|---|
| 53 | my $class = shift; |
|---|
| 54 | my ($verbose) = $class->SUPER::main(@_); |
|---|
| 55 | |
|---|
| 56 | $arg_slow ||= 2; |
|---|
| 57 | |
|---|
| 58 | my $proc = MT::Util::LogProcessor->new( |
|---|
| 59 | { |
|---|
| 60 | debug => $arg_debug, |
|---|
| 61 | logdir => $arg_logdir || '.', |
|---|
| 62 | sample => $arg_sample, |
|---|
| 63 | day => $arg_day || 'yesterday', |
|---|
| 64 | file_pattern => 'pl-\d{8}.log', |
|---|
| 65 | } |
|---|
| 66 | ); |
|---|
| 67 | |
|---|
| 68 | my %stash = ( today => $proc->day ); |
|---|
| 69 | my ( $total_records, $elapsed ) = $proc->process_log_files( |
|---|
| 70 | sub { |
|---|
| 71 | my ($rec) = @_; |
|---|
| 72 | |
|---|
| 73 | my $secs = int $rec->{time_total}; |
|---|
| 74 | |
|---|
| 75 | my $bucket = $secs > 10 ? 10 : $secs; |
|---|
| 76 | $stash{by_seconds}[$bucket]++; |
|---|
| 77 | |
|---|
| 78 | $stash{total_requests}++; |
|---|
| 79 | |
|---|
| 80 | if ( $secs > $arg_slow - 1 ) { |
|---|
| 81 | push @{ $stash{slow} }, $rec; |
|---|
| 82 | } |
|---|
| 83 | } |
|---|
| 84 | ); |
|---|
| 85 | |
|---|
| 86 | printf "Processed %d records in %.02f seconds; speed: %.02f recs/sec\n", |
|---|
| 87 | $total_records, $elapsed, $total_records / ( $elapsed || 1 ) |
|---|
| 88 | if $arg_debug; |
|---|
| 89 | |
|---|
| 90 | for my $bucket ( 0 .. $#{ $stash{by_seconds} } ) { |
|---|
| 91 | my $count = $stash{by_seconds}[$bucket] || 0; |
|---|
| 92 | $stash{restime_histogram}[$bucket] = { |
|---|
| 93 | count => $count, |
|---|
| 94 | range => $bucket == 10 |
|---|
| 95 | ? '10+ sec' |
|---|
| 96 | : $bucket . '-' . ( $bucket + 1 ) . 's', |
|---|
| 97 | percent => int( $count / $stash{total_requests} * 100 ) || 1, |
|---|
| 98 | }; |
|---|
| 99 | } |
|---|
| 100 | |
|---|
| 101 | $stash{slow} = |
|---|
| 102 | [ sort { $b->{time_total} <=> $a->{time_total} } @{ $stash{slow} || [] } ]; |
|---|
| 103 | |
|---|
| 104 | report( \%stash ); |
|---|
| 105 | } |
|---|
| 106 | |
|---|
| 107 | sub report { |
|---|
| 108 | my ($stash) = @_; |
|---|
| 109 | |
|---|
| 110 | print "Response time histogram:\n"; |
|---|
| 111 | for my $row ( @{ $stash->{restime_histogram} } ) { |
|---|
| 112 | printf "%s: %s (%s%%)\n", $row->{range}, $row->{count}, $row->{percent}; |
|---|
| 113 | } |
|---|
| 114 | |
|---|
| 115 | print "Slowest requests:\n"; |
|---|
| 116 | for my $row ( @{ $stash->{slow} } ) { |
|---|
| 117 | printf "%s\n", $row->{url}; |
|---|
| 118 | for my $key ( keys %$row ) { |
|---|
| 119 | next if $key !~ /^time_/; |
|---|
| 120 | my $secs = $row->{$key}; |
|---|
| 121 | next |
|---|
| 122 | if $key eq 'time_mem_start' |
|---|
| 123 | || $key eq 'time_mem_end' |
|---|
| 124 | || $key eq 'time_total' |
|---|
| 125 | || $secs < 0.01; |
|---|
| 126 | printf "%s: %s\n", $key, $secs; |
|---|
| 127 | } |
|---|
| 128 | } |
|---|
| 129 | } |
|---|
| 130 | |
|---|
| 131 | __PACKAGE__->main() unless caller; |
|---|
| 132 | |
|---|
| 133 | 1; |
|---|
| 134 | |
|---|