| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Mojo::Netdata::Collector::HTTP; |
|
2
|
1
|
|
|
1
|
|
455
|
use Mojo::Base 'Mojo::Netdata::Collector', -signatures; |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
5
|
|
|
3
|
|
|
|
|
|
|
|
|
4
|
1
|
|
|
1
|
|
795
|
use Mojo::UserAgent; |
|
|
1
|
|
|
|
|
90907
|
|
|
|
1
|
|
|
|
|
36
|
|
|
5
|
1
|
|
|
1
|
|
79
|
use Mojo::Netdata::Util qw(logf safe_id); |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
92
|
|
|
6
|
1
|
|
|
1
|
|
7
|
use Time::HiRes qw(time); |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
24
|
|
|
7
|
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
has jobs => sub ($self) { +[] }; |
|
9
|
|
|
|
|
|
|
has type => 'HTTP'; |
|
10
|
|
|
|
|
|
|
has ua => sub { Mojo::UserAgent->new(insecure => 0, connect_timeout => 5, request_timeout => 5) }; |
|
11
|
|
|
|
|
|
|
has update_every => 30; |
|
12
|
|
|
|
|
|
|
|
|
13
|
3
|
|
|
3
|
1
|
33
|
sub register ($self, $config, $netdata) { |
|
|
3
|
|
|
|
|
7
|
|
|
|
3
|
|
|
|
|
40
|
|
|
|
3
|
|
|
|
|
5
|
|
|
|
3
|
|
|
|
|
6
|
|
|
14
|
|
|
|
|
|
|
$config->{update_every} ? $self->update_every($config->{update_every}) |
|
15
|
3
|
50
|
|
|
|
21
|
: $netdata->update_every >= 10 ? $self->update_every($netdata->update_every) |
|
|
|
50
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
: $self->update_every(30); |
|
17
|
|
|
|
|
|
|
|
|
18
|
3
|
100
|
|
|
|
61
|
$self->ua->insecure($config->{insecure}) if defined $config->{insecure}; |
|
19
|
3
|
100
|
|
|
|
30
|
$self->ua->connect_timeout($config->{connect_timeout}) if defined $config->{connect_timeout}; |
|
20
|
3
|
100
|
|
|
|
23
|
$self->ua->request_timeout($config->{request_timeout}) if defined $config->{request_timeout}; |
|
21
|
3
|
50
|
50
|
|
|
35
|
$self->ua->proxy->detect if $config->{proxy} // 1; |
|
22
|
3
|
|
|
|
|
220
|
$self->jobs([]); |
|
23
|
|
|
|
|
|
|
|
|
24
|
3
|
50
|
|
|
|
24
|
my @jobs = ref $config->{jobs} eq 'HASH' ? %{$config->{jobs}} : @{$config->{jobs}}; |
|
|
0
|
|
|
|
|
0
|
|
|
|
3
|
|
|
|
|
15
|
|
|
25
|
3
|
|
|
|
|
13
|
while (my $url = shift @jobs) { |
|
26
|
13
|
100
|
|
|
|
81
|
my $job = $self->_make_job($url => ref $jobs[0] eq 'HASH' ? shift @jobs : {}, $config); |
|
27
|
13
|
100
|
|
|
|
2724
|
push @{$self->jobs}, $job if $job; |
|
|
11
|
|
|
|
|
29
|
|
|
28
|
|
|
|
|
|
|
} |
|
29
|
|
|
|
|
|
|
|
|
30
|
3
|
50
|
|
|
|
25
|
return @{$self->jobs} ? $self : undef; |
|
|
3
|
|
|
|
|
9
|
|
|
31
|
|
|
|
|
|
|
} |
|
32
|
|
|
|
|
|
|
|
|
33
|
1
|
|
|
1
|
1
|
466
|
sub update_p ($self) { |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
2
|
|
|
34
|
1
|
|
|
|
|
5
|
my ($ua, @p) = ($self->ua); |
|
35
|
|
|
|
|
|
|
|
|
36
|
1
|
|
|
|
|
11
|
my $t0 = time; |
|
37
|
1
|
|
|
|
|
3
|
for my $job (@{$self->jobs}) { |
|
|
1
|
|
|
|
|
6
|
|
|
38
|
3
|
|
|
|
|
2175
|
my $tx = $ua->build_tx(@{$job->[0]}); |
|
|
3
|
|
|
|
|
21
|
|
|
39
|
2
|
|
|
2
|
|
4
|
push @p, $ua->start_p($tx)->then(sub ($tx) { |
|
|
2
|
|
|
|
|
508883
|
|
|
|
2
|
|
|
|
|
6
|
|
|
40
|
2
|
|
|
|
|
11
|
my $t1 = time; |
|
41
|
2
|
|
|
|
|
9
|
logf(debug => '%s %s == %s', $tx->req->method, $tx->req->url, $tx->res->code); |
|
42
|
2
|
|
|
|
|
15
|
$job->[1]->($tx, $t0); |
|
43
|
1
|
|
|
1
|
|
2
|
})->catch(sub ($err) { |
|
|
1
|
|
|
|
|
162837
|
|
|
|
1
|
|
|
|
|
4
|
|
|
44
|
1
|
|
|
|
|
5
|
logf(warnings => '%s %s == %s', $tx->req->method, $tx->req->url, $err); |
|
45
|
1
|
|
|
|
|
6
|
$job->[1]->($tx, $t0); |
|
46
|
3
|
|
|
|
|
1519
|
}); |
|
47
|
|
|
|
|
|
|
} |
|
48
|
|
|
|
|
|
|
|
|
49
|
1
|
|
|
|
|
2347
|
return Mojo::Promise->all(@p); |
|
50
|
|
|
|
|
|
|
} |
|
51
|
|
|
|
|
|
|
|
|
52
|
13
|
|
|
13
|
|
20
|
sub _make_job ($self, $url, $params, $defaults) { |
|
|
13
|
|
|
|
|
17
|
|
|
|
13
|
|
|
|
|
16
|
|
|
|
13
|
|
|
|
|
16
|
|
|
|
13
|
|
|
|
|
18
|
|
|
|
13
|
|
|
|
|
17
|
|
|
53
|
13
|
|
|
|
|
47
|
$url = Mojo::URL->new($url); |
|
54
|
13
|
100
|
|
|
|
2291
|
return undef unless my $host = $url->host; |
|
55
|
|
|
|
|
|
|
|
|
56
|
12
|
|
100
|
|
|
91
|
my $headers = Mojo::Headers->new->from_hash($defaults->{headers} || {}); |
|
57
|
12
|
100
|
|
|
|
260
|
$headers->header($_ => $params->{headers}{$_}) for keys %{$params->{headers} || {}}; |
|
|
12
|
|
|
|
|
65
|
|
|
58
|
|
|
|
|
|
|
|
|
59
|
12
|
|
66
|
|
|
159
|
my $dimension = $params->{dimension} || $headers->host || $url->host; |
|
60
|
12
|
|
66
|
|
|
157
|
my $family = $params->{family} || $defaults->{family} || $headers->host || $url->host; |
|
61
|
|
|
|
|
|
|
|
|
62
|
12
|
|
|
|
|
119
|
my $code_chart = $self->chart("${family}_code")->title("HTTP Status code for $family") |
|
63
|
|
|
|
|
|
|
->context('httpcheck.code')->family($family)->units('#'); |
|
64
|
|
|
|
|
|
|
|
|
65
|
12
|
100
|
|
|
|
426
|
if ($code_chart->dimension($dimension)) { |
|
66
|
1
|
|
|
|
|
7
|
logf(warnings => 'Family "%s" already has dimension "%s".', $family, $dimension); |
|
67
|
1
|
|
|
|
|
4
|
return undef; |
|
68
|
|
|
|
|
|
|
} |
|
69
|
|
|
|
|
|
|
|
|
70
|
11
|
|
|
|
|
40
|
my $time_chart = $self->chart("${family}_time")->title("Response time for $family") |
|
71
|
|
|
|
|
|
|
->context('httpcheck.responsetime')->family($family)->units('ms'); |
|
72
|
|
|
|
|
|
|
|
|
73
|
11
|
|
|
|
|
345
|
$code_chart->dimension($dimension => {}); |
|
74
|
11
|
|
|
|
|
32
|
$time_chart->dimension($dimension => {}); |
|
75
|
|
|
|
|
|
|
|
|
76
|
9
|
|
|
9
|
|
13
|
my $update = sub ($tx, $t0) { |
|
|
9
|
|
|
|
|
637
|
|
|
|
9
|
|
|
|
|
14
|
|
|
|
9
|
|
|
|
|
13
|
|
|
77
|
9
|
|
|
|
|
118
|
$time_chart->dimension($dimension => {value => int(1000 * (time - $t0))}); |
|
78
|
9
|
|
100
|
|
|
34
|
$code_chart->dimension($dimension => {value => $tx->res->code // 0}); |
|
79
|
11
|
|
|
|
|
60
|
}; |
|
80
|
|
|
|
|
|
|
|
|
81
|
11
|
|
|
|
|
15
|
my @data; |
|
82
|
11
|
|
|
|
|
37
|
push @data, $headers->to_hash(1); |
|
83
|
|
|
|
|
|
|
push @data, |
|
84
|
|
|
|
|
|
|
exists $params->{json} ? (json => $params->{json}) |
|
85
|
|
|
|
|
|
|
: exists $params->{form} ? (form => $params->{form}) |
|
86
|
|
|
|
|
|
|
: exists $params->{body} ? ($params->{body}) |
|
87
|
11
|
100
|
|
|
|
230
|
: (); |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
|
|
89
|
11
|
|
|
|
|
34
|
logf(info => 'Tracking %s', $url); |
|
90
|
11
|
|
100
|
|
|
50
|
return [[$params->{method} || 'GET', $url->to_unsafe_string, @data], $update]; |
|
91
|
|
|
|
|
|
|
} |
|
92
|
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
1; |
|
94
|
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
=encoding utf8 |
|
96
|
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
=head1 NAME |
|
98
|
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
Mojo::Netdata::Collector::HTTP - A website monitorer for Mojo::Netdata |
|
100
|
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
102
|
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
=head2 Config |
|
104
|
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
Below is an example C config file. Note |
|
106
|
|
|
|
|
|
|
that the file can have any name and you have have as many as you want, as long |
|
107
|
|
|
|
|
|
|
as it has the C<.conf.pl> extension. |
|
108
|
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
{ |
|
110
|
|
|
|
|
|
|
# Required |
|
111
|
|
|
|
|
|
|
collector => 'Mojo::Netdata::Collector::HTTP', |
|
112
|
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
# Optional |
|
114
|
|
|
|
|
|
|
insecure => 0, # Set to "1" to allow insecure SSL/TLS connections |
|
115
|
|
|
|
|
|
|
connect_timeout => 5, # Max time for the connection to be established |
|
116
|
|
|
|
|
|
|
request_timeout => 5, # Max time for the whole request to complete |
|
117
|
|
|
|
|
|
|
proxy => 1, # Set to "0" to disable proxy auto-detect |
|
118
|
|
|
|
|
|
|
update_every => 30, # How often to run the "jobs" below |
|
119
|
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
# Default values, unless defined in the job |
|
121
|
|
|
|
|
|
|
family => 'default-family-name', |
|
122
|
|
|
|
|
|
|
headers => {'X-Merged-With' => 'headers inside job config'}, |
|
123
|
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
# Required - List of URLs and an optional config hash (object) |
|
125
|
|
|
|
|
|
|
jobs => [ |
|
126
|
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
# List of URLs to check (Config is optional) |
|
128
|
|
|
|
|
|
|
'https://superwoman.example.com', |
|
129
|
|
|
|
|
|
|
'https://superman.example.com', |
|
130
|
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
# URL and config parameters |
|
132
|
|
|
|
|
|
|
'https://example.com' => { |
|
133
|
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
method => 'GET', # GET (Default), HEAD, POST, ... |
|
135
|
|
|
|
|
|
|
headers => {'X-Foo' => 'bar'}, # HTTP headers |
|
136
|
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
# Set "dimension" to get a custom label in the chart. |
|
138
|
|
|
|
|
|
|
# Default to the "Host" header or the host part of the URL. |
|
139
|
|
|
|
|
|
|
dimension => 'foo', # Default: "example.com" |
|
140
|
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
# Set "family" to group multiple domains together in one chart, |
|
142
|
|
|
|
|
|
|
# Default to the "Host" header or the host part of the URL. |
|
143
|
|
|
|
|
|
|
family => 'bar', # Default: "example.com" |
|
144
|
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
# Only one of these can be present |
|
146
|
|
|
|
|
|
|
json => {...}, # JSON HTTP body |
|
147
|
|
|
|
|
|
|
form => {key => $value}, # Form data |
|
148
|
|
|
|
|
|
|
body => '...', # Raw HTTP body |
|
149
|
|
|
|
|
|
|
}, |
|
150
|
|
|
|
|
|
|
], |
|
151
|
|
|
|
|
|
|
}; |
|
152
|
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
=head2 Health |
|
154
|
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
Here is an example C file: |
|
156
|
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
template: web_server_code |
|
158
|
|
|
|
|
|
|
on: httpcheck.code |
|
159
|
|
|
|
|
|
|
class: Errors |
|
160
|
|
|
|
|
|
|
type: Web Server |
|
161
|
|
|
|
|
|
|
component: HTTP endpoint |
|
162
|
|
|
|
|
|
|
plugin: mojo |
|
163
|
|
|
|
|
|
|
lookup: max -5m absolute foreach * |
|
164
|
|
|
|
|
|
|
every: 1m |
|
165
|
|
|
|
|
|
|
warn: $this >= 300 && $this < 500 |
|
166
|
|
|
|
|
|
|
crit: $this >= 500 && $this != 503 |
|
167
|
|
|
|
|
|
|
to: webmaster |
|
168
|
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
template: web_server_up |
|
170
|
|
|
|
|
|
|
on: httpcheck.code |
|
171
|
|
|
|
|
|
|
class: Errors |
|
172
|
|
|
|
|
|
|
type: Web Server |
|
173
|
|
|
|
|
|
|
component: HTTP endpoint |
|
174
|
|
|
|
|
|
|
plugin: mojo |
|
175
|
|
|
|
|
|
|
lookup: min -5m absolute foreach * |
|
176
|
|
|
|
|
|
|
every: 1m |
|
177
|
|
|
|
|
|
|
crit: $this == 0 |
|
178
|
|
|
|
|
|
|
units: up/down |
|
179
|
|
|
|
|
|
|
to: webmaster |
|
180
|
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
182
|
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
L is a collector that can chart web page |
|
184
|
|
|
|
|
|
|
response time and HTTP status codes. |
|
185
|
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
=head1 ATTRIBUTES |
|
187
|
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
=head2 jobs |
|
189
|
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
$array_ref = $self->jobs; |
|
191
|
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
A list of jobs generated by L. |
|
193
|
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
=head2 type |
|
195
|
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
$str = $collector->type; |
|
197
|
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
Defaults to "http". |
|
199
|
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
=head2 ua |
|
201
|
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
$ua = $collector->ua; |
|
203
|
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
Holds a L. |
|
205
|
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
=head2 update_every |
|
207
|
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
$num = $chart->update_every; |
|
209
|
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
Default value is 30. See L for more |
|
211
|
|
|
|
|
|
|
details. |
|
212
|
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
=head1 METHODS |
|
214
|
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
=head2 register |
|
216
|
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
$collector = $collector->register(\%config, $netdata); |
|
218
|
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
Returns a L<$collector> object if any "jobs" are defined in C<%config>. Will |
|
220
|
|
|
|
|
|
|
also set L from C<%config> or use L |
|
221
|
|
|
|
|
|
|
if it is 10 or greater. |
|
222
|
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
=head2 update_p |
|
224
|
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
$p = $collector->update_p; |
|
226
|
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
Gathers information about the "jobs" registered. |
|
228
|
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
=head1 SEE ALSO |
|
230
|
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
L and L. |
|
232
|
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
=cut |