in reply to Troubleshooting perl runtime errors

For logging, use something like Log::Any. In the line just before where the error is occuring, I would $log->debugf("DIcas_text='%s', HR=%s", \@HR); -- but that will add to your log whether or not there was an error.

As for debugging the problem: see perldiag#Use of uninitialized value: something in your @HR is coming up as an undef.

Armed with that knowledge, I might change the logging to something like what's used in the following SSCCE:

use warnings; use strict; use Log::Any qw($log); use Log::Any::Adapter ('File', './debug.log'); sub errcheck_array { my $logger = shift; my $prefix = shift; my $count = grep {!defined} @_; # count the number of undefined el +ements in input array return unless $count; # this line will prevent a log mes +sage unless there's an undef; comment it out to log _all_ calls, whet +her or not there's an undefined value $logger->debugf("%s: %d undefined values found in %s", $prefix, $c +ount, \@_); 1; } foreach my $hr ( [qw(a b c)], [a => undef, b => undef, 'c'], [qw(x y z +)] ) { my @HR = @$hr; my $DIcas_text = '%s' . ',%s'x$#HR; errcheck_array($log, "sprintf('$DIcas_text', \@HR)", @HR); my $EVmsg = sprintf($DIcas_text, @HR); print "STD OUTPUT> $EVmsg\ +n"; }

Replies are listed 'Best First'.
Re^2: Troubleshooting perl runtime errors
by AnomalousMonk (Archbishop) on Nov 16, 2016 at 16:22 UTC
    ... something in your @HR is coming up as an undef.

    I was going to write that a simple empty array could also produce an "... uninitialized value in printf ..." warning, but warnings apparently got a little bit smarter in version 5.12:

    c:\@Work\Perl>perl -wMstrict -le "print 'perl version ', $]; ;; my @HR; ;; printf qq{A: %s \n}, @HR; ;; ++$#HR; printf qq{B: %s \n}, @HR; " perl version 5.008009 Use of uninitialized value in printf at -e line 1. A: Use of uninitialized value in printf at -e line 1. B: perl version 5.010001 Use of uninitialized value in printf at -e line 1. A: Use of uninitialized value in printf at -e line 1. B: perl version 5.012003 Missing argument in printf at -e line 1. A: Use of uninitialized value in printf at -e line 1. B: perl version 5.014004 Missing argument in printf at -e line 1. A: Use of uninitialized value in printf at -e line 1. B:
    (See 'Missing argument in %s' in perldiag in version 5.12 and after.)

    Update: Posted this reply before seeing other, closely related replies: this from Monk::Thomas and this from hippo.


    Give a man a fish:  <%-{-{-{-<

      Yeah, with 5.8.x, the warnings are indistinguishable. And thanks for pointing out that the empty array will also create that error: my errcheck_array() didn't handle the empty array condition.

      Further, while both my method and the BrowserUk/stevieb method will help you find what's wrong, neither will help sanitize the input to prevent the warning in a live-system (for example, if you need your debug logging live until the unlikely data triggers it, but you still need the production code to set a reasonable value for $EVmsg): it's safer in production code to try to sanitize the input, to prevent such a condition from affecting your users. For that, you could wrap an error-checker-and-sanitizer around the sprintf command, or otherwise sanitize before running the sprintf. This example has a wrapper sprintf_prevent_error() and a sanitize() function which cleans and logs, but keeps the sprintf separate:

      use warnings; use strict; use Log::Any qw($log); use Log::Any::Adapter ('File', './debug.log', log_level => 'debug'); sub sprintf_prevent_error { my $format = shift; my @a = @_; # if there isn't a format, log an error message and return an erro +r string # might want to return undef instead, and check $EVmsg for undef + before blindly doing anything else with it... unless(defined $format) { $log->debugf("sprintf('%s',%s): format is not defined", $forma +t, \@_); return "<WARNING: sprintf format not defined>"; } # if there aren't any arguments, the array is undefined; log an er +ror message and return an error string # might want to return undef instead, and check $EVmsg for undef + before blindly doing anything else with it... unless(@a) { $log->debugf("sprintf('%s',%s): array is empty", $format, \@_) +; return "<WARNING: array is empty>"; } # count the number of undefined elements in input array, and log t +he error message # but _don't_ return; we will sanitize the inputs and continue t +o create the sprintf my $count = grep {!defined} @a; $log->debugf("sprintf('%s',%s): sanitizing %d undefined values", $ +format, \@_, $count) if $count; # sanitizes the input: replace any undefined elements with the emp +ty string $_//='' for @a; # return the final sprintf of the sanitized input sprintf $format, @a; } sub sanitize { $log->debugf("sanitize(%s): calling", \@_); unless(@_) { # log and return if there's nothing to sanitize $log->debugf("sanitize(%s): nothing to sanitize", \@_); return; }; my $count = grep {!defined} @_; # count the undefined argument +s $log->debugf("sprintf(%s): sanitizing %d undefined values", \@_, $ +count) if $count; $_//='' for @_; } foreach my $hr ( [qw(a b c)], [d => undef, e => undef, 'f'], [qw(x y z +)], [] ) { my @HR = @$hr; my $DIcas_text = @HR ? '%s' . ',%s'x$#HR : 'empty array format'; my $EVmsg = sprintf_prevent_error($DIcas_text, @HR); print "STD OUTPUT> $EVmsg\n"; $EVmsg = sprintf_prevent_error(undef, @HR); print "STD OUTPUT> $EVmsg\n"; sanitize($DIcas_text, @HR); $EVmsg = sprintf($DIcas_text, @HR); }