Viewing File: /usr/local/cpanel/3rdparty/perl/536/cpanel-lib/x86_64-linux/B/C/Debug.pm
package B::C::Debug;
use strict;
use Exporter ();
our @ISA = qw(Exporter);
our @EXPORT_OK = qw/debug verbose WARN INFO FATAL/;
my %debug_map = (
'A' => 'av',
'c' => 'cops',
'C' => 'cv',
'f' => 'file',
'G' => 'gv',
'g' => 'signals',
'H' => 'hv',
'M' => 'mg',
'O' => 'op',
'p' => 'pkg',
'P' => 'pv',
'R' => 'rx',
's' => 'sub',
'S' => 'sv',
'u' => 'unused',
'd' => 'debug', # special case for debug without any level
'v' => 'verbose', # special case to consider verbose as a debug level
'W' => 'walk',
'bench' => 'benchmark',
'stack' => 'stack',
'h' => 'hooks',
'hook' => 'hooks',
);
my %reverse_map = reverse %debug_map;
# list all possible level of debugging
my %debug;
sub init {
%debug = map { $_ => 0 } sort values %debug_map, sort keys %debug_map;
%debug = (
%debug,
flags => 0,
runtime => 0,
);
binmode( STDERR, ":utf8" ); # Binmode of STDOUT and STDERR are not preserved for the perl compiler
return;
}
init(); # initialize
my %saved;
sub save {
my %copy = %debug;
return \%copy;
}
sub restore {
my $cfg = shift;
die unless ref $cfg;
%debug = %$cfg;
return;
}
# you can then enable them
# $debug{sv} = 1;
sub enable_debug_level {
my $l = shift or die;
if ( defined $debug_map{$l} ) {
INFO("Enabling debug level: '$debug_map{$l}'");
_enable_debug_level( $debug_map{$l} );
_enable_debug_level($l);
return 1;
}
if ( defined $reverse_map{$l} ) {
INFO("Enabling debug level: '$l'");
_enable_debug_level($l);
_enable_debug_level( $reverse_map{$l} );
return 1;
}
# allow custom debug levels
_enable_debug_level($l);
# tricky, but do not enable aliases if the level we are using use an unknown character
# allow to use custom debug levels without enabling all others
my @letters = split( //, $l );
return 1 if grep { !exists $debug_map{$_} } @letters;
return;
}
sub _enable_debug_level {
my $level = shift or die;
$debug{$level}++;
return;
}
sub enable_all {
enable_verbose() unless verbose();
foreach my $level ( sort keys %debug ) {
next if $debug{$level};
next if $level =~ qr{^bench};
enable_debug_level($level);
}
return;
}
sub enable_verbose {
enable_debug_level('verbose');
}
sub enable_global_debug {
enable_debug_level('debug');
}
sub verbose {
return $debug{'v'} unless $debug{'v'};
return $debug{'v'} unless scalar @_;
display_message( '[verbose]', @_ );
return $debug{'v'};
}
# can be improved
sub WARN { return verbose() && display_message( "[WARNING]", @_ ) }
sub INFO { return verbose() && display_message( "[INFO]", @_ ) }
sub FATAL { die display_message( "[FATAL]", @_ ) }
my $logfh;
sub display_message {
my (@msg) = @_;
return unless scalar @msg;
my $txt = join( " ", map { defined $_ ? $_ : 'undef' } @msg );
# just safety to avoid double \n and trailing spaces
$txt =~ s{\s+$}{}s;
$txt .= "\n";
print STDERR $txt;
if ( $ENV{BC_DEVELOPING} ) {
$logfh or open( $logfh, '>', 'fullog.txt' );
print {$logfh} $txt;
}
return;
}
=pod
=item debug( $level, @msg )
always return the current status for the level
when call with one single arg print the string
more than one, use sprintf
=cut
sub debug {
my ( $level, @msg ) = @_;
my @levels = ref $level eq 'ARRAY' ? @$level : $level;
if ( !scalar @levels || grep { !defined $debug{$_} } @levels ) {
# this is a call to debug without a level, display it when -d is enabled
unshift @msg, $level;
@levels = 'debug'; # regular debug
}
my $debug_on = grep { $debug{$_} } @levels;
if ( $debug_on && scalar @msg ) {
@msg = map { defined $_ ? $_ : 'undef' } @msg;
my $header = '[level=' . join( ',', sort @levels ) . '] ';
my $cnt = @msg;
my $warn;
if ( $cnt == 1 ) {
$warn = $msg[0];
}
else {
my $str = shift @msg;
eval {
if ( $str =~ qr{%} ) { # use sprintf style when % is used
$warn = sprintf( $str, @msg );
}
else { # use a regular join when % is not used
$warn = join( ' ', map { $_ // '' } $str, @msg );
}
1;
} or do {
my $error = $@;
# track the error source when possible
eval q/require Carp; 1/ or die $error;
Carp::croak( "Error: $error", $header, "STR:'$str' ; ", join( ', ', @msg ) );
};
}
$warn = '' unless defined $warn;
display_message("$header$warn");
}
return $debug_on;
}
# maint entry points
sub setup_debug {
my ( $levels_str, $verbose, $debug ) = @_;
enable_verbose() if $verbose || $debug;
enable_global_debug() if $debug;
return unless defined $levels_str && length $levels_str;
my @levels = split( /\./, $levels_str );
my $use_a_valid_level;
foreach my $level (@levels) {
if ( enable_debug_level($level) ) {
WARN("Enable debug mode: $level");
$use_a_valid_level = 1;
next;
}
foreach my $level ( split( //, $level ) ) {
next if enable_debug_level($level);
if ( $level eq "o" ) {
enabe_verbose();
B->debug(1);
}
elsif ( $level eq "F" ) {
enable_debug_level('flags');
$B::C::all_bc_deps{'B::Flags'}++;
}
elsif ( $level eq "r" ) {
enable_debug_level('runtime');
$SIG{__WARN__} = sub {
WARN(@_);
my $s = join( " ", @_ );
chomp $s;
B::C::File::init()->add( "/* " . $s . " */" ) if init();
};
}
else {
WARN("ignoring unknown debug option: $level");
}
}
}
return $use_a_valid_level;
}
1;
Back to Directory
File Manager