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