| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
########################################################################### |
|
2
|
|
|
|
|
|
|
# basic Perlbal statistics gatherer |
|
3
|
|
|
|
|
|
|
########################################################################### |
|
4
|
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
package Perlbal::Plugin::Stats; |
|
6
|
|
|
|
|
|
|
|
|
7
|
1
|
|
|
1
|
|
2473
|
use strict; |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
41
|
|
|
8
|
1
|
|
|
1
|
|
7
|
use warnings; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
35
|
|
|
9
|
1
|
|
|
1
|
|
6
|
no warnings qw(deprecated); |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
45
|
|
|
10
|
|
|
|
|
|
|
|
|
11
|
1
|
|
|
1
|
|
8
|
use Time::HiRes qw(gettimeofday tv_interval); |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
59
|
|
|
12
|
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
# setup our package variables |
|
14
|
|
|
|
|
|
|
our %statobjs; # { svc_name => [ service, statobj ], svc_name => [ service, statobj ], ... } |
|
15
|
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
# define all stats keys here |
|
17
|
|
|
|
|
|
|
our @statkeys = qw( files_sent files_reproxied |
|
18
|
|
|
|
|
|
|
web_requests proxy_requests |
|
19
|
|
|
|
|
|
|
proxy_requests_highpri ); |
|
20
|
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
# called when we're being added to a service |
|
22
|
|
|
|
|
|
|
sub register { |
|
23
|
0
|
|
|
0
|
0
|
|
my ($class, $svc) = @_; |
|
24
|
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
# create a stats object |
|
26
|
0
|
|
|
|
|
|
my $sobj = Perlbal::Plugin::Stats::Storage->new(); |
|
27
|
0
|
|
|
|
|
|
$statobjs{$svc->{name}} = [ $svc, $sobj ]; |
|
28
|
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
# simple events we count are done here. when the hook on the left side is called, |
|
30
|
|
|
|
|
|
|
# we simply increment the count of the stat on the right side. |
|
31
|
0
|
|
|
|
|
|
my %simple = qw( |
|
32
|
|
|
|
|
|
|
start_send_file files_sent |
|
33
|
|
|
|
|
|
|
start_file_reproxy files_reproxied |
|
34
|
|
|
|
|
|
|
start_web_request web_requests |
|
35
|
|
|
|
|
|
|
); |
|
36
|
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
# create hooks for %simple things |
|
38
|
0
|
|
|
|
|
|
while (my ($hook, $stat) = each %simple) { |
|
39
|
0
|
|
|
|
|
|
eval "\$svc->register_hook('Stats', '$hook', sub { \$sobj->{'$stat'}++; return 0; });"; |
|
40
|
0
|
0
|
|
|
|
|
return undef if $@; |
|
41
|
|
|
|
|
|
|
} |
|
42
|
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
# more complicated statistics |
|
44
|
|
|
|
|
|
|
$svc->register_hook('Stats', 'backend_client_assigned', sub { |
|
45
|
0
|
|
|
0
|
|
|
my Perlbal::BackendHTTP $be = shift; |
|
46
|
0
|
|
|
|
|
|
my Perlbal::ClientProxy $cp = $be->{client}; |
|
47
|
0
|
|
|
|
|
|
$sobj->{pending}->{"$cp"} = [ gettimeofday() ]; |
|
48
|
0
|
0
|
|
|
|
|
($cp->{high_priority} ? $sobj->{proxy_requests_highpri} : $sobj->{proxy_requests})++; |
|
49
|
0
|
|
|
|
|
|
return 0; |
|
50
|
0
|
|
|
|
|
|
}); |
|
51
|
|
|
|
|
|
|
$svc->register_hook('Stats', 'backend_response_received', sub { |
|
52
|
0
|
|
|
0
|
|
|
my Perlbal::BackendHTTP $be = shift; |
|
53
|
0
|
|
|
|
|
|
my Perlbal::ClientProxy $obj = $be->{client}; |
|
54
|
0
|
|
|
|
|
|
my $ot = delete $sobj->{pending}->{"$obj"}; |
|
55
|
0
|
0
|
|
|
|
|
return 0 unless defined $ot; |
|
56
|
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
# now construct data to put in recent |
|
58
|
0
|
0
|
|
|
|
|
if (defined $obj->{req_headers}) { |
|
59
|
0
|
|
0
|
|
|
|
my $uri = 'http://' . ($obj->{req_headers}->header('Host') || 'unknown') . $obj->{req_headers}->request_uri; |
|
60
|
0
|
|
|
|
|
|
push @{$sobj->{recent}}, sprintf('%-6.4f %s', tv_interval($ot), $uri); |
|
|
0
|
|
|
|
|
|
|
|
61
|
0
|
0
|
|
|
|
|
shift(@{$sobj->{recent}}) if scalar(@{$sobj->{recent}}) > 100; # if > 100 items, lose one |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
} |
|
63
|
0
|
|
|
|
|
|
return 0; |
|
64
|
0
|
|
|
|
|
|
}); |
|
65
|
|
|
|
|
|
|
|
|
66
|
0
|
|
|
|
|
|
return 1; |
|
67
|
|
|
|
|
|
|
} |
|
68
|
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
# called when we're no longer active on a service |
|
70
|
|
|
|
|
|
|
sub unregister { |
|
71
|
0
|
|
|
0
|
0
|
|
my ($class, $svc) = @_; |
|
72
|
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
# clean up time |
|
74
|
0
|
|
|
|
|
|
$svc->unregister_hooks('Stats'); |
|
75
|
0
|
|
|
|
|
|
delete $statobjs{$svc->{name}}; |
|
76
|
0
|
|
|
|
|
|
return 1; |
|
77
|
|
|
|
|
|
|
} |
|
78
|
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
# called when we are loaded |
|
80
|
|
|
|
|
|
|
sub load { |
|
81
|
|
|
|
|
|
|
# setup a management command to dump statistics |
|
82
|
|
|
|
|
|
|
Perlbal::register_global_hook("manage_command.stats", sub { |
|
83
|
0
|
|
|
0
|
|
|
my @res; |
|
84
|
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
# create temporary object for stats storage |
|
86
|
0
|
|
|
|
|
|
my $gsobj = Perlbal::Plugin::Stats::Storage->new(); |
|
87
|
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
# dump per service |
|
89
|
0
|
|
|
|
|
|
foreach my $svc (keys %statobjs) { |
|
90
|
0
|
|
|
|
|
|
my $sobj = $statobjs{$svc}->[1]; |
|
91
|
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
# for now, simply dump the numbers we have |
|
93
|
0
|
|
|
|
|
|
foreach my $key (sort @statkeys) { |
|
94
|
0
|
|
|
|
|
|
push @res, sprintf("%-15s %-25s %12d", $svc, $key, $sobj->{$key}); |
|
95
|
0
|
|
|
|
|
|
$gsobj->{$key} += $sobj->{$key}; |
|
96
|
|
|
|
|
|
|
} |
|
97
|
|
|
|
|
|
|
} |
|
98
|
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
# global stats |
|
100
|
0
|
|
|
|
|
|
foreach my $key (sort @statkeys) { |
|
101
|
0
|
|
|
|
|
|
push @res, sprintf("%-15s %-25s %12d", 'total', $key, $gsobj->{$key}); |
|
102
|
|
|
|
|
|
|
} |
|
103
|
|
|
|
|
|
|
|
|
104
|
0
|
|
|
|
|
|
push @res, "."; |
|
105
|
0
|
|
|
|
|
|
return \@res; |
|
106
|
0
|
|
|
0
|
0
|
|
}); |
|
107
|
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
# recent requests and how long they took |
|
109
|
|
|
|
|
|
|
Perlbal::register_global_hook("manage_command.recent", sub { |
|
110
|
0
|
|
|
0
|
|
|
my @res; |
|
111
|
0
|
|
|
|
|
|
foreach my $svc (keys %statobjs) { |
|
112
|
0
|
|
|
|
|
|
my $sobj = $statobjs{$svc}->[1]; |
|
113
|
0
|
|
|
|
|
|
push @res, "$svc $_" |
|
114
|
0
|
|
|
|
|
|
foreach @{$sobj->{recent}}; |
|
115
|
|
|
|
|
|
|
} |
|
116
|
|
|
|
|
|
|
|
|
117
|
0
|
|
|
|
|
|
push @res, "."; |
|
118
|
0
|
|
|
|
|
|
return \@res; |
|
119
|
0
|
|
|
|
|
|
}); |
|
120
|
|
|
|
|
|
|
|
|
121
|
0
|
|
|
|
|
|
return 1; |
|
122
|
|
|
|
|
|
|
} |
|
123
|
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
# called for a global unload |
|
125
|
|
|
|
|
|
|
sub unload { |
|
126
|
|
|
|
|
|
|
# unregister our global hooks |
|
127
|
0
|
|
|
0
|
0
|
|
Perlbal::unregister_global_hook('manage_command.stats'); |
|
128
|
0
|
|
|
|
|
|
Perlbal::unregister_global_hook('manage_command.recent'); |
|
129
|
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
# take out all service stuff |
|
131
|
0
|
|
|
|
|
|
foreach my $statref (values %statobjs) { |
|
132
|
0
|
|
|
|
|
|
$statref->[0]->unregister_hooks('Stats'); |
|
133
|
|
|
|
|
|
|
} |
|
134
|
0
|
|
|
|
|
|
%statobjs = (); |
|
135
|
|
|
|
|
|
|
|
|
136
|
0
|
|
|
|
|
|
return 1; |
|
137
|
|
|
|
|
|
|
} |
|
138
|
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
# statistics storage object |
|
140
|
|
|
|
|
|
|
package Perlbal::Plugin::Stats::Storage; |
|
141
|
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
use fields ( |
|
143
|
1
|
|
|
|
|
27
|
'files_sent', # files sent from disk (includes reproxies and regular web requests) |
|
144
|
|
|
|
|
|
|
'files_reproxied', # files we've sent via reproxying (told to by backend) |
|
145
|
|
|
|
|
|
|
'web_requests', # requests we sent ourselves (no reproxy, no backend) |
|
146
|
|
|
|
|
|
|
'proxy_requests', # regular requests that went to a backend to be served |
|
147
|
|
|
|
|
|
|
'proxy_requests_highpri', # same as above, except high priority |
|
148
|
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
'pending', # hashref; { "obj" => time_start } |
|
150
|
|
|
|
|
|
|
'recent', # arrayref; strings of recent URIs and times |
|
151
|
1
|
|
|
1
|
|
1668
|
); |
|
|
1
|
|
|
|
|
8
|
|
|
152
|
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
sub new { |
|
154
|
0
|
|
|
0
|
|
|
my Perlbal::Plugin::Stats::Storage $self = shift; |
|
155
|
0
|
0
|
|
|
|
|
$self = fields::new($self) unless ref $self; |
|
156
|
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
# 0 initialize everything here |
|
158
|
0
|
|
|
|
|
|
$self->{$_} = 0 foreach @Perlbal::Plugin::Stats::statkeys; |
|
159
|
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
# other setup |
|
161
|
0
|
|
|
|
|
|
$self->{pending} = {}; |
|
162
|
0
|
|
|
|
|
|
$self->{recent} = []; |
|
163
|
|
|
|
|
|
|
|
|
164
|
0
|
|
|
|
|
|
return $self; |
|
165
|
|
|
|
|
|
|
} |
|
166
|
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
1; |