Stacktrace付きdie
ログをもう少し詳しくしたいなぁと思って調べていて、Error.pmのソースで気がついたんけど、
eval { die Foo->new; } warn ref $@; #Foo
が使えるんですね。
Sledge::Plugin::DebugScreenとか、CGI::Applicationだと$self->{__stacktrace}で情報を保存しているけど、$@を利用してstacktrace情報を受け渡すことができるよな、と考えたので書いてみた
package MyApp::Exception; use strict; use warnings; use base qw/Class::Accessor::Fast Exporter/; use Devel::StackTrace; use overload '""' => 'as_string'; __PACKAGE__->mk_accessors(qw/frames message debug/); our @EXPORT_OK = qw/throw/; our $IGNOREPKG = []; sub throw { my $exception = __PACKAGE__->new(@_); die $exception; } sub new { my $class = shift; my $message = join '', @_; $message =~ s/[\n\r]*$//gi; my $self = bless { frames => [], message => $message, }, $class; my $stack = Devel::StackTrace->new( ignore_package => $IGNOREPKG, no_refs => 1, respect_overload => 1, ); $self->frames([$stack->frames]); $self; } sub as_string { my $self = shift; unless ( grep { $_->package eq 'MyApp::Framework' } @{$self->frames} ) {#frameworkとの連携 return $self->stacktrace; } my $caller = $self->frames->[0]; sprintf("%s at %s line %s\n", $self->message, $caller->filename, $caller->line); } sub stacktrace { my $self = shift; my @trace; foreach my $frame ( @{$self->frames} ) { push @trace, sprintf( "%s line %s", $frame->filename, $frame->line ); } sprintf( "%s at %s\n", $self->message, join( ", ", @trace ) ); } 1;
基本、dieの代わりにthrowを使うようにする。そうすっとSTDERRにstacktrace付きのメッセージがでる。
#!/usr/bin/perl use MyApp::Exception qw/throw/; DBI->connect(...) or throw 'connection failed';#stacktraceが付く
フレームワークを離礁しているところでは、フレームワークで、
package MyApp::Framework; sub run { .... eval { local $SIG{__DIE__} = MyApp::Exeption->can('throw'); $self->prepare; $self->execute; $self->finilize; }; if ( $@ && ref $@ && $self->debug) { $@->framesをtemplateに渡してdebugscreenなど } else { die $@; } }
と書いてあるので、普通にdieした時もtraceするし、throwを使っていてもいい具合に出力を調整することができる。
ただ、車輪の再発明をした気がすごくするなぁ。。
コメント
スタックトレース表示したいだけなら、Carp::confess でもできます。
use Carp;
$SIG{__DIE__} = \&Carp::confess;
とかよくやります。
投稿者: tokuhirom | 2006年09月19日 10:37
一部のエラーが恒常的にでるので、Apacheのerror_logに出すのに、confessよりは情報をしぼりたいのと、DebugScreenが目的なのです。
投稿者: かぜぶろ | 2006年09月19日 15:49