File Coverage

blib/lib/App/CLI/Plugin/StackTrace.pm
Criterion Covered Total %
statement 12 48 25.0
branch 0 16 0.0
condition 0 21 0.0
subroutine 4 7 57.1
pod 0 1 0.0
total 16 93 17.2


line stmt bran cond sub pod time code
1             package App::CLI::Plugin::StackTrace;
2              
3 1     1   6 use strict;
  1         2  
  1         41  
4 1     1   5 use warnings;
  1         2  
  1         34  
5 1     1   1055 use Devel::StackTrace;
  1         8016  
  1         36  
6 1     1   11 use Fcntl qw(:DEFAULT :flock);
  1         3  
  1         1534  
7              
8             our $CONTEXT_LINE = 5;
9             our @IGNORE_PACKAGE = ( __PACKAGE__, "Carp", "Error::subs" );
10             our $VERSION = '1.1';
11              
12             sub setup {
13              
14 0     0 0   my($self, @argv) = @_;
15              
16 0 0         my $stacktrace = (exists $self->config->{stacktrace}) ? $self->config->{stacktrace} : 0;
17              
18 0 0 0       if ( (defined $stacktrace && $stacktrace != 0) ||
      0        
      0        
      0        
      0        
      0        
19             (exists $ENV{APPCLI_STACKTRACE_ENABLE} && $ENV{APPCLI_STACKTRACE_ENABLE} != 0) ||
20             (exists $self->{stacktrace} && defined $self->{stacktrace} && $self->{stacktrace} != 0)
21             ) {
22 0           $self->_build_override_die_subroutine;
23             }
24              
25 0           $self->maybe::next::method(@argv);
26             }
27              
28             sub _build_override_die_subroutine {
29              
30 0     0     my $self = shift;
31              
32             $SIG{__DIE__} = sub {
33              
34 0     0     my $message = shift;
35 0           my @frames;
36 0           my $pkg = ref $self;
37 0           my $trace = Devel::StackTrace->new( ignore_package => \@IGNORE_PACKAGE );
38 0           my $stacktrace_message = <
39             $pkg
40              
41             $message
42              
43             ----------
44             STACKTRACE_MESSAGE
45              
46 0           chomp $message;
47              
48             LOOP_OF_FRAMES:
49 0           while ( my $frame = $trace->next_frame ) {
50              
51 0           my $start_line = $frame->line - $CONTEXT_LINE;
52 0           my $end_line = $frame->line + $CONTEXT_LINE;
53 0 0         if ($start_line < 1) {
54 0           $start_line = 1;
55             }
56              
57 0           my @lines;
58 0 0         open my $fh, "<", $frame->filename or die sprintf("can not open %s. %s", $frame->filename, $!);
59 0 0         flock $fh, LOCK_EX or die sprintf("can not flock %s. %s", $frame->filename, $!);
60 0           while ( my $line = <$fh> ) {
61              
62 0           chomp $line;
63 0           my $current_line = $.;
64 0 0 0       if ($current_line < $start_line || $current_line > $end_line) {
65 0           next;
66             }
67 0 0         my $mark = ($current_line == $frame->line) ? "*" : " ";
68 0           push @lines, sprintf(" %s %05d: %s", $mark, $current_line, $line);
69             }
70 0 0         close $fh or die sprintf("can not close %s. %s", $frame->filename, $!);
71              
72 0           my $package = $frame->package;
73 0           my $filename = $frame->filename;
74 0           my $line = $frame->line;
75 0           my $lines = join "\n", @lines;
76 0           $stacktrace_message .= <
77             $package at $filename line $line.
78              
79             $lines
80              
81             ==========
82             STACKTRACE_MESSAGE
83              
84             } # end of LOOP_OF_FRAMES
85              
86 0           $stacktrace_message .= <
87             ----------
88              
89             STACKTRACE_MESSAGE
90              
91             # rethrow
92 0           die $stacktrace_message;
93 0           };
94              
95             }
96              
97             1;
98              
99             __END__