http://www.perlmonks.org?node_id=1058283

kp2a has asked for the wisdom of the Perl Monks concerning the following question:

I am working on a large data set (and large debug log).

I get occasional non-fatal error messages via STDERR such as "Use of uninitialized value in concatenation . . ."

Is there a way to trap such an error so I can find the specific event that evoked the error?

The needle in the haystack!

Replies are listed 'Best First'.
Re: trap run time errors
by BrowserUk (Patriarch) on Oct 15, 2013 at 10:47 UTC

    The usual form of that message is something like: Use of uninitialized value in say at line 1, <STDIN> line 4.

    Which says (in this case) that the uninitialised value occurred in a say statement at line 1 of the source file whilst processing line 4 of input from standard in.

    The full error message should tell you what lines of your source and data files caused the error. What more information do you need?


    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
Re: trap run time errors
by hdb (Monsignor) on Oct 15, 2013 at 10:54 UTC

    Typically, you would also know the line number where the error occurs. "Use of uninitialized value in concatenation . . ." would mean that one of the variables in that line is uninitialized. So why not just adding a print statement like

    print STDERR "|\$var1=$var1|\$var2=$var2|\n" unless defined $var1 and +defined $var2;
Re: trap run time errors
by kcott (Archbishop) on Oct 15, 2013 at 16:18 UTC

    G'day kp2a,

    You may find one or more of these to be useful (some you may already know about):

    • The 'refs' stricture of the strict pragma. (The other strictures generate compile-time errors.)
    • Promote warnings to fatal errors.
    • Use eval to trap errors.
    • Use Carp routines to produce more verbose warning and error messages, including stack traces.
    • Use caller to get varying amounts of information from just the caller's package to a complete stack trace.
    • Write $SIG{__WARN__} and $SIG{__DIE__} handlers (see %SIG in perlvar).
    • Take a look at the information provided by the $!, $?, $@ and $^E Error Variables.
    • Use autodie to trap errors from specific functions.
    • CPAN modules such as TryCatch and Try::Tiny. Take a look at their SEE ALSO sections for similar modules.
    • A CPAN search for 'exception' may prove fruitful.

    -- Ken

Re: trap run time errors
by marinersk (Priest) on Oct 15, 2013 at 13:19 UTC
    Example:

    01 #!/usr/bin/perl 02 03 use strict; 04 use warnings; 05 06 my $testval; 07 08 my $newval = "$testval test"; 09 10 exit; 11 12 __END__ C:\Steve\Dev\PerlMonks\P-2013-10-15@0712-Uninitalized>uninit.pl Use of uninitialized value $testval in concatenation (.) or string at C:\Steve\Dev\PerlMonks\P-2013-10-15@0712\Uninitalized\uninit.pl line 8 .

    Line 8 attempts to build a string using embedded translation of $testval which is, at that time, uninitialized.

    So the error message should tell you where to look. All the usual caveats apply; depending on what you're doing, the actual error in Perl could be not exactly on the line where perl caught the error, but at least you have reduced it from a haystack to a handful of hay.

    Good luck!

Re: trap run time errors
by no_slogan (Deacon) on Oct 15, 2013 at 15:44 UTC
    Maybe try use warnings FATAL => 'all'; with strategic evals?

    Trying to retrofit old code to make it warning-proof may not be worth the candle. You tend to end up with a lot of $foo // '', which isn't really an improvement.

Re: trap run time errors
by Laurent_R (Canon) on Oct 15, 2013 at 21:15 UTC

    Just one easy but useful command to find the reason why you obtained an uninitialized value warning when processing, say, line 1,234,687 of your input.txt file:

    $ perl -ne 'print if $. == 1234687' input.txt

    Or, if your file is much longer than 1,234,687 lines:

    $ perl -ne 'print and exit if $. == 1234687' input.txt
Re: trap run time errors
by aitap (Curate) on Oct 19, 2013 at 19:15 UTC
    I would like to increment the $SIG{__WARN__} solution. This is an example of how can you catch and analyze warnings at program run time:
    $ perl -w -MData::Dumper -E' $SIG{__WARN__} = sub { print Dumper \@_, [ caller(0) ] }; # create an +d install the handler my $undef; # obviousely undefined say "$undef undef"; # warning occurs here ' $VAR1 = [ 'Use of uninitialized value $undef in concatenation (.) or s +tring at -e line 4. ' ]; $VAR2 = [ 'main', '-e', 1, 'main::__ANON__', 1, '', undef, undef, 133376, 'UUUUUUUUUUUUU', { 'feature_unicode' => 1, 'feature_say' => 1, 'feature_state' => 1, 'feature_switch' => 1 } ]; undef

    As you can see, if you have installed a subroutine as the warning handler using %SIG hash, it gets called each time you encounter a warning with the error message as the first parameter ($_[0]), and you can obtain the information on where did the warning occur using caller. No error message is printed, you can warn it from your warning handler if you want to.

    It's probably a good idea to make your changes to %SIG local, otherwise you can catch warnings in code you have no control of. Also have a look at the Carp module which is very useful for error reporting from modules and can print backtraces.