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