【发布时间】:2011-01-22 23:48:31
【问题描述】:
如何在 Perl 中获取堆栈跟踪?
【问题讨论】:
-
perl -d script.plDB<1> t 50Trace = on (to level 51)DB<2> T
标签: perl stack-trace
如何在 Perl 中获取堆栈跟踪?
【问题讨论】:
perl -d script.plDB<1> t 50Trace = on (to level 51)DB<2> T
标签: perl stack-trace
出于调试需要,我喜欢Carp::Always。
perl -MCarp::Always my_script.pl
【讨论】:
Carp::confess(来自use Carp;)将作为错误的一部分为您提供完整的堆栈跟踪。如果你只是需要它作为失败的一部分,confess 就是你真正需要的。
每个 cmets,这里是各种 Carp 函数的输出:
use strict;
use warnings;
use Carp qw/longmess cluck confess/;
sub foo {
&bar;
}
sub bar {
&baz;
}
sub baz {
shift->();
}
my %tests = (
'longmess' => sub { print longmess 'longmess' },
'cluck' => sub { cluck 'using cluck' },
'confess' => sub { confess 'using confess' },
);
while (my ($name, $sub) = each %tests) {
print "$name - before eval:\n";
eval {
foo($sub);
};
print "$name - before if:\n";
if ($@) {
print "caught: $@";
}
print "$name - done\n\n";
}
运行这个脚本,你会得到:
longmess - 在评估之前: longmess 在 - 第 14 行 main::baz 在第 10 行调用 main::bar 在第 6 行调用 main::foo('CODE(0x183a4d0)') 在第 26 行调用 eval {...} 在第 25 行调用 longmess - 之前如果: 长篇大论 - 完成 承认 - 在评估之前: 承认 - 之前如果: 抓到:在第 20 行使用表白 main::__ANON__() 在第 14 行调用 main::baz 在第 10 行调用 main::bar 在第 6 行调用 main::foo('CODE(0x183a3e0)') 在第 26 行调用 eval {...} 在第 25 行调用 承认 - 完成 咯咯 - 在评估之前: 在第 19 行使用咯咯声 main::__ANON__() 在第 14 行调用 main::baz 在第 10 行调用 main::bar 在第 6 行调用 main::foo('CODE(0x183a434)') 在第 26 行调用 eval {...} 在第 25 行调用 咯咯 - 之前如果: 咯咯 - 完成运行此脚本但重定向 STDOUT(从而显示在 STDERR 上打印的内容),您会得到:
在第 19 行使用咯咯声 main::__ANON__() 在第 14 行调用 main::baz 在第 10 行调用 main::bar 在第 6 行调用 main::foo('CODE(0x183a434)') 在第 26 行调用 eval {...} 在第 25 行调用【讨论】:
cluck 是带有堆栈跟踪的警告,confess 是一个死机。
有许多有用的、基于核心和 CPAN 的工具可以生成堆栈跟踪(如其他答案所示。)但是,如果您想自己动手,请查看 caller 内置工具。您可以使用它沿着堆栈向下走,看看到底发生了什么。
【讨论】:
Devel::StackTrace。
caller 的示例。
使用caller 的简单方法。
此代码不使用任何附加模块。只需在需要的地方添加即可。
my $i = 1;
print "Stack Trace:\n";
while ( (my @call_details = (caller($i++))) ){
print $call_details[1].":".$call_details[2]." in function ".$call_details[3]."\n";
}
【讨论】: