コールトレースを追うデバッグ用モジュール
Perl スクリプトをトレースするには Perl デバッガを使ってもいいですが,全体的な実行フローを追いたい場合 Devel::Trace が使えます。
たとえば
#!/usr/bin/perl use strict; use warnings; my $i = 0; sub foo { bar(); baz(); } sub bar { baz(); } sub baz { $i ++; } foo();
みたいなスクリプトがあるときに,Devel::Trace でトレースするには下記のようにスクリプトを実行します。
$ perl -d:Trace test.pl
実行結果は,
>> test.pl:6: my $i = 0; >> test.pl:21: foo(); >> test.pl:9: bar(); >> test.pl:14: baz(); >> test.pl:18: $i ++; >> test.pl:10: baz(); >> test.pl:18: $i ++;
のようになります。
んが,これは実行している行がだぁーっと出るのでみにくい。
Devel::Trace のソースを読んだら,こんな簡単なしくみなのかとびっくりしたので,コールスタックの深さがわかるようなデバッグ用モジュールを書いてみました。
package Devel::Tracer; use strict; use warnings; my $fh; sub DB::DB { my ($p, $f, $l, $s) = caller(0); return if $p eq __PACKAGE__; # caller(1)[3] is more suitable than caller(0)[3] ('DB::DB') (undef, undef, undef, $s) = caller(1); $s = q{} if ! defined $s; $s =~ s{ \A $p :: }{}xms; my $level = 0; while (defined (caller($level + 1))) { $level ++; } # my $source = do { no strict 'refs'; \@{"::_<$f"} }; # my $c = $source->[$l]; # chomp $c; # $c =~ s{"}{\\"}gxmso; print {$fh} ">" x ($level + 1) . " $p($l): $s\n"; } sub import { my $package = shift; if (@_) { my $file = shift; open $fh, '>', $file or die $!; } else { $fh = \*STDERR; } } END { close $fh; } 1;
$ perl -d:Tracer test.pl
このように実行すると,
> main(6): > main(21): >> main(9): foo >>> main(14): bar >>>> main(18): baz >> main(10): foo >>> main(18): baz
のように左側の >
の数が深さをあらわします。
オプションを
$ perl -d:Tracer=trace.out test.pl
のように指定すると,STDERR
の代わりに指定したファイルに出力します。
まぁこのモジュール使わなくても,同じようなモジュールが Devel::Trace*
な名前空間にいくつかあるのですが,Perl の -d
スイッチに対応しているのが Devel::Trace と Devel::TraceCalls くらいなので,難しいしくみでもないですし,自分で書いてみるのもいいんではないでしょうか。HTML で吐くようにするとかね。