« 開発環境のこととか | メイン | qw// -> qw() »

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を使っていてもいい具合に出力を調整することができる。

ただ、車輪の再発明をした気がすごくするなぁ。。

トラックバック

この一覧は、次のエントリーを参照しています: Stacktrace付きdie:

» Bitacle Blog Search Archive - Stacktrace付きdie : blog.nomadscafe.jp from bitacle.org
[...] ログをもう少し詳しくしたいなぁと思って調べていて、Error. [...] [詳しくはこちら]

コメント

スタックトレース表示したいだけなら、Carp::confess でもできます。

use Carp;
$SIG{__DIE__} = \&Carp::confess;
とかよくやります。

一部のエラーが恒常的にでるので、Apacheのerror_logに出すのに、confessよりは情報をしぼりたいのと、DebugScreenが目的なのです。

コメントを投稿