I mentioned in passing last week that the next major release of Perl, v5.36, is set to enable warnings by default for code that opts in to use v5.35; or above. Commemorating Perl’s 34th birthday the week before that, I noted that the warnings system has been getting ever finer-​grained since its introduction in 2000. And fellow Perl blogger and CPAN author Tom Wyant has been cataloging his favorites over the past several months—the latest as of this writing was on the ambiguous” category of warnings, and you can find links to previous entries in his series at the bottom of that post.

It occurred to me afterward that there may be some confusion between the warnings pragma and the related warn function for reporting arbitrary runtime errors. warn outputs its arguments to the standard error (STDERR) stream, or if it’s not given any then you get a string with any exception from $@ ($EVAL_ERROR under use English) followed by a tab and then “...caught at <file> line x.” If that’s empty too, a plain warn just says, Warning: something's wrong at <file> line x.”, which isn’t exactly helpful, but then again you didn’t give it much to go on.

warn output doesn’t have to go to STDERR, and this is where the relation to the warnings pragma comes in because both are governed by the __WARN__ signal handler in the %SIG hash. Normally, you might opt to only display runtime warnings if a debugging flag is set, like so:

#!/usr/bin/env perl

use strict;
use warnings;

my $DEBUG = 0;
$SIG{__WARN__} = sub { warn @_ if $DEBUG };
warn 'shhh'; # silenced

$DEBUG = 1;
warn 'hello warnings';

But if you set that signal handler in a BEGIN block, it catches compile-​time warnings too, in which case flipping a flag after the fact has no effect—the compiler’s already run:

#!/usr/bin/env perl

use strict;
use warnings;

my $DEBUG = 0;
BEGIN { $SIG{__WARN__} = sub { warn @_ if $DEBUG } }
my $foo = 'hello';
my $foo = 'world'; # no warning issued here

$DEBUG = 1;
my $foo = 'howdy'; # still nothing

By the way, both __WARN__ and __DIE__ hooks are also used by the Carp module and its friends, so you can use the same technique with their enhanced output:

#!/usr/bin/env perl

use strict;
use warnings;
use Carp qw(carp cluck);

my $DEBUG = 0;
BEGIN { $SIG{__WARN__} = sub { warn @_ if $DEBUG } }
carp 'quiet fish';

$DEBUG = 1;
loud_chicken();

sub loud_chicken {
    cluck 'here comes a stack trace';
}

You could use these as stepping stones towards a debug log for larger applications, but at that point, I’d suggest looking into one of the logging modules on CPAN like Log::Log4perl (not to be confused with that lately-​problematic Java library), Log::Dispatch (which can be wired into Log4perl), or something else to suit your needs.

man cutting tress using chainsaw

The Java world had an… interesting weekend when security researchers revealed on December 9 a vulnerability in the popular Apache Log4j 2 software library for recording and debugging events. Systems as diverse as Amazon Web Services, Apple iCloud, and the Minecraft video game could be exploited to run arbitrary code on a server merely by sending a specially-​crafted string of text. Information technology professionals have been scrambling ever since the initial disclosure to patch, upgrade, reconfigure, or otherwise protect affected servers. It’s bad, and past unpatched vulnerabilities like this have been responsible for the exposure of millions of people’s sensitive data.

Many Perl applications use the similarly-​named and ‑designed Log::Log4perl library, and the good news is that as far as I can tell the latter doesn’t suffer from the type of vulnerability described above. This doesn’t mean poorly-​written or ‑configured Perl-​based systems are immune to all exploits, just this particular one. You should be safe to continue using Log4perl unless someone has deliberately configured it otherwise, and in fact, my work uses it extensively.

You might be surprised to read me suggesting a logging framework after writing multiple articles espousing the Perl step debugger as an alternative. Log4perl developer Mike Schilli’s 2002 introduction to the package for Perl.com came down on the opposite side of the argument. It can seem like one of those programmer religious issues like tabs vs. spaces, vim vs. Emacs, or Linux vs. Windows. (For the record, the correct answers are spaces, BBEdit, and macOS. 😉)

But in this case, you can and should have the best of both worlds—logging at different levels to appropriate destinations while still dropping into the interactive debugger when you need to do something trickier like examine program state or tweak a data structure on the fly. I use both techniques and only emphasize the advocacy of step debugging because it’s understood less.