File Coverage

blib/lib/Mojo/Netdata/Collector/HTTP.pm
Criterion Covered Total %
statement 85 86 98.8
branch 27 32 84.3
condition 11 14 78.5
subroutine 10 10 100.0
pod 2 2 100.0
total 135 144 93.7


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