File Coverage

blib/lib/Carp/Patch/OutputToBrowser.pm
Criterion Covered Total %
statement 23 24 95.8
branch n/a
condition n/a
subroutine 8 9 88.8
pod 0 1 0.0
total 31 34 91.1


line stmt bran cond sub pod time code
1             ## no critic: TestingAndDebugging::RequireUseStrict
2             package Carp::Patch::OutputToBrowser;
3              
4 1     1   389934 use 5.010001;
  1         22  
5             #use strict 'vars';
6 1     1   5 no warnings;
  1         3  
  1         76  
7              
8 1     1   588 use Browser::Open qw(open_browser);
  1         2507  
  1         75  
9 1     1   637 use Data::Dump::HTML::Collapsible qw(dump);
  1         11521  
  1         77  
10 1     1   1016 use File::Temp qw(tempfile);
  1         22240  
  1         120  
11 1     1   10 use HTML::Entities qw(encode_entities);
  1         2  
  1         68  
12 1     1   642 use Module::Patch;
  1         28702  
  1         9  
13 1     1   64 use base qw(Module::Patch);
  1         2  
  1         834  
14              
15             our $AUTHORITY = 'cpan:PERLANCAR'; # AUTHORITY
16             our $DATE = '2024-03-12'; # DATE
17             our $DIST = 'Carp-Patch-OutputToBrowser'; # DIST
18             our $VERSION = '0.001'; # VERSION
19              
20             our %config;
21              
22             my $p_ret_backtrace = sub {
23             my ( $i, @error ) = @_;
24             my $mess;
25             my $err = join '', @error;
26             $i++;
27              
28             my $tid_msg = '';
29             if ( defined &threads::tid ) {
30             my $tid = threads->tid;
31             $tid_msg = " thread $tid" if $tid;
32             }
33              
34             my %i = Carp::caller_info($i);
35             $mess = "

".encode_entities("$i. $err at $i{file} line $i{line}$tid_msg");

36             if( $. ) {
37             # Use ${^LAST_FH} if available.
38             if (LAST_FH) {
39             if (${+LAST_FH}) {
40             $mess .= sprintf ", <%s> %s %d",
41             *${+LAST_FH}{NAME},
42             ($/ eq "\n" ? "line" : "chunk"), $.
43             }
44             }
45             else {
46             local $@ = '';
47             local $SIG{__DIE__};
48             eval {
49             CORE::die;
50             };
51             if($@ =~ /^Died at .*(, <.*?> (?:line|chunk) \d+).$/ ) {
52             $mess .= $1;
53             }
54             }
55             }
56             $mess .= "\.\n";
57              
58             while ( my %i = Carp::caller_info( ++$i ) ) {
59             $mess .= "\t$i{sub_name} called at $i{file} line $i{line}$tid_msg
\n";
60             }
61              
62             my ($temp_fh, $temp_filename) = tempfile("stacktrace-XXXXXXXX", SUFFIX=>".html", TMPDIR=>1) or die;
63             print $temp_fh $mess;
64             close $temp_fh;
65             open_browser($temp_filename);
66              
67             return "Backtrace is output to $temp_filename and opened in browser\n";
68             };
69              
70             sub patch_data {
71             return {
72 0     0 0   v => 3,
73             config => {
74             },
75             patches => [
76             {
77             action => 'replace',
78             sub_name => 'ret_backtrace',
79             code => $p_ret_backtrace,
80             },
81             ],
82             };
83             }
84              
85             1;
86             # ABSTRACT: Output stacktrace to browser as HTML instead of returning it
87              
88             __END__