Apache-Voodoo/lib/Apache/Voodoo/Debug/Native.pm
################################################################################
#
# Apache::Voodoo::Debug - handles operations associated with debugging output.
#
# This object is used by Voodoo internally to handling various types of debugging
# information and to produce end user display of that information. End users
# never interact with this module directly, instead they use the methods from
# the Apache::Voodoo base class.
#
################################################################################
package Apache::Voodoo::Debug::Native;
$VERSION = "3.0200";
use strict;
use warnings;
use base("Apache::Voodoo::Debug::Common");
use Apache::Voodoo::Constants;
use DBI;
use HTML::Template;
use JSON::DWIW;
sub new {
my $class = shift;
my $id = shift;
my $conf = shift;
my $self = {};
bless($self,$class);
$self->{id}->{app_id} = $id;
my $ac = Apache::Voodoo::Constants->new();
my @flags = qw(debug info warn error exception table trace);
my @flag2 = qw(profile params template_conf return_data session);
$self->{enabled} = 0;
if ($conf eq "1" || (ref($conf) eq "HASH" && $conf->{all})) {
foreach (@flags,@flag2) {
$self->{enable}->{$_} = 1;
}
$self->{enable}->{anydebug} = 1;
$self->{enabled} = 1;
}
elsif (ref($conf) eq "HASH") {
foreach (@flags) {
if ($conf->{$_}) {
$self->{enable}->{$_} = 1;
$self->{enable}->{anydebug} = 1;
$self->{enabled} = 1;
}
}
foreach (@flag2) {
if ($conf->{$_}) {
$self->{enable}->{$_} = 1;
$self->{enabled} = 1;
}
}
}
if ($self->{enabled}) {
my $file = $INC{"Apache/Voodoo/Constants.pm"};
$file =~ s/Constants.pm$/Debug\/html\/debug.tmpl/;
$self->{template} = HTML::Template->new(
'filename' => $file,
'die_on_bad_params' => 0,
'global_vars' => 1,
'loop_context_vars' => 1
);
$self->{template}->param(
debug_root => $ac->debug_path(),
app_id => $self->{id}->{app_id}
);
$self->{json} = JSON::DWIW->new({bad_char_policy => 'convert', pretty => 1});
$self->{db_info} = $ac->debug_dbd();
my $dbh;
eval {
$dbh = DBI->connect(@{$self->{db_info}});
};
if ($@) {
warn "Debugging infomation will be lost: $@";
$self->{enabled} = 0;
return;
}
# From the DBI docs. This will give use the database server name
my $db_type = $dbh->get_info(17);
eval {
require "Apache/Voodoo/Debug/Native/$db_type.pm";
my $class = 'Apache::Voodoo::Debug::Native::'.$db_type;
$self->{db} = $class->new();
};
if ($@) {
die "$db_type is not supported: $@";
}
$self->{db}->init_db($dbh,$ac);
}
# we always send this since is fundamental to identifying the request chain
# regardless of what other info we log
$self->{enable}->{url} = 1;
$self->{enable}->{status} = 1;
$self->{enable}->{session_id} = 1;
return $self;
}
sub init {
my $self = shift;
my $mp = shift;
return unless $self->{enabled};
$self->{id}->{request_id} = $mp->request_id();
$self->{db}->set_dbh(DBI->connect(@{$self->{db_info}}) || die DBI->errstr);
$self->_write({
type => 'request',
id => $self->{'id'}
});
$self->{template}->param(request_id => $self->{id}->{request_id});
}
sub enabled {
return $_[0]->{enabled};
}
sub shutdown {
$_[0]->{db}->db_disconnect();
return;
}
sub debug { my $self = shift; $self->_debug('debug', @_); }
sub info { my $self = shift; $self->_debug('info', @_); }
sub warn { my $self = shift; $self->_debug('warn', @_); }
sub error { my $self = shift; $self->_debug('error', @_); }
sub exception { my $self = shift; $self->_debug('exception',@_); }
sub trace { my $self = shift; $self->_debug('trace', @_); }
sub table { my $self = shift; $self->_debug('table', @_); }
sub _debug {
my $self = shift;
my $type = shift;
return unless $self->{'enable'}->{$type};
my $data;
if (scalar(@_) > 1 || ref($_[0])) {
# if there's more than one item, or the item we have is a reference
# then we need to serialize it.
$data = $self->_encode(@_);
}
else {
# simple scalar can be logged as is.
$data = $_[0];
}
my $full = ($type =~ /(exception|trace)/)?1:0;
$self->_write({
type => 'debug',
id => $self->{id},
level => $type,
stack => $self->_encode([$self->stack_trace($full)]),
data => $data
});
}
sub mark {
my $self = shift;
return unless $self->{'enable'}->{'profile'};
$self->_write({
type => 'profile',
id => $self->{id},
timestamp => shift,
data => shift
});
}
sub return_data {
my $self = shift;
return unless $self->{'enable'}->{'return_data'};
$self->_write({
type => 'return_data',
id => $self->{id},
handler => shift,
method => shift,
data => $self->_encode(shift)
});
}
# these all behave the same way. With the execption of session_id which
# also inserts it into the underlying template.
sub url { my $self = shift; $self->_log('url', @_); }
sub status { my $self = shift; $self->_log('status', @_); }
sub params { my $self = shift; $self->_log('params', @_); }
sub template_conf { my $self = shift; $self->_log('template_conf', @_); }
sub session { my $self = shift; $self->_log('session', @_); }
sub session_id {
my $self = shift;
my $id = shift;
$self->{template}->param(session_id => $id);
$self->_log('session_id',$id);
}
sub _log {
my $self = shift;
my $type = shift;
return unless $self->{'enable'}->{$type};
my $data;
if (scalar(@_) > 1 || ref($_[0])) {
# if there's more than one item, or the item we have is a reference
# then we need to serialize it.
$data = $self->_encode(@_);
}
else {
# simple scalar can be logged as is.
$data = $_[0];
}
$self->_write({
type => $type,
id => $self->{id},
data => $data
});
}
sub _encode {
my $self = shift;
my $j;
if (scalar(@_) > 1) {
$j = $self->{json}->to_json(\@_);
}
else {
$j = $self->{json}->to_json($_[0]);
}
return $j;
}
sub _write {
my $self = shift;
my $data = shift;
my $handler = 'handle_'.$data->{'type'};
if ($self->{db}->can($handler)) {
$self->{db}->$handler($data);
}
}
sub finalize {
my $self = shift;
return () unless $self->{enabled};
foreach (keys %{$self->{'enable'}}) {
$self->{template}->param('enable_'.$_ => $self->{'enable'}->{$_});
}
return (_DEBUG_ => $self->{template}->output());
}
1;
################################################################################
# Copyright (c) 2005-2010 Steven Edwards (maverick@smurfbane.org).
# All rights reserved.
#
# You may use and distribute Apache::Voodoo under the terms described in the
# LICENSE file include in this package. The summary is it's a legalese version
# of the Artistic License :)
#
################################################################################