File Coverage

blib/lib/PerlGuard/Agent/Output/PerlGuardServer.pm
Criterion Covered Total %
statement 21 75 28.0
branch 0 20 0.0
condition 0 2 0.0
subroutine 7 15 46.6
pod 0 7 0.0
total 28 119 23.5


line stmt bran cond sub pod time code
1             package PerlGuard::Agent::Output::PerlGuardServer;
2 1     1   2259 use Moo;
  1         3  
  1         11  
3             extends 'PerlGuard::Agent::Output';
4              
5 1     1   3783 use HTTP::Async;
  1         5954  
  1         31  
6 1     1   14762 use Encode;
  1         21595  
  1         97  
7 1     1   1111 use JSON;
  1         21999  
  1         7  
8 1     1   1553 use HTTP::Request;
  1         1472  
  1         41  
9 1     1   11 use HTTP::Headers;
  1         2  
  1         51  
10 1     1   8 use Time::HiRes;
  1         4  
  1         12  
11              
12             has api_key => ( is => 'rw', lazy => 1, default => \&_attempt_to_fetch_api_key_from_env_or_die);
13             has base_url => ( is => 'rw', lazy => 1, default => \&DEFAULT_BASE_URL );
14              
15             has async_http => ( is => 'rw', lazy => 1, default => sub { HTTP::Async->new(timeout => 2, max_request_time=>2, slots=>1000000); });
16              
17             has disabled_until => (is => 'rw', lazy => 1, default => sub { [0,0] });
18              
19             has headers => (is => 'rw', lazy => 1, default => sub {
20             HTTP::Headers->new(
21             'X-API-KEY' => shift->api_key,
22             'content-type' => 'application/json'
23             )
24             });
25              
26             has json_encoder => ( is => 'rw', lazy => 1, default => sub { JSON->new->utf8->convert_blessed->allow_blessed });
27              
28             sub DEFAULT_BASE_URL {
29 0     0 0   return 'https://perlguard.com';
30             }
31              
32             sub _attempt_to_fetch_api_key_from_env_or_die {
33 0     0     my $self = shift;
34 0   0       return $ENV{PERLGUARD_API_KEY} || die "No api_key specified, can be specified in PerlGuard::Agent->new() or with an ENV var named PERLGUARD_API_KEY";
35             }
36              
37             sub save {
38 0     0 0   my $self = shift;
39 0           my $profile = shift;
40              
41 0 0         return unless $profile->should_save();
42              
43 0           my $content = {
44             "start_time" => $profile->start_time,
45             "finish_time" => $profile->finish_time,
46             "total_elapsed_time_in_ms" => $profile->total_elapsed_time_in_ms,
47             "cross_application_tracing_id" => $profile->cross_application_tracing_id,
48             # "project_id": 10,
49             "type" => "web",
50             "grouping_name" => $profile->controller . '#' . $profile->controller_action,
51             "database_transactions" => $self->format_database_transactions($profile),
52             "web_transactions" => $self->format_webservice_transactions($profile),
53             "database_elapsed_time_in_ms" => $profile->database_elapsed_time_in_ms,
54             "web_elapsed_time_in_ms" => $profile->webservice_elapsed_time_in_ms,
55             "sum_of_database_transactions" => $profile->database_transaction_count,
56             "sum_of_web_transactions" => $profile->webservice_transaction_count,
57             };
58              
59 0           $content = $self->json_encoder->encode($content);
60              
61             #warn $content;
62              
63 0           $self->check_responses();
64              
65 0 0         unless($self->can_run_yet()) {
66 0           warn "Skipping due to previous errors\n";
67 0           return;
68             }
69              
70             #without_collectors_do {} - We can't really include sending this report in the request time..
71              
72 0 0         if($self->async_http->to_send_count > 250) {
73 0           warn "PerlGuard send queue has reached 250, dropping subsequent requests\n";
74 0           return;
75             }
76              
77 0 0         if($self->async_http->in_progress_count > 250) {
78 0           warn "PerlGuard in progress count queue has reached 250, dropping subsequent requests\n";
79 0           return;
80             }
81              
82 0           my $request_id = $self->async_http->add( HTTP::Request->new(
83             POST => $self->base_url . "/collector/v1/profile",
84             $self->headers,
85             $content
86             ));
87              
88 0           while($self->async_http->to_send_count > 0) {
89 0           $self->async_http->poke();
90             }
91              
92             #warn "completed send";
93              
94             # This helped keep things cleaner on local but it quite obviously causes a race condition,
95             #$self->async_http->remove($request_id);
96              
97              
98             }
99              
100             sub flush {
101 0     0 0   my $self = shift;
102              
103 0           while($self->async_http->not_empty) {
104 0           $self->async_http->next_response( $self->async_http->max_request_time );
105             }
106             }
107              
108             sub check_responses {
109 0     0 0   my $self = shift;
110              
111 0           while(my $response = $self->async_http->next_response) {
112 0 0         if($response->is_error) {
113             #print STDERR "Response is " . $response->as_string ."\n";
114              
115 0           my $next_run_time = [Time::HiRes::gettimeofday];
116 0           $next_run_time->[0]++;
117              
118 0           $self->disabled_until($next_run_time);
119              
120             }
121              
122             }; #Clear queue
123             }
124              
125             sub can_run_yet {
126 0     0 0   my $self = shift;
127              
128 0 0         return Time::HiRes::tv_interval( $self->disabled_until ) >= 0 ? 1 : 0;
129             }
130              
131             sub format_database_transactions {
132 0     0 0   my $self = shift;
133 0           my $profile = shift;
134              
135 0           my @results;
136              
137 0           foreach my $row(@{$profile->database_transactions}) {
  0            
138 0 0         if($row->{start_time}) {
139 0           $row->{start_time_offset} = $profile->calculate_time_index_in_ms($row->{start_time});
140             }
141 0 0         if($row->{finish_time}) {
142 0           $row->{finish_time_offset} = $profile->calculate_time_index_in_ms($row->{finish_time});
143             }
144              
145 0           push @results, $row;
146             }
147              
148 0           return \@results;
149              
150             }
151              
152             sub format_webservice_transactions {
153 0     0 0   my $self = shift;
154 0           my $profile = shift;
155              
156 0           my @results;
157              
158 0           foreach my $row(@{$profile->webservice_transactions}) {
  0            
159 0 0         if($row->{start_time}) {
160 0           $row->{start_time_offset} = $profile->calculate_time_index_in_ms($row->{start_time});
161             }
162 0 0         if($row->{finish_time}) {
163 0           $row->{finish_time_offset} = $profile->calculate_time_index_in_ms($row->{finish_time});
164             }
165              
166 0           push @results, $row;
167              
168             }
169              
170 0           return \@results;
171              
172             }
173              
174              
175              
176              
177             1;