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 |