|  line  | 
 stmt  | 
 bran  | 
 cond  | 
 sub  | 
 pod  | 
 time  | 
 code  | 
| 
1
 | 
  
 
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 package Plack::Middleware::StatsPerRequest;  | 
| 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # ABSTRACT: Measure HTTP stats on each request  | 
| 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 our $VERSION = '0.902'; # VERSION  | 
| 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
7
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
 
 | 
58910
 | 
 use strict;  | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
12
 | 
    | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
48
 | 
    | 
| 
8
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
 
 | 
9
 | 
 use warnings;  | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2
 | 
    | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
39
 | 
    | 
| 
9
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
 
 | 
44
 | 
 use 5.010;  | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7
 | 
    | 
| 
10
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
 
 | 
450
 | 
 use Time::HiRes qw();  | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1122
 | 
    | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
46
 | 
    | 
| 
11
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
12
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
 
 | 
377
 | 
 use parent 'Plack::Middleware';  | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
242
 | 
    | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
9
 | 
    | 
| 
13
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 use Plack::Util::Accessor  | 
| 
14
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
 
 | 
12063
 | 
     qw( app_name metric_name path_cleanups add_headers has_headers long_request );  | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
    | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
10
 | 
    | 
| 
15
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
 
 | 
974
 | 
 use Plack::Request;  | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
110424
 | 
    | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
63
 | 
    | 
| 
16
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
 
 | 
399
 | 
 use Log::Any qw($log);  | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6712
 | 
    | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
10
 | 
    | 
| 
17
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
 
 | 
2380
 | 
 use Measure::Everything 1.002 qw($stats);  | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2153
 | 
    | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
11
 | 
    | 
| 
18
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
 
 | 
1147
 | 
 use HTTP::Headers::Fast;  | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
    | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1326
 | 
    | 
