Support logging DB queries

hinted-selects
Vitaliy Filippov 2014-11-01 00:18:57 +03:00
parent c59ff61181
commit 961e6ff825
5 changed files with 141 additions and 3 deletions

View File

@ -200,8 +200,6 @@ sub _tt_provider_load_compiled
# Global Code
#####################################################################
# $::SIG{__DIE__} = i_am_cgi() ? \&CGI::Carp::confess : \&Carp::confess;
# Note that this is a raw subroutine, not a method, so $class isn't available.
sub init_page
{
@ -1083,6 +1081,7 @@ sub _cleanup
{
next if !$dbh;
$dbh->bz_rollback_transaction() if $dbh->bz_in_transaction;
$dbh->write_query_log;
$dbh->disconnect;
}
undef $_request_cache;

View File

@ -95,6 +95,12 @@ use constant get_param_list => (
default => 0,
},
{
name => 'query_log',
type => 't',
default => '',
},
{
name => 'docs_urlbase',
type => 't',

View File

@ -44,6 +44,7 @@ use Bugzilla::Error;
use Bugzilla::DB::Schema;
use List::Util qw(max);
use POSIX qw(strftime);
use Storable qw(dclone);
#####################################################################
@ -1474,6 +1475,134 @@ sub _check_references {
}
}
sub interpolate_params
{
my $self = shift;
my ($sql, $bind) = @_;
my $r = '';
# match unquoted part + any number of quoted strings/identifiers
while ($sql =~ s!^([^"`']*)((?:`(?:[^`]+|``)*`|"(?:[^"\\]+|\\.|"")*"|'(?:[^'\\]+|\\.|'')*)*)!!so)
{
my ($c, $q) = ($1, $2);
last if $c eq '' && $q eq '';
$c =~ s/\?/$self->quote(shift @$bind)/geso;
$r .= $c.$q;
}
return $r;
}
sub write_query_log
{
my $self = shift;
if (my $logfile = Bugzilla->params->{query_log})
{
# Log queries
$logfile = bz_locations()->{datadir} . '/' . $logfile if substr($logfile, 0, 1) ne '/';
trick_taint($logfile);
my $fd;
my @q = @{ tied(%$self)->{_logged_queries} || [] };
if (@q && open $fd, ">>", $logfile)
{
print $fd strftime("[%Y-%m-%d %H:%M:%S] ", localtime) .
"[pid=$$] $ENV{REQUEST_URI} DB queries:\n" . join("\n", map { $self->interpolate_params(@$_).';' } @q) . "\n\n";
close $fd;
}
tied(%$self)->{_logged_queries} = [];
}
}
sub log_query
{
my $self = shift;
push @{tied(%$self)->{_logged_queries}}, [ @_ ] if Bugzilla->params->{query_log};
}
sub get_logged_queries
{
my $self = shift;
return tied(%$self)->{_logged_queries} || [];
}
sub do
{
my $self = shift;
my ($sql, undef, @bind) = @_;
$self->log_query($sql, \@bind);
$self->SUPER::do(@_);
}
sub selectrow_array
{
my $self = shift;
my ($sql, undef, @bind) = @_;
$self->log_query($sql, \@bind);
return $self->SUPER::selectrow_array(@_);
}
sub selectrow_arrayref
{
my $self = shift;
my ($sql, undef, @bind) = @_;
$self->log_query($sql, \@bind);
return $self->SUPER::selectrow_array(@_);
}
sub selectrow_hashref
{
my $self = shift;
my ($sql, undef, @bind) = @_;
$self->log_query($sql, \@bind);
return $self->SUPER::selectrow_hashref(@_);
}
sub selectall_hashref
{
my $self = shift;
my ($sql, undef, @bind) = @_;
$self->log_query($sql, \@bind);
return $self->SUPER::selectall_hashref(@_);
}
sub selectall_arrayref
{
my $self = shift;
my ($sql, undef, @bind) = @_;
$self->log_query($sql, \@bind);
return $self->SUPER::selectall_arrayref(@_);
}
sub selectcol_arrayref
{
my $self = shift;
my ($sql, undef, @bind) = @_;
$self->log_query($sql, \@bind);
return $self->SUPER::selectcol_arrayref(@_);
}
sub prepare
{
my $self = shift;
return bless $self->SUPER::prepare(@_), 'Bugzilla::DB::st';
}
sub prepare_cached
{
my $self = shift;
return bless $self->SUPER::prepare_cached(@_), 'Bugzilla::DB::st';
}
package Bugzilla::DB::st;
use base qw(DBI::st);
sub execute
{
my $self = shift;
my $dbh = tied(%$self)->{Database}->{Driver}->{ChildHandles};
$dbh->[$#$dbh]->log_query(tied(%$self)->{Statement}, [ @_ ]);
return $self->SUPER::execute(@_);
}
1;
__END__

View File

@ -778,7 +778,8 @@ sub bz_setup_database {
}
package Bugzilla::DB::Oracle::st;
use base qw(DBI::st);
use base qw(Bugzilla::DB::st);
sub fetchrow_arrayref
{

View File

@ -40,6 +40,9 @@
report_user_errors_to_maintainer =>
"Whether to send e-mail messages about each 'user' (invalid input, non-fatal) error to Bugzilla maintainer (not recommended).",
query_log =>
"<b>Use only for debug purposes!</b> Path to the file to which Bugzilla should log all database queries with all parameters.",
docs_urlbase =>
"The URL that is the common initial leading part of all"
_ " $terms.Bugzilla documentation URLs. It may be an absolute URL,"