我有一个应用程序在 DBI 调用期间随机死亡的问题。我们无法在我们的测试或验收环境中可靠地重现这一点,因此我需要在我们的生产系统上对其进行监控,以试图找出正在发生的事情。
我正在通过环境变量记录所有DBI
流量。DBI_TRACE
DBI_TRACE=3=dbi.log script.pl
然而,问题是 DBI 日志文件中没有时间戳,因此很难通过它们来查找在死机时发生的情况。
有没有办法启用带有时间戳的 DBI 日志记录?
您可以使用File::Tee重定向 STDERR 并添加带有时间戳的前缀。
例如:
use strict;
use warnings;
use File::Tee 'tee';
my $logfile = "/path/to/timestamped/logfile.log";
my $filter = sub { return localtime() . ' ' . $_[0] };
my $pid = tee STDERR, { preprocess => $filter, reopen => $logfile };
print STDERR "something bad happened.";
这里的优点是它不会干扰您现有的 STDERR——所有错误消息将继续发送到同一个地方。但是流被复制并写入$logfile
,通过$filter
钩子进行任何您想要的转换。
如果覆盖STDERR
不是一个选项,并且如果您使用的是 UNIXy 系统(各种帖子都建议您这样做),您可以将跟踪输出定向到fifo并在那里运行时间戳过滤器:
$ mkfifo /tmp/fifo
$ perl -MTime::HiRes=time -npe 's/^/time . " "/e' < /tmp/fifo > /tmp/timestamped.log &
[1] 12345
$ DBI_TRACE=1=/tmp/fifo script.pl
该过滤程序可以是任何东西,甚至是logger ,它在我的系统上添加了由syslogd提供的时间戳。
DBI 文档包含如何使用分层文件句柄启用时间戳日志的代码。缺点是您失去了使用环境变量的奢侈,并且必须在代码中设置跟踪参数:
$dbh->trace('SQL', $fh);
其中 $fh 包含对PerlIO::Via的“子类”对象的引用
我建议看看DBI::Log。
默认情况下,它会打印到 STDERR,因此要复制您的使用情况,您可以这样称呼它:
perl -MDBI::Log script.pl 2> dbi.log
通过以下方式,输出可以让您更好地了解基于 DBI 的 SQL 访问中发生的情况:
尽管有可能,但我怀疑 DBI 本身是否存在问题。尽管我看到您使用的是跟踪级别 3,但 DBI 的跟踪可能非常冗长。使用 DBIx::Log4perl,您将获得可配置的时间戳、方法调用、SQL、绑定等跟踪,您需要做的就是更改连接调用。
我写了一个简约的perl 记录器,带有可配置的动态日志记录,为您提供以下 API:
use strict ; use warnings ; use Exporter;
use Configurator ;
use Logger ;
# anonymous hash !!!
our $confHolder = () ;
sub main {
# strip the remote path and keep the bare name
$0=~m/^(.*)(\\|\/)(.*)\.([a-z]*)/;
my $MyBareName = $3;
my $RunDir= $1 ;
# create the configurator object
my $objConfigurator = new Configurator($RunDir , $MyBareName );
# get the hash having the vars
$confHolder = $objConfigurator ->getConfHolder () ;
# pring the hash vars
print $objConfigurator->dumpIni();
my $objLogger = new Logger (\$confHolder) ;
$objLogger->LogMsg ( " START MAIN " ) ;
$objLogger->LogMsg ( "my \$RunDir is $RunDir" ) ;
$objLogger->LogMsg ( "this is a simple message" ) ;
$objLogger->LogErrorMsg ( "This is an error message " ) ;
$objLogger->LogWarningMsg ( "This is a warning message " ) ;
$objLogger->LogInfoMsg ( "This is a info message " ) ;
$objLogger->LogDebugMsg ( "This is a debug message " ) ;
$objLogger->LogTraceMsg ( "This is a trace message " ) ;
$objLogger->LogMsg ( "using the following log file " . "$confHolder->{'LogFile'}" ) ;
$objLogger->LogMsg ( " STOP MAIN \n\n" ) ;
} #eof main
#Action !!!
main();
1 ;
__END__