1 package Catalyst::Plugin::StackTrace;
6 use base qw/Class::Accessor::Fast/;
9 use Scalar::Util qw/blessed/;
12 our $VERSION = '0.11';
14 __PACKAGE__->mk_accessors('_stacktrace');
20 my $conf = $c->config->{stacktrace};
22 return $c->next::method(@_)
23 unless defined $conf->{enable} && $conf->{enable}
24 || !defined $conf->{enable} && $c->debug;
26 local $SIG{__DIE__} = sub {
29 # ignore if the error is a Tree::Simple object
30 # because FindByUID uses an internal die several times per request
31 return if ( blessed($error) && $error->isa('Tree::Simple') );
33 my $ignore_package = [ 'Catalyst::Plugin::StackTrace' ];
34 my $ignore_class = [];
36 if ( $c->config->{stacktrace}->{verbose} < 2 ) {
43 Catalyst::Plugin::StackTrace
44 Catalyst::Plugin::Static::Simple
57 # Devel::StackTrace dies sometimes, and dying in $SIG{__DIE__} does bad
63 $trace = Devel::StackTrace->new(
64 ignore_package => $ignore_package,
65 ignore_class => $ignore_class,
69 die $error unless defined $trace;
71 my @frames = $c->config->{stacktrace}->{reverse} ?
72 reverse $trace->frames : $trace->frames;
75 for my $frame ( @frames ) {
76 # only display frames from the user's app unless verbose
77 if ( !$c->config->{stacktrace}->{verbose} ) {
80 next unless $frame->package =~ /^$app/;
83 push @{$keep_frames}, {
84 pkg => $frame->package,
85 file => $frame->filename,
89 $c->_stacktrace( $keep_frames );
94 return $c->next::method(@_);
100 $c->next::method(@_);
103 return unless ref $c->_stacktrace eq 'ARRAY';
105 # insert the stack trace into the error screen above the "infos" div
107 <style type="text/css">
109 background-color: #eee;
110 border: 1px solid #575;
112 div#stacktrace table {
115 div#stacktrace th, td {
116 padding-right: 1.5em;
119 div#stacktrace .line {
124 <div class="trace error">
125 <h2><a href="#" onclick="toggleDump('stacktrace'); return false">Stack Trace</a></h2>
126 <div id="stacktrace">
134 for my $frame ( @{$c->_stacktrace} ) {
136 # clean up the common filename of
137 # .../MyApp/script/../lib/...
138 if ( $frame->{file} =~ /../ ) {
139 $frame->{file} =~ s{script/../}{};
142 my $pkg = encode_entities $frame->{pkg};
143 my $line = encode_entities $frame->{line};
144 my $file = encode_entities $frame->{file};
145 my $code_preview = _print_context(
148 $c->config->{stacktrace}->{context}
158 <td colspan="3"><pre><p><code class="error">$code_preview</code></p></pre></td>
168 $c->res->{body} =~ s{<div class="infos">}{$html<div class="infos">};
175 $c->next::method(@_);
177 $c->config->{stacktrace}->{context} ||= 3;
178 $c->config->{stacktrace}->{verbose} ||= 0;
182 my ( $file, $linenum, $context ) = @_;
186 my $start = $linenum - $context;
187 my $end = $linenum + $context;
188 $start = $start < 1 ? 1 : $start;
189 if ( my $fh = IO::File->new( $file, 'r' ) ) {
191 while ( my $line = <$fh> ) {
193 last if $cur_line > $end;
194 next if $cur_line < $start;
195 my @tag = $cur_line == $linenum ? ('<strong class="line">', '</strong>') : (q{}, q{});
200 $line ? encode_entities $line : q{},
216 Catalyst::Plugin::StackTrace - Display a stack trace on the debug screen
220 use Catalyst qw/-Debug StackTrace/;
224 This plugin will enhance the standard Catalyst debug screen by including
225 a stack trace of your appliation up to the point where the error occurred.
226 Each stack frame is displayed along with the package name, line number, file
227 name, and code context surrounding the line number.
229 This plugin is only active in -Debug mode by default, but can be enabled by
230 setting the C<enable> config option.
234 Configuration is optional and is specified in MyApp->config->{stacktrace}.
238 Allows you forcibly enable or disalbe this plugin, ignoring the current
239 debug setting. If this option is defined, its value will be used.
243 The number of context lines of code to display on either side of the stack
244 frame line. Defaults to 3.
248 By default, the stack frames are shown in from "top" to "bottom"
249 (newest to oldest). Enabling this option reverses the stack frames so they will
250 be displayed "bottom" to "top", or from the callers perspective.
254 This option sets the amount of stack frames you want to see in the stack
255 trace. It defaults to 0, meaning only frames from your application's
256 namespace are shown. You can use levels 1 and 2 for deeper debugging.
258 If set to 1, the stack trace will include frames from packages outside of
259 your application's namespace, but not from most of the Catalyst internals.
260 Packages ignored at this level include:
267 Catalyst::Plugin::StackTrace
268 Catalyst::Plugin::Static::Simple
272 If set to 2, the stack trace will include frames from everything except this
275 =head1 INTERNAL METHODS
277 The following methods are extended by this plugin.
283 In execute, we create a local die handler to generate the stack trace.
287 In finalize_error, we inject the stack trace HTML into the debug screen below
300 Andy Grundman, <andy@hybridized.org>
302 Matt S. Trout, <mst@shadowcatsystems.co.uk>
306 The authors of L<CGI::Application::Plugin::DebugScreen>, from which a lot of
311 Copyright (c) 2005 - 2009
312 the Catalyst::Plugin::StackTrace L</AUTHORS>
317 This program is free software, you can redistribute it and/or modify it
318 under the same terms as Perl itself.