Support logging DB queries
parent
c59ff61181
commit
961e6ff825
|
@ -200,8 +200,6 @@ sub _tt_provider_load_compiled
|
||||||
# Global Code
|
# 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.
|
# Note that this is a raw subroutine, not a method, so $class isn't available.
|
||||||
sub init_page
|
sub init_page
|
||||||
{
|
{
|
||||||
|
@ -1083,6 +1081,7 @@ sub _cleanup
|
||||||
{
|
{
|
||||||
next if !$dbh;
|
next if !$dbh;
|
||||||
$dbh->bz_rollback_transaction() if $dbh->bz_in_transaction;
|
$dbh->bz_rollback_transaction() if $dbh->bz_in_transaction;
|
||||||
|
$dbh->write_query_log;
|
||||||
$dbh->disconnect;
|
$dbh->disconnect;
|
||||||
}
|
}
|
||||||
undef $_request_cache;
|
undef $_request_cache;
|
||||||
|
|
|
@ -95,6 +95,12 @@ use constant get_param_list => (
|
||||||
default => 0,
|
default => 0,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
name => 'query_log',
|
||||||
|
type => 't',
|
||||||
|
default => '',
|
||||||
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
name => 'docs_urlbase',
|
name => 'docs_urlbase',
|
||||||
type => 't',
|
type => 't',
|
||||||
|
|
129
Bugzilla/DB.pm
129
Bugzilla/DB.pm
|
@ -44,6 +44,7 @@ use Bugzilla::Error;
|
||||||
use Bugzilla::DB::Schema;
|
use Bugzilla::DB::Schema;
|
||||||
|
|
||||||
use List::Util qw(max);
|
use List::Util qw(max);
|
||||||
|
use POSIX qw(strftime);
|
||||||
use Storable qw(dclone);
|
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;
|
1;
|
||||||
|
|
||||||
__END__
|
__END__
|
||||||
|
|
|
@ -778,7 +778,8 @@ sub bz_setup_database {
|
||||||
}
|
}
|
||||||
|
|
||||||
package Bugzilla::DB::Oracle::st;
|
package Bugzilla::DB::Oracle::st;
|
||||||
use base qw(DBI::st);
|
|
||||||
|
use base qw(Bugzilla::DB::st);
|
||||||
|
|
||||||
sub fetchrow_arrayref
|
sub fetchrow_arrayref
|
||||||
{
|
{
|
||||||
|
|
|
@ -40,6 +40,9 @@
|
||||||
report_user_errors_to_maintainer =>
|
report_user_errors_to_maintainer =>
|
||||||
"Whether to send e-mail messages about each 'user' (invalid input, non-fatal) error to Bugzilla maintainer (not recommended).",
|
"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 =>
|
docs_urlbase =>
|
||||||
"The URL that is the common initial leading part of all"
|
"The URL that is the common initial leading part of all"
|
||||||
_ " $terms.Bugzilla documentation URLs. It may be an absolute URL,"
|
_ " $terms.Bugzilla documentation URLs. It may be an absolute URL,"
|
||||||
|
|
Loading…
Reference in New Issue