3

So my goal is to find an easy way to turn on print statements in Perl using a flag. In C/C++ you can use a #define to choose if certain code is run and it is a way to turn on and off debug print statements. If a #define DEBUG is defined, then you print something, else you run it without the print statements. I was wondering if there was an easy way to do this in Perl.

Here is an example of how it would work:

for($i = 0 ; $i < 10; $i++){
    if(debug flag){
         print some info;
    }
    do operational stuff.
}

Now from the command line you could do one of two things:

1.Run without the debug print statements

perlScript.pl 

2.Run with debug print statements

perlScript.pl -debug

Or if someone has a better idea please let me know!

user1334858
  • 1,885
  • 5
  • 30
  • 39
  • 2
    You could also consider using an environment variable: `DEBUG=1 perl perlScript.pl`. Then you could inspect the DEBUG environment variable(`$ENV{DEBUG}`) and react accordingly – Hunter McMillen Jun 23 '15 at 16:18

5 Answers5

3

In perl, compile time is also run time. So there's really not a great deal of advantage in using #define type statements.

My usual trick is:

my $debug = 0; 
$debug += scalar grep ( "-d", @ARGV ); 

(GetOpt is probably honestly a better plan though)

And then use:

print if $debug;
print $statement if $debug > 2;

Which means I've an easy way of setting the verbosity, and also allowing me to be selective about it by incrementing the statements.

Sometimes I'll embed a signal handler to also adjust debugging level -

#!/usr/bin/perl

use strict;
use warnings;

my $debug = 0; 
$debug += scalar grep ( "-d", @ARGV ); 

$SIG{'USR1'} = { $debug++ };
$SIG{'USR2'} = { $debug-- };

while ( 1 ) {
    print "Debugging at: $debug\n";
    sleep 1;
}

It's more a question of what sort of code I'm writing - this latter I particularly like when doing forky stuff, because then I can adjust debug levels in each fork independently and on the fly.

Sobrique
  • 52,974
  • 7
  • 60
  • 101
  • So I used GetOptions for my command options. Is there a way to make `$debug = 1` if they put in the `-debug` flag. Because right now I first set `$debug =0` Then I do the `GetOptions(debug=i =>$debug)`. The issue is if they just do '-debug' then `$debug` is still set to 0.... But I want it set to 1 if they don't include a verbose setting. – user1334858 Jun 23 '15 at 22:51
  • For some reason, `grep ("-d", @ARGV)` doesn't work for me, it just gives me the total number of arguments. In order to count the number of `-d` arguments passed, I have to use `grep(/-d/, @ARGV)`. That is to say use `/` and not `"`.This is assuming that you call the script using `script.pl -d -d filename.txt`, to get a debugging level of two. Or have I misunderstood how the script is called (when using `grep("-d"...`), i.e. how are the arguments used to trigger debugging? – Greenonline Dec 15 '20 at 13:40
2

The -s option allows you to specify the value of main package variables on the command line, although you must be running a perl program from a file rather than using the -e option

If you have a perl program

use strict;
use warnings;

our $debug
print $debug, "\n";

and run it with the command line

perl -s myprog.pl -debug

then the program will print 1

Note that, instead of using -s on the command line, you can specify it on the shebang line in the program file itself, so if your code looks like

#!/usr/bin/perl -s

use strict;
use warnings;

our $debug
print $debug, "\n";

then your command line need only contain

myprog.pl -debug
Borodin
  • 126,100
  • 9
  • 70
  • 144
  • I tried to use the -s... It is not doing what you say. Do I need the `use strict` and the `use warnings`? I am using GetOptions as my way of getting the -debug flag – user1334858 Jun 23 '15 at 23:09
  • @user1334858: The `-debug` has to be *after* the script file name and *before* any parameters to the script. So if you're passing files `f1` and `f2` to your script you would write `perl -d myscript.pl -debug f1 f2`. If it's working properly then `-debug` will be removed from `@ARGV` and `GetOptions` will never see it. You should try it with my program above first to see if you can get it to print the value 1, and then adapt it to your needs. – Borodin Jun 23 '15 at 23:32
  • Learned something new about Perl today. – mob Jun 24 '15 at 02:37
1

Similar to your idea, but more succinct and goes to stderr and assuming you use something like Getopt::Long to set a debug CLI option.

warn "debug info:..." if ( $debug );
Neil H Watson
  • 1,002
  • 1
  • 14
  • 31
1

I usually use the following boilerplate for logging in scripts via Log::Log4perl. You can override the logbase/log configuration locations from the command line (or, more usually, set appropriate locations as default on deploy), and upon giving one or more -verbose flags to the script, override that logging and log to screen, with 4 verboses giving you screen output. This lets you transition easily from debugging by providing verbise flags to get every log output, to passing it to a custom log handler config to debug subsystems, to setting up logging in production deploy, all with minimal/no code changes.

use Getopt::Long;
use Pod::Usage;
use Log::Log4perl qw/:easy/;

my $opts = { logconf        => undef,
             logbase        => 'corp.team.app.appname'
             debug          => 0,
           };

GetOptions ( 'logconf|l=s'       => \$opts->{logconf},
             'logbase=s'         => \$opts->{logbase},
             'verbose|v+'        => \$opts->{debug},  ### debug levels - 0 = off (default), 1 = error, 2 = warn, 3 = info, 4 = debug.
                                                      ### Ignored if a logconf is provided.
           ) or pod2usage(0);

### Initialize logging subsystem
init_logger();

### Usage
logger('app_subsystem')->info('some message...');
logger()->debug('debug message...');


### Initialize logging system
sub init_logger {
    ### If a log configuration is found, and debug was not set, use it
    if (        $opts->{logconf}
         and -e $opts->{logconf}
         and  ! $opts->{debug}
       ) {
        Log::Log4perl->init($opts->{logconf});
    }
    ### Otherwise fall through to easy_init a screen logger based on the verboseness level
    ### Logging off if no config found and no verboseness set
    else {
        my ($min, $max) = ( 0, 4 );
        my %levels;
        @levels{$min .. $max} = ( $OFF, $ERROR, $WARN, $INFO, $DEBUG );
        my $log_level = $opts->{debug};
        if ($log_level < $min) {
            $log_level = $min;
        }
        elsif ($log_level > $max) {
            $log_level = $max;
        }
        Log::Log4perl->easy_init($levels{$log_level});
    }
}

### Shorthand shim sub to get a logger
### Always returns a Log::Log4perl logger object
sub logger {
    my ($category) = @_;
    if ($category) {
        return Log::Log4perl->get_logger($opts->{logbase} . '.' . $category);
    }
    return Log::Log4perl->get_logger($opts->{logbase});
}
Oesor
  • 6,632
  • 2
  • 29
  • 56
-2

Up through v5.10, you can also literally use the C preprocessor on your Perl script with the -P command-line switch, documented in perlrun.

#!perl -P
# myScript.pl
#define DEBUG(x) x
$foo = 42;
DEBUG( print "foo is $foo\n"; )

$ perl -P myScript.pl
foo is 42

(Like the -T switch, #!perl -P doesn't automatically use the C preprocessor with your script, but it does force you to explicitly use the -P switch yourself every time you run the script)

mob
  • 117,087
  • 18
  • 149
  • 283