| 
19
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
20
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub prepare_app {  | 
| 
21
 | 
9
 | 
 
 | 
 
 | 
  
9
  
 | 
  
1
  
 | 
69062
 | 
     my $self = shift;  | 
| 
22
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
23
 | 
9
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
21
 | 
     $self->app_name('unknown')         unless $self->app_name;  | 
| 
24
 | 
9
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
122
 | 
     $self->metric_name('http_request') unless $self->metric_name;  | 
| 
25
 | 
9
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
76
 | 
     $self->path_cleanups( [ \&replace_idish ] ) unless $self->path_cleanups;  | 
| 
26
 | 
9
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
79
 | 
     $self->long_request(5) unless defined $self->long_request;  | 
| 
27
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
71
 | 
     foreach my $check (qw(add_headers has_headers)) {  | 
| 
28
 | 
18
 | 
 
 | 
 
 | 
 
 | 
 
 | 
42
 | 
         my $val = $self->$check;  | 
| 
29
 | 
18
 | 
  
100
  
 | 
  
100
  
 | 
 
 | 
 
 | 
88
 | 
         if ( $val && ref($val) ne 'ARRAY' ) {  | 
| 
30
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
14
 | 
             $log->warn(  | 
| 
31
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 "Plack::Middleware::StatsPerRequest $check has to be an ARRAYREF, ignoring $val"  | 
| 
32
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             );  | 
| 
33
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
92
 | 
             $self->$check(undef);  | 
| 
34
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
35
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
36
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
37
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
38
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub call {  | 
| 
39
 | 
17
 | 
 
 | 
 
 | 
  
17
  
 | 
  
1
  
 | 
38090
 | 
     my $self = shift;  | 
| 
40
 | 
17
 | 
 
 | 
 
 | 
 
 | 
 
 | 
27
 | 
     my $env  = shift;  | 
| 
41
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
42
 | 
17
 | 
 
 | 
 
 | 
 
 | 
 
 | 
48
 | 
     my $t0 = [Time::HiRes::gettimeofday];  | 
| 
43
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
44
 | 
17
 | 
 
 | 
 
 | 
 
 | 
 
 | 
49
 | 
     my $res = $self->app->($env);  | 
| 
45
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
46
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     return Plack::Util::response_cb(  | 
| 
47
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         $res,  | 
| 
48
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         sub {  | 
| 
49
 | 
17
 | 
 
 | 
 
 | 
  
17
  
 | 
 
 | 
233
 | 
             my $res = shift;  | 
| 
50
 | 
17
 | 
 
 | 
 
 | 
 
 | 
 
 | 
24
 | 
             my $req;  | 
| 
51
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
52
 | 
17
 | 
 
 | 
 
 | 
 
 | 
 
 | 
50
 | 
             my $elapsed = Time::HiRes::tv_interval($t0);  | 
| 
53
 | 
17
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
313
 | 
             $elapsed = sprintf( '%5f', $elapsed ) if $elapsed < .0001;  | 
| 
54
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
55
 | 
17
 | 
 
 | 
 
 | 
 
 | 
 
 | 
39
 | 
             my $path = $env->{PATH_INFO};  | 
| 
56
 | 
17
 | 
 
 | 
 
 | 
 
 | 
 
 | 
27
 | 
             foreach my $callback ( @{ $self->path_cleanups } ) {  | 
| 
 
 | 
17
 | 
 
 | 
 
 | 
 
 | 
 
 | 
44
 | 
    | 
| 
57
 | 
16
 | 
 
 | 
 
 | 
 
 | 
 
 | 
82
 | 
                 $path = $callback->($path);  | 
| 
58
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
59
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
60
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             my %tags = (  | 
| 
61
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 status => $res->[0],  | 
| 
62
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 method => $env->{REQUEST_METHOD},  | 
| 
63
 | 
17
 | 
 
 | 
 
 | 
 
 | 
 
 | 
73
 | 
                 app    => $self->app_name,  | 
| 
64
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 path   => $path,  | 
| 
65
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             );  | 
| 
66
 | 
17
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
134
 | 
             if ( my $headers_to_add = $self->add_headers ) {  | 
| 
67
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
27
 | 
                 $req = Plack::Request->new($env);  | 
| 
68
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
31
 | 
                 foreach my $header (@$headers_to_add) {  | 
| 
69
 | 
8
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
800
 | 
                     $tags{ 'header_' . lc($header) } = $req->header($header)  | 
| 
70
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         // 'not_set';  | 
| 
71
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 }  | 
| 
72
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
73
 | 
17
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
178
 | 
             if ( my $has_headers = $self->has_headers ) {  | 
| 
74
 | 
4
 | 
 
 | 
  
 33
  
 | 
 
 | 
 
 | 
32
 | 
                 $req ||= Plack::Request->new($env);  | 
| 
75
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
34
 | 
                 foreach my $header (@$has_headers) {  | 
| 
76
 | 
8
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
693
 | 
                     $tags{ 'has_header_' . lc($header) } =  | 
| 
77
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         $req->header($header) ? 1 : 0;  | 
| 
78
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 }  | 
| 
79
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
80
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
81
 | 
17
 | 
 
 | 
 
 | 
 
 | 
 
 | 
157
 | 
             eval {  | 
| 
82
 | 
17
 | 
 
 | 
 
 | 
 
 | 
 
 | 
32
 | 
                 $stats->write( $self->metric_name,  | 
| 
83
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     { request_time => $elapsed, hit => 1 }, \%tags );  | 
| 
84
 | 
17
 | 
  
100
  
 | 
  
100
  
 | 
 
 | 
 
 | 
215
 | 
                 if ( $self->long_request && $elapsed > $self->long_request ) {  | 
| 
85
 | 
1
 | 
 
 | 
  
 33
  
 | 
 
 | 
 
 | 
29
 | 
                     $req ||= Plack::Request->new($env);  | 
| 
86
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
17
 | 
                     $log->warnf( "Long request, took %f: %s %s",  | 
| 
87
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         $elapsed, $req->method, $req->request_uri );  | 
| 
88
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 }  | 
| 
89
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             };  | 
| 
90
 | 
17
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
383
 | 
             if ($@) {  | 
| 
91
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                 $log->errorf( "Could not write stats: %s", $@ );  | 
| 
92
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
93
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
94
 | 
17
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3000710
 | 
     );  | 
| 
95
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
96
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
97
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
98
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub replace_idish {  | 
| 
99
 | 
37
 | 
 
 | 
 
 | 
  
37
  
 | 
  
1
  
 | 
12870
 | 
     my $path = shift;  | 
| 
100
 | 
37
 | 
 
 | 
 
 | 
 
 | 
 
 | 
95
 | 
     $path = lc( $path . '/' );  | 
| 
101
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
102
 | 
37
 | 
 
 | 
 
 | 
 
 | 
 
 | 
86
 | 
     $path =~ s{/[a-f0-9\-.]+\@[a-z0-9\-.]+/}{/:msgid/}g;  | 
| 
103
 | 
37
 | 
 
 | 
 
 | 
 
 | 
 
 | 
100
 | 
     $path =~ s{/[a-f0-9]+\/[a-f0-9\/]+/}{/:hexpath/}g;  | 
| 
104
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
105
 | 
37
 | 
 
 | 
 
 | 
 
 | 
 
 | 
70
 | 
     $path =~ s([a-f0-9]{40})(:sha1)g;  | 
| 
106
 | 
37
 | 
 
 | 
 
 | 
 
 | 
 
 | 
64
 | 
     $path =~  | 
| 
107
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         s([a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12})(:uuid)g;  | 
| 
108
 | 
37
 | 
 
 | 
 
 | 
 
 | 
 
 | 
74
 | 
     $path =~ s(\d{6,})(:int)g;  | 
| 
109
 | 
37
 | 
 
 | 
 
 | 
 
 | 
 
 | 
61
 | 
     $path =~ s{\d+x\d+}{:imgdim}g;  | 
| 
110
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
111
 | 
37
 | 
 
 | 
 
 | 
 
 | 
 
 | 
72
 | 
     $path =~ s{/\d+/}{/:int/}g;  | 
| 
112
 | 
37
 | 
 
 | 
 
 | 
 
 | 
 
 | 
56
 | 
     $path =~ s(/[^/]{55,}/)(/:long/)g;  | 
| 
113
 | 
37
 | 
 
 | 
 
 | 
 
 | 
 
 | 
65
 | 
     $path =~ s(/[a-f0-9\-]{8,}/)(/:hex/)g;  | 
| 
114
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
115
 | 
37
 | 
 
 | 
 
 | 
 
 | 
 
 | 
148
 | 
     return substr( $path, 0, -1 );  | 
| 
116
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
117
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
118
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 "42nd birthday release";  | 
| 
119
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
120
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 __END__  |