File Coverage

blib/lib/Devel/Scope.pm
Criterion Covered Total %
statement 74 81 91.3
branch 12 16 75.0
condition 4 9 44.4
subroutine 13 13 100.0
pod 1 6 16.6
total 104 125 83.2


line stmt bran cond sub pod time code
1             package Devel::Scope;
2              
3 3     3   130057 use 5.006;
  3         16  
4 3     3   13 use strict;
  3         5  
  3         60  
5 3     3   12 use warnings;
  3         4  
  3         76  
6              
7 3     3   12 use List::Util qw( min );
  3         5  
  3         222  
8 3     3   880 use Scope::Upper qw( SCOPE );
  3         1501  
  3         123  
9 3     3   819 use Term::Colormap qw( colormap print_colored_text colored_text);
  3         3608  
  3         177  
10 3     3   443 use Time::HiRes qw( tv_interval gettimeofday );
  3         1090  
  3         13  
11              
12             require Exporter;
13             our @ISA = qw( Exporter );
14             our @EXPORT_OK = qw( debug debug_enable debug_disable );
15              
16             our $VERSION = '0.12';
17              
18             my %default_config = (
19             'DEVEL_SCOPE_DEPTH' => 0,
20             'DEVEL_SCOPE_MIN_DECIMAL_PLACES' => 10,
21             'DEVEL_SCOPE_TIME_FORMAT' => '%06f',
22             'DEVEL_SCOPE_TIME_LOG_BASE' => 5,
23             'DEVEL_SCOPE_TIME_LOG_OFFSET' => 4,
24             );
25              
26             my %config = validate_env_vars();
27              
28             my $time_format = $config{'DEVEL_SCOPE_TIME_FORMAT'};
29             my $format_total_and_elapsed = "[ $time_format : $time_format ]";
30              
31             my $debug_min_elapsed = 10 ** (-1 * $config{'DEVEL_SCOPE_MIN_DECIMAL_PLACES'} );
32             my $log_base = log( $config{ 'DEVEL_SCOPE_TIME_LOG_BASE' } );
33              
34             # blue cyan green yellow orange red
35             my $colormap = [ 201, 51, 46, 226, 202, 196 ];
36              
37             my $start_time = [ gettimeofday ];
38             my $tic = $start_time;
39             my $last_file = '';
40              
41             debug("Using " . __PACKAGE__ . ' with ');
42             for my $key (sort keys %config) {
43             debug(" " . $key . '=' . $config{$key});
44             }
45             debug("[ total seconds, seconds since last debug call ]");
46             debug('D-2 means Depth = 2 ( relative to the file or subroutine )');
47             debug('L-4 means Line number 4');
48             debug('Stars indicate time spent between debug calls:');
49             for my $time_level (1..5) {
50             my $sec = seconds_for_time_level($time_level);
51             my $color_index = min($time_level, $#$colormap);
52             my $stars = colored_text($colormap->[$color_index],
53             "(" . ('*'x$time_level) . ")");
54             debug("$stars : > $sec seconds");
55             }
56             debug("-"x40);
57              
58             sub debug {
59 40 100   40 1 1024244 return if not defined $ENV{'DEVEL_SCOPE_DEPTH'};
60 5         13 $config{'DEVEL_SCOPE_DEPTH'} = $ENV{'DEVEL_SCOPE_DEPTH'};
61 5         21 my $toc = [ gettimeofday ];
62              
63 5         26 my ($message) = join(' ', @_);
64 5         19 my $depth = SCOPE(1);
65              
66 5         19 my ($pack0, $file0, $line0) = caller(); # If in main
67 5 50 33     19 return if ($depth > $config{'DEVEL_SCOPE_DEPTH'}) and ($pack0 ne __PACKAGE__);
68              
69 5         27 my ($package, $filename, $line, $subroutine) = caller(1);
70 5 100       17 if (defined $subroutine) {
71 3 100 66     26 if ($subroutine eq 'main::' or $subroutine eq '(eval)') {
72 2         12 $subroutine = '';
73             } else {
74 1         2 $subroutine .= "()";
75             }
76 3         11 $subroutine =~ s|^main::||;
77             } else {
78 2         3 $line = $line0;
79 2         3 $subroutine = '';
80 2         2 $filename = $file0;
81             }
82              
83 5         24 my $elapsed = tv_interval( $tic, $toc );
84 5 50       66 return unless $elapsed >= $debug_min_elapsed;
85              
86 5         13 my $total_elapsed = tv_interval( $start_time, $toc );
87 5         80 my $time_output = sprintf($format_total_and_elapsed,
88             $total_elapsed, $elapsed);
89              
90             # Time level capped at the number of colors in our colormap
91 5         21 my $time_level = int( $config{'DEVEL_SCOPE_TIME_LOG_OFFSET'}
92             + ( log($elapsed) / $log_base ));
93              
94 5 100       12 if ($filename eq $last_file) {
95 4         5 $filename = '';
96             } else {
97 1         5 output("DEVEL_SCOPE Entering $filename \n");
98 1         3 $last_file = $filename;
99             }
100              
101 5         28 output("$time_output D-$depth L-$line $subroutine : ");
102 5 100       17 if ($time_level > 0) {
103             # Highligh longer running steps with stars (* = fastish, ***** = slow )
104 3         20 my $color_index = min($time_level, $#$colormap);
105 3         26 print_colored_text($colormap->[$color_index],
106             "(" . ('*'x$time_level) . ")");
107 3         104 print " : ";
108             }
109 5         19 output("$message\n");
110 5         27 $tic = [ gettimeofday ];
111             }
112              
113             sub seconds_for_time_level {
114 10     10 0 13 my ($level) = @_;
115 10         10 my $offset = $config{'DEVEL_SCOPE_TIME_LOG_OFFSET'};
116 10         28 return exp( ($level - $offset) * $log_base );
117             }
118              
119             sub output {
120 11     11 0 18 my ($msg) = @_;
121              
122             {
123 11         13 local $| = 1;
  11         39  
124 11         159 print $msg;
125             }
126             }
127              
128             sub debug_disable {
129 1     1 0 455 my $previous_value = $ENV{'DEVEL_SCOPE_DEPTH'};
130 1         5 delete $ENV{'DEVEL_SCOPE_DEPTH'};
131 1         2 delete $config{'DEVEL_SCOPE_DEPTH'};
132 1         1 return $previous_value;
133             }
134              
135             sub debug_enable {
136 1     1 0 221 my ($depth) = @_;
137 1   33     3 $depth ||= $default_config{'DEVEL_SCOPE_DEPTH'};
138              
139 1         6 $ENV{'DEVEL_SCOPE_DEPTH'} = $depth;
140 1         3 $config{'DEVEL_SCOPE_DEPTH'} = $depth;
141              
142 1         2 return $depth;
143             }
144              
145             sub validate_env_vars {
146 2     2 0 18 my $env_prefix = 'DEVEL_SCOPE_';
147 2         15 my @env_vars_maybe = grep { m|^$env_prefix| } keys %ENV;
  67         124  
148              
149 2         10 my %config = %default_config;
150 2         6 for my $env_var (@env_vars_maybe) {
151 0 0       0 if ( not defined $config{$env_var} ) {
152 0         0 print "Invalid " . __PACKAGE__ . " env variable '$env_var'\n";
153 0         0 print "Possible variable names: [name=default]\n";
154 0         0 for my $key ( sort keys %config ) {
155 0         0 print " " . $key . '=' . $config{$key} . "\n";
156             }
157 0         0 die "\n";
158             } else {
159 0         0 $config{ $env_var } = $ENV{ $env_var };
160             }
161             }
162              
163 2         8 return %config;
164             }
165              
166             1; # End of Devel::Scope
167              
168             __END__