我只想打印特定子程序的stacktrace。
可能吗 ?脚本在不带-d
选项的perl下运行。
简单的例子:
#!/usr/bin/env perl
foo();
sub foo {
print "Hello world\n";
# enable debugger from this moment with PERLDB_OPTS='NonStop frame=1'
bar();
# disable debugger from this moment
return;
}
sub bar {
print "Just another Perl hacker\n";
return;
}
预期输出:
$ perl test.pl
Hello world
entering main::bar
Just another Perl hacker
我尝试和$ENV{PERL5DB}
一起玩,但是没有效果:
$ENV{PERL5DB}='sub DB::DB {} sub sub {print ++$i, " $sub\n"; &$sub}';
bar();
$ENV{PERL5DB} = undef;
答案 0 :(得分:3)
您可以直接在代码中直接设置$DB::frame
:
#!/usr/bin/env perl
foo();
sub foo {
print "Hello world\n";
$DB::frame = 1;
bar();
$DB::frame = 0;
return;
}
sub bar {
print "Just another Perl hacker\n";
return;
}
可以如下运行:
$ PERLDB_OPTS=NonStop perl -d try.pl
Hello world
entering main::bar
Just another Perl hacker
就是这样。
如果您想手动执行并定义自己的自定义调试器,则可以按照以下步骤进行操作:
#!/usr/bin/env perl
foo();
sub foo {
print "Hello world\n";
$DB::xtrace = 1;
bar();
$DB::xtrace = 0;
return;
}
sub bar {
print "Just another Perl hacker\n";
return;
}
$ PERL5DB='BEGIN { package DB; sub DB {} sub sub { print STDERR " entering $sub\n" if $xtrace; &$sub } }' perl -d try.pl
Hello world
entering main::bar
Just another Perl hacker
答案 1 :(得分:1)
这仅仅是关于如何产生堆栈跟踪的问题吗?您不需要调试器。
use Carp;
sub bar {
Carp::cluck("entering main::bar");
...
}
答案 2 :(得分:1)
将脚本转换为模数将使您受益。
您遇到的问题是foo()
会在Perl进入运行时立即被直接调用。但是从调试的角度来看,这不是您想要的行为。
modulino的目的是允许将大部分代码视为嵌入式模块,并且仅在直接运行脚本时才运行启动或启动代码,而在脚本时则不运行而是作为模块加载。这样,您就可以针对模块代码编写测试套件,而仅将最小的启动代码保留在单元测试的范围之外。
以下是该主题的一些文章之一:https://perlmaven.com/modulino-both-script-and-module
出于您的目的,使用modulino,您可以更加选择使用Perl调试器运行什么。
如果您按如下所示组织代码,那么您会更加成功:
package MyModulino;
use parent 'Exporter';
our @EXPORT = qw(foo bar);
sub foo {
print "Hello world\n";
# enable debugger from this moment with PERLDB_OPTS='NonStop frame=1'
bar();
# disable debugger from this moment
return;
}
sub bar {
print "Just another Perl hacker\n";
return;
}
package main;
if(!caller) {
MyModulino->import();
foo();
}
现在您可以执行以下操作:
perl -I/some/path/to/script -e 'do "scriptname"; MyModulino::bar()'
换句话说,您现在可以将scriptname
视为具有MyModulino
包的模块,无论它是什么,您都可以直接调用bar()
而不是依靠{{ 1}}来调用它。仅当foo()
返回false时,才发生对foo()
的调用,如果直接运行该程序,则将执行此操作,但是如果将其作为模块调用,则不会进行该操作。
通过将caller()
视为模块,scriptname
调用不会隐式运行,并且调试器代码可以从foo()
包中调用bar()
。
这一行可以让您直接进入调试器,而无需调用MyModulino
。
foo()
您可以将此技术与perl -d -I/path/to/script -e 'do "scriptname"; MyModulino::bar()'
结合使用,以模拟在测试Test::MockModule
时也不关心的调用堆栈部分。但是,当您开始走这条路时,您确实应该花时间在自动化测试脚本中实施这些策略。在这种情况下,“模块化”建议仍然适用。