Tag: Log::Dispatch

  • Perl warnings and the warn function

    Perl warnings and the warn function

    I men­tioned in pass­ing 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 birth­day the week before that, I not­ed that the warn­ings sys­tem has been get­ting ever finer-​grained since its intro­duc­tion in 2000. And fel­low Perl blog­ger and CPAN author Tom Wyant has been cat­a­loging his favorites over the past sev­er­al months—the lat­est as of this writ­ing was on the ​“ambigu­ous” cat­e­go­ry of warn­ings, and you can find links to pre­vi­ous entries in his series at the bot­tom of that post.

    It occurred to me after­ward that there may be some con­fu­sion between the warnings prag­ma and the relat­ed warn func­tion for report­ing arbi­trary run­time errors. warn out­puts its argu­ments to the stan­dard error (STDERR) stream, or if it’s not giv­en any then you get a string with any excep­tion from $@ ($EVAL_ERROR under use English) fol­lowed by a tab and then “...caught at <file> line x.” If that’s emp­ty too, a plain warn just says, ​“Warning: something's wrong at <file> line x.”, which isn’t exact­ly help­ful, but then again you didn’t give it much to go on.

    warn out­put doesn’t have to go to STDERR, and this is where the rela­tion to the warn­ings prag­ma comes in because both are gov­erned by the __WARN__ sig­nal han­dler in the %SIG hash. Normally, you might opt to only dis­play run­time warn­ings if a debug­ging 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 sig­nal han­dler in a BEGIN block, it catch­es compile-​time warn­ings too, in which case flip­ping 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 mod­ule and its friends, so you can use the same tech­nique 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 step­ping stones towards a debug log for larg­er appli­ca­tions, but at that point, I’d sug­gest look­ing into one of the log­ging mod­ules on CPAN like Log::Log4perl (not to be con­fused with that lately-​problematic Java library), Log::Dispatch (which can be wired into Log4perl), or some­thing else to suit your needs.