File Coverage

blib/lib/Apache/Voodoo/Debug/Handler.pm
Criterion Covered Total %
statement 24 219 10.9
branch 0 46 0.0
condition 0 6 0.0
subroutine 8 26 30.7
pod 0 17 0.0
total 32 314 10.1


line stmt bran cond sub pod time code
1             ################################################################################
2             #
3             # Apache::Voodoo::Debug::Handler
4             #
5             # Handles servicing debugging information requests
6             #
7             ################################################################################
8             package Apache::Voodoo::Debug::Handler;
9              
10             $VERSION = "3.0200";
11              
12 1     1   2834 use strict;
  1         3  
  1         37  
13 1     1   5 use warnings;
  1         4  
  1         40  
14              
15 1     1   6 use DBI;
  1         3  
  1         47  
16 1     1   5 use Time::HiRes;
  1         3  
  1         21  
17 1     1   103 use JSON::DWIW;
  1         3  
  1         13  
18              
19 1     1   89 use Apache::Voodoo::MP;
  1         2  
  1         28  
20 1     1   5 use Apache::Voodoo::Constants;
  1         12  
  1         656  
21              
22             sub new {
23 0     0 0   my $class = shift;
24 0           my $self = {};
25 0           bless $self, $class;
26              
27 0           $self->{mp} = Apache::Voodoo::MP->new();
28 0           $self->{constants} = Apache::Voodoo::Constants->new();
29              
30 0           $self->{debug_root} = $self->{constants}->debug_path();
31              
32 0           warn "Voodoo Debugging Handler Starting...\n";
33              
34 0           $self->{template_dir} = $INC{"Apache/Voodoo/Debug/Handler.pm"};
35 0           $self->{template_dir} =~ s/Handler.pm$/html/;
36              
37 0           $self->{handlers} = {
38 0           map { $_ => 'handle_'.$_ }
39             ('profile','debug','return_data','session','template_conf','parameters','request')
40             };
41              
42 0           $self->{static_files} = {
43             "debug.css" => "text/css",
44             "debug.js" => "application/x-javascript",
45             "debug.png" => "image/png",
46             "error.png" => "image/png",
47             "exception.png" => "image/png",
48             "info.png" => "image/png",
49             "minus.png" => "image/png",
50             "plus.png" => "image/png",
51             "spinner.gif" => "image/gif",
52             "table.png" => "image/png",
53             "trace.png" => "image/png",
54             "warn.png" => "image/png"
55             };
56              
57 0           $self->{json} = JSON::DWIW->new({bad_char_policy => 'convert', pretty => 1});;
58              
59 0           return $self;
60             }
61              
62             sub handler {
63 0     0 0   my $self = shift;
64 0           my $r = shift;
65              
66 0           $self->{mp}->set_request($r);
67              
68             # holds all vars associated with this page processing request
69 0           my $uri = $self->{mp}->uri();
70 0           $uri =~ s/^$self->{debug_root}//;
71 0           $uri =~ s/^\///;
72              
73 0 0         if (defined($self->{static_files}->{$uri})) {
    0          
74             # request for one of the static files.
75              
76 0           my $file = File::Spec->catfile($self->{template_dir},$uri);
77 0           my $mtime = (stat($file))[9];
78              
79             # Handle "if not modified since" requests.
80 0           $r->update_mtime($mtime);
81 0           $r->set_last_modified;
82 0           $r->meets_conditions;
83 0           my $rc = $self->{mp}->if_modified_since($mtime);
84 0 0         return $rc unless $rc == $self->{mp}->ok;
85              
86             # set the content type
87 0           $self->{mp}->content_type($self->{static_files}->{$uri});
88              
89             # tell apache to send the underlying file
90 0           $r->sendfile($file);
91              
92 0           return $self->{mp}->ok;
93             }
94             elsif (defined($self->{handlers}->{$uri})) {
95             # request for an operation
96              
97 0           my $method = $self->{handlers}->{$uri};
98              
99             # parse the params
100 0           my $params = $self->{mp}->parse_params(1);
101 0 0         unless (ref($params)) {
102             # something went boom
103 0           return $self->display_host_error($params);
104             }
105              
106             # connect to the debugging database
107 0           my $dbh = DBI->connect_cached(@{$self->{constants}->debug_dbd()});
  0            
108 0 0         unless ($dbh) {
109 0           return $self->display_host_error("Can't connect to debugging database: ".DBI->errstr);
110             }
111              
112 0           my $return;
113 0           eval {
114 0           $return = $self->$method($dbh,$params);
115             };
116 1     1   7 use Data::Dumper;
  1         4  
  1         2342  
117 0           warn Dumper $@;
118 0 0         if ($@) {
119 0           return $self->display_host_error("$@");
120             }
121              
122 0 0         if (ref($return) eq "HASH") {
123 0           $self->{mp}->content_type("application/json");
124 0           $self->{mp}->print($self->{json}->to_json($return));
125             }
126             else {
127 0           $self->{mp}->content_type("text/plain");
128 0           $self->{mp}->print($return);
129             }
130              
131 0           $self->{mp}->flush();
132              
133 0           return $self->{mp}->ok;
134             }
135              
136             # not a request we handle
137 0           return $self->{mp}->declined;
138             }
139              
140             sub display_host_error {
141 0     0 0   my $self = shift;
142 0           my $error = shift;
143              
144 0           $self->{'mp'}->content_type("text/html");
145 0           $self->{'mp'}->print("

The following error was encountered while processing this request:

");
146 0           $self->{'mp'}->print("
$error
");
147 0           $self->{'mp'}->flush();
148              
149 0           return $self->{mp}->ok;
150             }
151              
152             sub json_data {
153 0     0 0   my $self = shift;
154 0           my $type = shift;
155 0           my $data = shift;
156              
157 0 0         if (ref($data)) {
    0          
158 0           $data = $self->{json}->to_json($data);
159             }
160             elsif ($data !~ /^\s*[\[\{\"]/) {
161 0           $data = '"'.$data.'"';
162             }
163              
164 0           return '{"key":"'.$type.'","value":'.$data.'}';
165             }
166              
167             sub json_error {
168 0     0 0   my $self = shift;
169 0           my $errors = shift;
170              
171 0           my $return = {
172             'success' => 'false',
173             'errors' => []
174             };
175              
176 0 0         if (ref($errors) eq "HASH") {
177 0           foreach my $key (keys %{$errors}) {
  0            
178 0           push(@{$return->{errors}},{id => $key, msg => $errors->{$key}});
  0            
179             }
180             }
181             else {
182 0           push(@{$return->{errors}},{id => 'error', msg => $errors});
  0            
183             }
184              
185 0           return $return;
186             }
187              
188 0     0 0   sub json_true { return $JSON::DWIW->true; }
189 0     0 0   sub json_false { return $JSON::DWIW->false; }
190              
191             sub get_request_id {
192 0     0 0   my $self = shift;
193 0           my $dbh = shift;
194 0           my $id = shift;
195              
196 0 0         unless ($id->{request_id} =~ /^\d+(\.\d*)?$/) {
197 0           return "invalid request id";
198             }
199              
200 0 0         unless ($id->{app_id} =~ /^[a-z]\w*$/i) {
201 0           return "invalid application id";
202             }
203              
204 0 0         unless ($id->{session_id} =~ /^[0-9a-z]+$/i) {
205 0           return "invalid session id";
206             }
207              
208              
209 0           my $res = $dbh->selectcol_arrayref("
210             SELECT id
211             FROM request
212             WHERE
213             request_timestamp = ? AND
214             application = ? AND
215             session_id = ?",undef,
216             $id->{request_id},
217             $id->{app_id},
218             $id->{session_id});
219              
220 0 0         unless ($res->[0] > 0) {
221 0           return "no such id";
222             }
223              
224 0           return $res->[0];
225             }
226              
227             sub select_data_by_id {
228 0     0 0   my $self = shift;
229 0           my $dbh = shift;
230 0           my $table = shift;
231 0           my $id = shift;
232              
233 0           my $res = $dbh->selectall_arrayref("
234             SELECT
235             data
236             FROM
237             $table
238             WHERE
239             request_id = ?",undef,
240             $id);
241              
242 0           return $res->[0]->[0];
243             }
244              
245             sub simple_data {
246 0     0 0   my $self = shift;
247 0           my $dbh = shift;
248 0           my $params = shift;
249 0           my $key = shift;
250 0           my $table = shift;
251              
252 0           my $id = $self->get_request_id($dbh,$params);
253 0 0         unless ($id =~ /^\d+$/) {
254 0           return $self->json_error($id);
255             }
256              
257 0           return $self->json_data(
258             $key,
259             $self->select_data_by_id($dbh,$table,$id)
260             );
261             }
262              
263             sub handle_template_conf {
264 0     0 0   my $self = shift;
265 0           my $dbh = shift;
266 0           my $params = shift;
267              
268 0           return $self->simple_data($dbh,$params,'vd_template_conf','template_conf');
269             }
270              
271             sub handle_parameters {
272 0     0 0   my $self = shift;
273 0           my $dbh = shift;
274 0           my $params = shift;
275              
276 0           return $self->simple_data($dbh,$params,'vd_parameters','params');
277             }
278              
279             sub handle_session {
280 0     0 0   my $self = shift;
281 0           my $dbh = shift;
282 0           my $params = shift;
283              
284 0           return $self->simple_data($dbh,$params,'vd_session','session');
285             }
286              
287             sub handle_request {
288 0     0 0   my $self = shift;
289 0           my $dbh = shift;
290 0           my $params = shift;
291              
292 0           my $app_id = $params->{'app_id'};
293 0           my $session_id = $params->{'session_id'};
294 0           my $request_id = $params->{'request_id'};
295              
296 0           my $return = [];
297 0 0 0       if ($app_id =~ /^[a-z]\w+/i &&
      0        
298             $session_id =~ /^[a-f0-9]+$/i &&
299             $request_id =~ /^\d+\.\d+$/) {
300              
301 0           $return = $dbh->selectall_arrayref("
302             SELECT
303             request_timestamp AS request_id,
304             url
305             FROM
306             request
307             WHERE
308             application = ? AND
309             session_id = ? AND
310             request_timestamp >= ?
311             ORDER BY
312             id",{Slice => {}},
313             $app_id,
314             $session_id,
315             $request_id);
316             }
317              
318 0           return $self->json_data('vd_request',$return);
319             }
320              
321             sub handle_return_data {
322 0     0 0   my $self = shift;
323 0           my $dbh = shift;
324 0           my $params = shift;
325              
326 0           my $id = $self->get_request_id($dbh,$params);
327 0 0         unless ($id =~ /^\d+$/) {
328 0           return $self->json_error($id);
329             }
330              
331 0           my $res = $dbh->selectall_arrayref("
332             SELECT
333             handler,
334             method,
335             data
336             FROM
337             return_data
338             WHERE
339             request_id = ?
340             ORDER BY
341             seq",undef,
342             $id);
343              
344 0           my $d = '[';
345 0           foreach (@{$res}) {
  0            
346 0           $d .= '["'.$_->[0].'->'.$_->[1].'",'.$_->[2].'],';
347             }
348 0           $d =~ s/,$//;
349 0           $d .= ']';
350              
351 0           return $self->json_data('vd_return_data',$d);
352             }
353              
354             sub handle_debug {
355 0     0 0   my $self = shift;
356 0           my $dbh = shift;
357 0           my $params = shift;
358              
359 0           my $id = $self->get_request_id($dbh,$params);
360 0 0         unless ($id =~ /^\d+$/) {
361 0           return $self->json_error($id);
362             }
363              
364 0           my @levels;
365 0           foreach (qw(debug info warn error exception table trace)) {
366 0 0         if ($params->{$_} eq "1") {
367 0           push(@levels,$_);
368             }
369             }
370              
371 0           my $query = "
372             SELECT
373             level,
374             stack,
375             data
376             FROM
377             debug
378             WHERE
379             request_id = ?";
380              
381 0 0         if (scalar(@levels)) {
382 0           $query .= ' AND level IN (' . join(',',map { '?'} @levels) . ') ';
  0            
383             }
384              
385 0           $query .= "
386             ORDER BY
387             seq";
388              
389 0           my $res = $dbh->selectall_arrayref($query,undef,$id,@levels);
390              
391 0           return $self->json_data('vd_debug',$self->_process_debug($params->{app_id},$res));
392             }
393              
394             sub _process_debug {
395 0     0     my $self = shift;
396 0           my $app_id = shift;
397 0           my $data = shift;
398              
399 0           my $debug = '[';
400 0           foreach my $row (@{$data}) {
  0            
401 0           $debug .= '{"level":"'.$row->[0].'"';
402 0           $debug .= ',"stack":' .$row->[1];
403 0           $debug .= ',"data":';
404 0 0         if ($row->[2] =~ /^[\[\{\"]/) {
405 0           $debug .= $row->[2];
406             }
407             else {
408 0           $debug .= '"'.$row->[2].'"';
409             }
410              
411 0           $debug .= '},';
412             }
413 0           $debug =~ s/,$//;
414 0           $debug .= ']';
415              
416 0           return $debug;
417             }
418              
419             sub handle_profile {
420 0     0 0   my $self = shift;
421 0           my $dbh = shift;
422 0           my $params = shift;
423              
424 0           my $id = $self->get_request_id($dbh,$params);
425 0 0         unless ($id =~ /^\d+$/) {
426 0           return $self->json_error($id);
427             }
428              
429 0           my $res = $dbh->selectall_arrayref("
430             SELECT
431             timestamp,
432             data
433             FROM
434             profile
435             WHERE
436             request_id = ?
437             ORDER BY
438             timestamp",undef,
439             $id);
440              
441 0           my $return;
442 0           $return->{'key'} = 'vd_profile';
443              
444 0           my $last = $#{$res};
  0            
445 0 0         if ($last > 0) {
446 0           my $total_time = $res->[$last]->[0] - $res->[0]->[0];
447              
448 0           $return->{'value'} = [
449             map {
450 0           [
451             sprintf("%.5f", $res->[$_]->[0] - $res->[$_-1]->[0]),
452             sprintf("%5.2f%%",($res->[$_]->[0] - $res->[$_-1]->[0])/$total_time*100),
453             $res->[$_]->[1]
454             ]
455             } (1 .. $last)
456             ];
457              
458 0           unshift(@{$return->{value}}, [
  0            
459             sprintf("%.5f",$total_time),
460             'percent',
461             'message'
462             ]);
463             }
464              
465 0           return $return;
466             }
467              
468             1;
469             ################################################################################
470             # Copyright (c) 2005-2010 Steven Edwards (maverick@smurfbane.org).
471             # All rights reserved.
472             #
473             # You may use and distribute Apache::Voodoo under the terms described in the
474             # LICENSE file include in this package. The summary is it's a legalese version
475             # of the Artistic License :)
476             #
477             ################################################################################