| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Mojolicious::Plugin::Status; |
|
2
|
1
|
|
|
1
|
|
1335
|
use Mojo::Base 'Mojolicious::Plugin'; |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
9
|
|
|
3
|
|
|
|
|
|
|
|
|
4
|
1
|
|
|
1
|
|
916
|
use BSD::Resource qw(getrusage); |
|
|
1
|
|
|
|
|
2216
|
|
|
|
1
|
|
|
|
|
6
|
|
|
5
|
1
|
|
|
1
|
|
113
|
use Time::HiRes qw(time); |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
8
|
|
|
6
|
1
|
|
|
1
|
|
131
|
use Mojo::File qw(path); |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
46
|
|
|
7
|
1
|
|
|
1
|
|
5
|
use Mojo::IOLoop; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
12
|
|
|
8
|
1
|
|
|
1
|
|
502
|
use Mojo::MemoryMap; |
|
|
1
|
|
|
|
|
5
|
|
|
|
1
|
|
|
|
|
12
|
|
|
9
|
1
|
|
|
1
|
|
41
|
use Mojo::Util qw(humanize_bytes); |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
64
|
|
|
10
|
|
|
|
|
|
|
|
|
11
|
1
|
|
|
1
|
|
6
|
use constant MACOS => $^O eq 'darwin'; |
|
|
1
|
|
|
|
|
4
|
|
|
|
1
|
|
|
|
|
3537
|
|
|
12
|
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
our $VERSION = '1.17'; |
|
14
|
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
sub register { |
|
16
|
1
|
|
|
1
|
1
|
56
|
my ($self, $app, $config) = @_; |
|
17
|
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
# Config |
|
19
|
1
|
|
33
|
|
|
6
|
my $prefix = $config->{route} // $app->routes->any('/mojo-status'); |
|
20
|
1
|
|
50
|
|
|
9
|
$prefix->to(return_to => $config->{return_to} // '/'); |
|
21
|
1
|
|
50
|
|
|
49
|
$self->{slowest} = $config->{slowest} // 10; |
|
22
|
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
# Initialize cache |
|
24
|
1
|
|
|
|
|
5
|
my $map = $self->{map} = Mojo::MemoryMap->new($config->{size}); |
|
25
|
1
|
|
|
|
|
11
|
$map->writer->store({processed => 0, started => time, stats => _stats(), slowest => []}); |
|
26
|
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
# Only the two built-in servers are supported for now |
|
28
|
1
|
|
|
2
|
|
9
|
$app->hook(before_server_start => sub { $self->_start(@_) }); |
|
|
2
|
|
|
|
|
7475
|
|
|
29
|
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
# Static files |
|
31
|
1
|
|
|
|
|
50
|
my $resources = path(__FILE__)->sibling('resources'); |
|
32
|
1
|
|
|
|
|
211
|
push @{$app->static->paths}, $resources->child('public')->to_string; |
|
|
1
|
|
|
|
|
10
|
|
|
33
|
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
# Templates |
|
35
|
1
|
|
|
|
|
78
|
push @{$app->renderer->paths}, $resources->child('templates')->to_string; |
|
|
1
|
|
|
|
|
8
|
|
|
36
|
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
# Routes |
|
38
|
1
|
|
|
|
|
62
|
$prefix->get('/' => => [format => ['json']] => {format => undef, mojo_status => $self} => \&_dashboard) |
|
39
|
|
|
|
|
|
|
->name('mojo_status'); |
|
40
|
|
|
|
|
|
|
} |
|
41
|
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
sub _activity { |
|
43
|
2
|
|
|
2
|
|
53
|
my $all = shift; |
|
44
|
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
# Workers |
|
46
|
2
|
|
|
|
|
6
|
my @table; |
|
47
|
2
|
|
|
|
|
6
|
for my $pid (sort keys %{$all->{workers}}) { |
|
|
2
|
|
|
|
|
19
|
|
|
48
|
2
|
|
|
|
|
10
|
my $worker = $all->{workers}{$pid}; |
|
49
|
2
|
|
|
|
|
49
|
my $cpu = sprintf '%.2f', $worker->{utime} + $worker->{stime}; |
|
50
|
2
|
|
|
|
|
9
|
my @worker = ($pid, $cpu, humanize_bytes($worker->{maxrss})); |
|
51
|
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
# Connections |
|
53
|
2
|
|
|
|
|
32
|
my $connections = $worker->{connections}; |
|
54
|
2
|
50
|
|
|
|
13
|
if (keys %$connections) { |
|
55
|
2
|
|
|
|
|
5
|
my $repeat; |
|
56
|
2
|
|
|
|
|
11
|
for my $cid (sort keys %$connections) { |
|
57
|
2
|
|
|
|
|
4
|
my $conn = $connections->{$cid}; |
|
58
|
2
|
50
|
|
|
|
14
|
@worker = ('', '', '') if $repeat++; |
|
59
|
2
|
|
|
|
|
7
|
my $bytes_read = humanize_bytes $conn->{bytes_read}; |
|
60
|
2
|
|
|
|
|
40
|
my $bytes_written = humanize_bytes $conn->{bytes_written}; |
|
61
|
2
|
|
|
|
|
30
|
my $rw = "$bytes_read/$bytes_written"; |
|
62
|
2
|
|
|
|
|
21
|
my @conn = ($conn->{client}, $rw, $conn->{processed}); |
|
63
|
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
# Request |
|
65
|
2
|
50
|
|
|
|
10
|
if (my $req = $conn->{request}) { |
|
66
|
2
|
50
|
|
|
|
11
|
my $active = $req->{finished} ? 0 : 1; |
|
67
|
2
|
|
|
|
|
4
|
my ($rid, $proto) = @{$req}{qw(request_id protocol)}; |
|
|
2
|
|
|
|
|
9
|
|
|
68
|
|
|
|
|
|
|
|
|
69
|
2
|
|
|
|
|
7
|
my $str = "$req->{method} $req->{path}"; |
|
70
|
2
|
100
|
|
|
|
10
|
$str .= "?$req->{query}" if $req->{query}; |
|
71
|
2
|
50
|
|
|
|
10
|
$str .= " → $req->{status}" if $req->{status}; |
|
72
|
|
|
|
|
|
|
|
|
73
|
2
|
50
|
|
|
|
23
|
my $finished = $active ? time : $req->{finished}; |
|
74
|
2
|
|
|
|
|
19
|
my $time = sprintf '%.2f', $finished - $req->{started}; |
|
75
|
2
|
|
|
|
|
19
|
push @table, [@worker, @conn, $rid, $active, $time, $proto, $str]; |
|
76
|
|
|
|
|
|
|
} |
|
77
|
0
|
|
|
|
|
0
|
else { push @table, [@worker, @conn] } |
|
78
|
|
|
|
|
|
|
} |
|
79
|
|
|
|
|
|
|
} |
|
80
|
0
|
|
|
|
|
0
|
else { push @table, \@worker } |
|
81
|
|
|
|
|
|
|
} |
|
82
|
|
|
|
|
|
|
|
|
83
|
2
|
|
|
|
|
10
|
return \@table; |
|
84
|
|
|
|
|
|
|
} |
|
85
|
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
sub _dashboard { |
|
87
|
9
|
|
|
9
|
|
15778
|
my $c = shift; |
|
88
|
|
|
|
|
|
|
|
|
89
|
9
|
|
|
|
|
35
|
my $map = $c->stash('mojo_status')->{map}; |
|
90
|
9
|
100
|
|
|
|
140
|
if ($c->param('reset')) { |
|
91
|
1
|
|
|
1
|
|
341
|
$map->writer->change(sub { @{$_}{qw(slowest stats)} = ([], _stats()) }); |
|
|
1
|
|
|
|
|
7
|
|
|
|
1
|
|
|
|
|
10
|
|
|
92
|
1
|
|
|
|
|
8
|
return $c->redirect_to('mojo_status'); |
|
93
|
|
|
|
|
|
|
} |
|
94
|
|
|
|
|
|
|
|
|
95
|
8
|
|
|
|
|
2361
|
my $all = $map->writer->fetch; |
|
96
|
|
|
|
|
|
|
$c->respond_to( |
|
97
|
|
|
|
|
|
|
html => sub { |
|
98
|
2
|
|
|
2
|
|
1090
|
$c->render( |
|
99
|
|
|
|
|
|
|
'mojo-status/dashboard', |
|
100
|
|
|
|
|
|
|
now => time, |
|
101
|
|
|
|
|
|
|
usage => humanize_bytes($map->usage), |
|
102
|
|
|
|
|
|
|
size => humanize_bytes($map->size), |
|
103
|
|
|
|
|
|
|
activity => _activity($all), |
|
104
|
|
|
|
|
|
|
slowest => _slowest($all), |
|
105
|
|
|
|
|
|
|
all => $all |
|
106
|
|
|
|
|
|
|
); |
|
107
|
|
|
|
|
|
|
}, |
|
108
|
8
|
|
|
|
|
47
|
json => {json => $all} |
|
109
|
|
|
|
|
|
|
); |
|
110
|
|
|
|
|
|
|
} |
|
111
|
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
sub _read_write { |
|
113
|
64
|
|
|
64
|
|
161
|
my ($all, $id) = @_; |
|
114
|
64
|
50
|
|
|
|
393
|
return unless my $stream = Mojo::IOLoop->stream($id); |
|
115
|
64
|
|
|
|
|
1290
|
@{$all->{workers}{$$}{connections}{$id}}{qw(bytes_read bytes_written)} |
|
|
64
|
|
|
|
|
623
|
|
|
116
|
|
|
|
|
|
|
= ($stream->bytes_read, $stream->bytes_written); |
|
117
|
|
|
|
|
|
|
} |
|
118
|
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
sub _request { |
|
120
|
64
|
|
|
64
|
|
152
|
my ($self, $c) = @_; |
|
121
|
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
# Request start |
|
123
|
64
|
|
|
|
|
184
|
my $tx = $c->tx; |
|
124
|
64
|
|
|
|
|
369
|
my $id = $tx->connection; |
|
125
|
64
|
|
|
|
|
482
|
my $req = $tx->req; |
|
126
|
64
|
|
|
|
|
388
|
my $url = $req->url->to_abs; |
|
127
|
64
|
50
|
|
|
|
12610
|
my $proto = $tx->is_websocket ? 'ws' : 'http'; |
|
128
|
64
|
50
|
|
|
|
405
|
$proto .= 's' if $req->is_secure; |
|
129
|
|
|
|
|
|
|
$self->{map}->writer->change(sub { |
|
130
|
|
|
|
|
|
|
$_->{workers}{$$}{connections}{$id}{request} = { |
|
131
|
64
|
|
|
64
|
|
275
|
request_id => $req->request_id, |
|
132
|
|
|
|
|
|
|
method => $req->method, |
|
133
|
|
|
|
|
|
|
protocol => $proto, |
|
134
|
|
|
|
|
|
|
path => $url->path->to_abs_string, |
|
135
|
|
|
|
|
|
|
query => $url->query->to_string, |
|
136
|
|
|
|
|
|
|
started => time |
|
137
|
|
|
|
|
|
|
}; |
|
138
|
64
|
|
|
|
|
14389
|
_read_write($_, $id); |
|
139
|
64
|
|
|
|
|
243
|
$_->{workers}{$$}{connections}{$id}{client} = $tx->remote_address; |
|
140
|
64
|
|
|
|
|
1674
|
}); |
|
141
|
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
# Request end |
|
143
|
|
|
|
|
|
|
$tx->on( |
|
144
|
|
|
|
|
|
|
finish => sub { |
|
145
|
64
|
|
|
64
|
|
126800
|
my $tx = shift; |
|
146
|
|
|
|
|
|
|
$self->{map}->writer->change(sub { |
|
147
|
64
|
50
|
|
|
|
291
|
return unless my $worker = $_->{workers}{$$}; |
|
148
|
|
|
|
|
|
|
|
|
149
|
64
|
|
50
|
|
|
228
|
my $code = $tx->res->code || 0; |
|
150
|
64
|
50
|
|
|
|
795
|
if ($code > 499) { $_->{stats}{server_error}++ } |
|
|
0
|
50
|
|
|
|
0
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
151
|
0
|
|
|
|
|
0
|
elsif ($code > 399) { $_->{stats}{client_error}++ } |
|
152
|
2
|
|
|
|
|
6
|
elsif ($code > 299) { $_->{stats}{redirect}++ } |
|
153
|
62
|
|
|
|
|
131
|
elsif ($code > 199) { $_->{stats}{success}++ } |
|
154
|
0
|
|
|
|
|
0
|
elsif ($code) { $_->{stats}{info}++ } |
|
155
|
|
|
|
|
|
|
|
|
156
|
64
|
|
|
|
|
228
|
@{$worker->{connections}{$id}{request}}{qw(finished status)} = (time, $code); |
|
|
64
|
|
|
|
|
241
|
|
|
157
|
64
|
|
|
|
|
142
|
$worker->{connections}{$id}{processed}++; |
|
158
|
64
|
|
|
|
|
109
|
$worker->{processed}++; |
|
159
|
64
|
|
|
|
|
188
|
$_->{processed}++; |
|
160
|
64
|
|
|
|
|
345
|
}); |
|
161
|
|
|
|
|
|
|
} |
|
162
|
64
|
|
|
|
|
502
|
); |
|
163
|
|
|
|
|
|
|
} |
|
164
|
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
sub _rendered { |
|
166
|
64
|
|
|
64
|
|
184
|
my ($self, $c) = @_; |
|
167
|
|
|
|
|
|
|
|
|
168
|
64
|
|
|
|
|
220
|
my $id = $c->tx->connection; |
|
169
|
|
|
|
|
|
|
$self->{map}->writer->change(sub { |
|
170
|
64
|
50
|
|
64
|
|
296
|
return unless my $conn = $_->{workers}{$$}{connections}{$id}; |
|
171
|
64
|
50
|
|
|
|
170
|
return unless my $req = $conn->{request}; |
|
172
|
64
|
|
|
|
|
275
|
$req->{time} = time - $req->{started}; |
|
173
|
64
|
|
|
|
|
248
|
@{$req}{qw(client status worker)} = ($conn->{client}, $c->res->code, $$); |
|
|
64
|
|
|
|
|
1061
|
|
|
174
|
|
|
|
|
|
|
|
|
175
|
64
|
|
|
|
|
158
|
my $slowest = $_->{slowest}; |
|
176
|
64
|
|
|
|
|
332
|
@$slowest = sort { $b->{time} <=> $a->{time} } @$slowest, $req; |
|
|
470
|
|
|
|
|
1074
|
|
|
177
|
64
|
|
|
|
|
114
|
my %seen; |
|
178
|
64
|
|
|
|
|
149
|
@$slowest = grep { !$seen{"$_->{method} $_->{path}"}++ } @$slowest; |
|
|
324
|
|
|
|
|
1192
|
|
|
179
|
64
|
|
|
|
|
499
|
pop @$slowest while @$slowest > $self->{slowest}; |
|
180
|
64
|
|
|
|
|
875
|
}); |
|
181
|
|
|
|
|
|
|
} |
|
182
|
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
sub _resources { |
|
184
|
2
|
|
|
2
|
|
5
|
my $self = shift; |
|
185
|
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
$self->{map}->writer->change(sub { |
|
187
|
2
|
|
|
2
|
|
41
|
@{$_->{workers}{$$}}{qw(utime stime maxrss)} = (getrusage)[0, 1, 2]; |
|
|
2
|
|
|
|
|
768
|
|
|
188
|
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
# macOS actually returns bytes instead of kilobytes |
|
190
|
2
|
|
|
|
|
12
|
$_->{workers}{$$}{maxrss} = $_->{workers}{$$}{maxrss} * 1000 unless MACOS; |
|
191
|
|
|
|
|
|
|
|
|
192
|
2
|
|
|
|
|
4
|
for my $id (keys %{$_->{workers}{$$}{connections}}) { _read_write($_, $id) } |
|
|
2
|
|
|
|
|
13
|
|
|
|
0
|
|
|
|
|
0
|
|
|
193
|
2
|
|
|
|
|
7
|
}); |
|
194
|
|
|
|
|
|
|
} |
|
195
|
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
sub _slowest { |
|
197
|
2
|
|
|
2
|
|
6
|
my $all = shift; |
|
198
|
|
|
|
|
|
|
|
|
199
|
2
|
|
|
|
|
5
|
my @table; |
|
200
|
2
|
|
|
|
|
4
|
for my $req (@{$all->{slowest}}) { |
|
|
2
|
|
|
|
|
14
|
|
|
201
|
8
|
|
|
|
|
24
|
my $str = "$req->{method} $req->{path}"; |
|
202
|
8
|
100
|
|
|
|
25
|
$str .= "?$req->{query}" if $req->{query}; |
|
203
|
8
|
50
|
|
|
|
39
|
$str .= " → $req->{status}" if $req->{status}; |
|
204
|
8
|
|
|
|
|
35
|
my $time = sprintf '%.2f', $req->{time}; |
|
205
|
8
|
|
|
|
|
18
|
push @table, [$time, $str, @{$req}{qw(request_id worker client started)}]; |
|
|
8
|
|
|
|
|
30
|
|
|
206
|
|
|
|
|
|
|
} |
|
207
|
|
|
|
|
|
|
|
|
208
|
2
|
|
|
|
|
17
|
return \@table; |
|
209
|
|
|
|
|
|
|
} |
|
210
|
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
sub _start { |
|
212
|
2
|
|
|
2
|
|
8
|
my ($self, $server, $app) = @_; |
|
213
|
|
|
|
|
|
|
|
|
214
|
2
|
50
|
|
|
|
17
|
return $app->log->warn('Server not suported by Mojolicious::Plugin::Status') |
|
215
|
|
|
|
|
|
|
unless $server->isa('Mojo::Server::Daemon'); |
|
216
|
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
# Register started workers |
|
218
|
|
|
|
|
|
|
Mojo::IOLoop->next_tick(sub { |
|
219
|
2
|
|
|
2
|
|
1868
|
$self->{map}->writer->change(sub { $_->{workers}{$$} = {started => time, processed => 0} }); |
|
|
2
|
|
|
|
|
16
|
|
|
220
|
2
|
|
|
|
|
40
|
}); |
|
221
|
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
# Remove stopped workers |
|
223
|
|
|
|
|
|
|
$server->on( |
|
224
|
|
|
|
|
|
|
reap => sub { |
|
225
|
0
|
|
|
0
|
|
0
|
my ($server, $pid) = @_; |
|
226
|
0
|
|
|
|
|
0
|
$self->{map}->writer->change(sub { delete $_->{workers}{$pid} }); |
|
|
0
|
|
|
|
|
0
|
|
|
227
|
|
|
|
|
|
|
} |
|
228
|
2
|
50
|
|
|
|
210
|
) if $server->isa('Mojo::Server::Prefork'); |
|
229
|
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
# Collect stats |
|
231
|
2
|
|
|
64
|
|
35
|
$app->hook(after_build_tx => sub { $self->_tx(@_) }); |
|
|
64
|
|
|
|
|
242419
|
|
|
232
|
2
|
|
|
64
|
|
58
|
$app->hook(before_dispatch => sub { $self->_request(@_) }); |
|
|
64
|
|
|
|
|
41673
|
|
|
233
|
2
|
|
|
64
|
|
34
|
$app->hook(after_dispatch => sub { $self->_rendered(@_) }); |
|
|
64
|
|
|
|
|
108898
|
|
|
234
|
2
|
|
|
2
|
|
32
|
Mojo::IOLoop->next_tick(sub { $self->_resources }); |
|
|
2
|
|
|
|
|
25
|
|
|
235
|
2
|
|
|
0
|
|
65
|
Mojo::IOLoop->recurring(5 => sub { $self->_resources }); |
|
|
0
|
|
|
|
|
0
|
|
|
236
|
|
|
|
|
|
|
} |
|
237
|
|
|
|
|
|
|
|
|
238
|
2
|
|
|
2
|
|
39
|
sub _stats { {started => time, info => 0, success => 0, redirect => 0, client_error => 0, server_error => 0} } |
|
239
|
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
sub _stream { |
|
241
|
1
|
|
|
1
|
|
5
|
my ($self, $id) = @_; |
|
242
|
|
|
|
|
|
|
|
|
243
|
1
|
|
|
|
|
7
|
my $stream = Mojo::IOLoop->stream($id); |
|
244
|
|
|
|
|
|
|
$stream->on( |
|
245
|
|
|
|
|
|
|
close => sub { |
|
246
|
1
|
50
|
|
1
|
|
34974
|
$self->{map}->writer->change(sub { delete $_->{workers}{$$}{connections}{$id} if $_->{workers}{$$} }); |
|
|
1
|
|
|
|
|
11
|
|
|
247
|
|
|
|
|
|
|
} |
|
248
|
1
|
|
|
|
|
24
|
); |
|
249
|
|
|
|
|
|
|
} |
|
250
|
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
sub _tx { |
|
252
|
64
|
|
|
64
|
|
172
|
my ($self, $tx, $app) = @_; |
|
253
|
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
$tx->on( |
|
255
|
|
|
|
|
|
|
connection => sub { |
|
256
|
64
|
|
|
64
|
|
2192
|
my ($tx, $id) = @_; |
|
257
|
|
|
|
|
|
|
|
|
258
|
64
|
|
|
|
|
205
|
my $map = $self->{map}; |
|
259
|
64
|
100
|
|
|
|
284
|
return if $map->writer->fetch->{workers}{$$}{connections}{$id}; |
|
260
|
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
$map->writer->change(sub { |
|
262
|
1
|
|
|
|
|
11
|
$_->{workers}{$$}{connections}{$id} = {started => time, processed => 0, bytes_read => 0, bytes_written => 0}; |
|
263
|
1
|
|
|
|
|
8
|
}); |
|
264
|
1
|
|
|
|
|
6
|
$self->_stream($id); |
|
265
|
|
|
|
|
|
|
} |
|
266
|
64
|
|
|
|
|
403
|
); |
|
267
|
|
|
|
|
|
|
} |
|
268
|
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
1; |
|
270
|
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
=encoding utf8 |
|
272
|
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
=head1 NAME |
|
274
|
|
|
|
|
|
|
|
|
275
|
|
|
|
|
|
|
Mojolicious::Plugin::Status - Mojolicious server status |
|
276
|
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
278
|
|
|
|
|
|
|
|
|
279
|
|
|
|
|
|
|
# Mojolicious |
|
280
|
|
|
|
|
|
|
$self->plugin('Status'); |
|
281
|
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
# Mojolicious::Lite |
|
283
|
|
|
|
|
|
|
plugin 'Status'; |
|
284
|
|
|
|
|
|
|
|
|
285
|
|
|
|
|
|
|
# Secure access to the server status ui with Basic authentication |
|
286
|
|
|
|
|
|
|
my $under = $self->routes->under('/status' => sub ($c) { |
|
287
|
|
|
|
|
|
|
return 1 if $c->req->url->to_abs->userinfo eq 'Bender:rocks'; |
|
288
|
|
|
|
|
|
|
$c->res->headers->www_authenticate('Basic'); |
|
289
|
|
|
|
|
|
|
$c->render(text => 'Authentication required!', status => 401); |
|
290
|
|
|
|
|
|
|
return undef; |
|
291
|
|
|
|
|
|
|
}); |
|
292
|
|
|
|
|
|
|
$self->plugin('Status' => {route => $under}); |
|
293
|
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
295
|
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
=begin html |
|
297
|
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
width="600px"> |
|
301
|
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
=end html |
|
304
|
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
L is a L plugin providing a server status ui for L and |
|
306
|
|
|
|
|
|
|
L. Note that this module is B and should therefore only be used for debugging |
|
307
|
|
|
|
|
|
|
purposes. |
|
308
|
|
|
|
|
|
|
|
|
309
|
|
|
|
|
|
|
=head1 OPTIONS |
|
310
|
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
L supports the following options. |
|
312
|
|
|
|
|
|
|
|
|
313
|
|
|
|
|
|
|
=head2 return_to |
|
314
|
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
# Mojolicious::Lite |
|
316
|
|
|
|
|
|
|
plugin Status => {return_to => 'some_route'}; |
|
317
|
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
Name of route or path to return to when leaving the server status ui, defaults to C>. |
|
319
|
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
=head2 route |
|
321
|
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
# Mojolicious::Lite |
|
323
|
|
|
|
|
|
|
plugin Status => {route => app->routes->any('/status')}; |
|
324
|
|
|
|
|
|
|
|
|
325
|
|
|
|
|
|
|
L object to attach the server status ui to, defaults to generating a new one with the |
|
326
|
|
|
|
|
|
|
prefix C. |
|
327
|
|
|
|
|
|
|
|
|
328
|
|
|
|
|
|
|
=head2 size |
|
329
|
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
# Mojolicious::Lite |
|
331
|
|
|
|
|
|
|
plugin Status => {size => 1234}; |
|
332
|
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
Size of anonymous mapped memory to use for storing statistics, defaults to C<52428800> (50 MiB). |
|
334
|
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
=head2 slowest |
|
336
|
|
|
|
|
|
|
|
|
337
|
|
|
|
|
|
|
# Mojolicious::Lite |
|
338
|
|
|
|
|
|
|
plugin Status => {slowest => 5}; |
|
339
|
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
Number of slowest requests to track, defaults to C<10>. |
|
341
|
|
|
|
|
|
|
|
|
342
|
|
|
|
|
|
|
=head1 METHODS |
|
343
|
|
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
L inherits all methods from L and implements the following new ones. |
|
345
|
|
|
|
|
|
|
|
|
346
|
|
|
|
|
|
|
=head2 register |
|
347
|
|
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
my $route = $plugin->register(Mojolicious->new); |
|
349
|
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
Register renderer and helper in L application. |
|
351
|
|
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
=head1 BUNDLED FILES |
|
353
|
|
|
|
|
|
|
|
|
354
|
|
|
|
|
|
|
The L distribution includes a few files with different licenses that have been bundled for |
|
355
|
|
|
|
|
|
|
internal use. |
|
356
|
|
|
|
|
|
|
|
|
357
|
|
|
|
|
|
|
=head2 Artwork |
|
358
|
|
|
|
|
|
|
|
|
359
|
|
|
|
|
|
|
Copyright (C) 2018, Sebastian Riedel. |
|
360
|
|
|
|
|
|
|
|
|
361
|
|
|
|
|
|
|
Licensed under the CC-SA License, Version 4.0 L. |
|
362
|
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
=head2 Bootstrap |
|
364
|
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
Copyright (C) 2011-2018 The Bootstrap Authors. |
|
366
|
|
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
Licensed under the MIT License, L. |
|
368
|
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
=head2 Font Awesome |
|
370
|
|
|
|
|
|
|
|
|
371
|
|
|
|
|
|
|
Copyright (C) Dave Gandy. |
|
372
|
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
Licensed under the MIT License, L, and the SIL OFL 1.1, |
|
374
|
|
|
|
|
|
|
L. |
|
375
|
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
=head1 AUTHOR |
|
377
|
|
|
|
|
|
|
|
|
378
|
|
|
|
|
|
|
Sebastian Riedel, C. |
|
379
|
|
|
|
|
|
|
|
|
380
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE |
|
381
|
|
|
|
|
|
|
|
|
382
|
|
|
|
|
|
|
Copyright (C) 2018-2021, Sebastian Riedel and others. |
|
383
|
|
|
|
|
|
|
|
|
384
|
|
|
|
|
|
|
This program is free software, you can redistribute it and/or modify it under the terms of the Artistic License version |
|
385
|
|
|
|
|
|
|
2.0. |
|
386
|
|
|
|
|
|
|
|
|
387
|
|
|
|
|
|
|
=head1 SEE ALSO |
|
388
|
|
|
|
|
|
|
|
|
389
|
|
|
|
|
|
|
L, L, L. |
|
390
|
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
=cut |