Wrapping Perl "die" and "warn" in a utility subroutine - perl

I want to write a small subroutine that can decorate all error messages in a consistent way instead of having to copy it all around my program.
However I want the line numbers to be from where it was called, not from where the die/warn occurred.
In C I would just use a preprocessor macro, but Perl does not have those. What is the best way to implement this?

Use Carp for warnings/errors. You can use __WARN__ and __DIE__ hooks to affect what warn prints to the STDERR stream and how die is thrown. Note that they are quite different.
use warnings;
use strict;
use feature 'say';
use Carp;
$SIG{__WARN__} = \&wrap_warn;
sub wrap_warn {
print "WARNING: #_";
}
sub level_2 {
say "Print from level_2";
carp "carp from level_2(#_)";
}
sub level_1 {
level_2(#_);
}
level_1("from main");
prints to STDOUT
Print from level_2
WARNING: carp from level_2(from main) at wrap_warn.pl line 19.
main::level_2('from main') called at wrap_warn.pl line 15
main::level_1('from main') called at wrap_warn.pl line 22
If you want this to still go to STDERR then use print STDERR "WARNING: #_";
Make sure to carefully read about %SIG in perlvar and warn, at least.
While it seems that you want this to be global, I'd like to mention that one generally wants to local-ize changes like this one. There's an example in this post, and more out there.

Adding the following will add stack traces to exceptions and warnings:
use Carp::Always;
For the occasional use, use the following to avoid modifying your program:
perl -MCarp::Always script args
or
PERL5OPT=-MCarp::Always script args

Related

Perl: print compilation warnings for do()

I am using do() to execute a perl script. I wanted to make sure it was doing the right error checking, but I noticed that warnings don't get printed when I use do(). I left the following warning on purpose in my script. I see it when I run it on the command line
Useless use of numeric eq (==) in void context at utils/queryEvent/query_event.pl line 47.
When I use do(), this message is suppressed. I saw in perlvar that $# doesn't contain warnings, so I tried to add this before my call to do(), but I still don't see anything.
local $SIG{__WARN__} = sub {
print "Warning #_\n";
};
do(...);
Is there a way I can still print the compilation/parsing warnings?
I'm using Perl v.5.22.1 on Windows 10.
Added edit:
Both the script calling do() and the script being run through do() have use strict; and use warnings;. It is only the parsing warning that isn't showing up. If I call warn in the do script, then I see that (I'm assuming stderr).
Edit:
Adding example script.
A minimal reproducible version is the following
use strict;
use warnings;
sub test
{
return 1;
}
main:
{
(test() == 1);
}
Calling script
use strict;
use warnings;
main:
{
do('test.pl');
}
You are mistaken. do doesn't affect warnings in the least.
There is no warning because there is nothing that should cause a warning. (test() == 1) isn't being evaluated in void context. Instead, its result is returned by do.
But while warnings AREN'T being silenced, exceptions ARE being silenced. Fixing this will fix the other.
Add a trailing 1 to the file loaded by do, and change the do as follows:
do('test.pl')
or die( "Can't execute `./test.pl`: ".( $# // $! ) );
The trailing 1 is used to signal the "caller" whether an error occurred or not. This has the side effect of cause (test() == 1) to be evaluated in void context as expected.
The -w or -W command-line switches will enable warnings throughout your program, including code included through a do statement.

Perl unexpected behavior: croak vs. try catch

I had seen some exceptions that pointed to (end of) the catch block itself (see the example below).
As my opinion, this is an unexpected behavior, since it alters the location of original exception and make difficult to debug (it should say die at line 13.)
It shows the (correct) line 13, if I use die/confess or using eval instead try-catch.
Not knowing how my code will be called within the stack, I started to avoid using croak now. What do you think? Did I get right, or there is a way to improve this?
Best regards, Steve
use Carp;
use Try::Tiny;
try {
foo();
}
catch {
# do something before die
die $_;
}; # this is line 10
sub foo {
croak 'die'; # this is line 13
}
Output:
die at line 10.
This is the intended behavior from Carp
[...] use carp() or croak() which report the error as being from where your module was called. [...] There is no guarantee that that is where the error was, but it is a good educated guess.
So the error is reported at where the module's sub is called, which is what the user wants
use warnings;
use strict;
use feature 'say';
use Try::Tiny;
package Throw {
use warnings;
use Carp qw(croak confess);
#sub bam { die "die in module" }; # l.11
sub bam { croak "croak in module" };
1;
};
try {
Throw::bam(); # l.17
}
catch {
say "caught one: $_";
die "die in catch: $_";
};
say "done";
Prints
caught one: croak in module at exceptions.pl line 17.
die in catch: croak in module at exceptions.pl line 17.
If the sub throws using die then this is reported at line 11, what is the normal behavior of die, and what you seem to expect.
If any of this is unclear or suboptimal then better use confess and nicely get a full stacktrace. Also, if you wish more exception-based-like code behavior, can put together an exception/error class and throw its object,† designed and populated as desired.
If you want to confess an object note that at this time Carp has limits with that
The Carp routines don't handle exception objects currently. If called with a first argument that is a reference, they simply call die() or warn(), as appropriate.
One way then would be to confess a stringification of the object,‡ getting at least both a full stack backtrace and whatever is in the object.
I get the same behavior with eval, by replacing try-catch and $_ above
eval {
Throw::bam();
};
if ($#) {
say "caught one: $#";
die "die in catch: $#";
};
Prints exactly the same as above
While the above is clear and behaves as expected, a weird thing is indeed seen in the question's example: the error is reported from the whole try-catch statement, ie. at its closing brace, where line 10 is. (The try sub is prototyped and the whole try-catch is a syntax aid equivalent to a call to try that takes an anonymous sub, and then perhaps more. See ikegami's comment, and docs. Also see this post for more about its syntax.)
This is strange since the call to the croaking sub is foo() inside the try statement and this line should be reported, what can be confirmed by running the script with -MCarp::Always. But in the code in this answer the line of the call to Throw::bam is indeed reported -- why this difference?
The clear purpose of croak is to be used in the libraries, so that the user can see at which point in their (user's) code they called the library in a way that triggered an error. (While die would point to the place where error is detected, so in the library, most likely useless to the user. But read die and Carp docs for related complexities.)
What isn't obvious is that when croak is emitted in the same namespace (main::foo()) from try-catch in its own namespace (Try::Tiny) things get confused, and the end of its statement is reported. This can be checked by adding a foo() to my code above and calling it (instead of a sub from a module), and we get the question's behavior reproduced.
This doesn't happen if main::foo() with croak inside is called from a (complex) statement right in main::, so it seems to be due to the try-catch mix up of namespaces. (On the other hand, try-catch sugar adds an anonymous sub to the callstack, and this sure can mix things up as well.)
In practical terms, I'd say: always use croak out of modules (otherwise use die), or, better yet if you want to mimic exception-based code, use confess and/or your exception class hierarchy.
† Even just like die ExceptionClass->new(...);
Bear in mind that in the way of exceptions Perl only has the lonesome die, and eval. For more structure you'll need to implement it all, or use frameworks like Exception::Class or Throwable
‡ By writing and using a method that generates a plain string with useful information from the object, for Carp::confess $obj->stringify.
Or by overloading the "" (quote) operator for the class since it gets used when confess-ing an object (string context), for Carp::confess $obj; this is good to have anyway.
A basic example for both:
use overload ( q("") => \&stringify );
sub stringify {
my $self = shift;
join ", ", map { "$_ => " . ( $self->{$_} // 'undef' ) } keys %$self
}
where instead of a reference to a named sub on can directly write an anonymous sub.
As a way of solving the OP's problem, but with a different module, if you use Nice::Try instead, you will get the result you expect:
use Carp;
use Nice::Try;
try {
foo();
}
catch {
# do something before die
die $_;
} # this is line 10
sub foo {
croak 'die'; # this is line 13
}
You get:
die at ./try-catch-and-croak.pl line 13.
main::foo() called at ./try-catch-and-croak.pl line 4
main::__ANON__ called at ./try-catch-and-croak.pl line 7
eval {...} called at ./try-catch-and-croak.pl line 7 ...propagated at ./try-catch-and-croak.pl line 9.
For full disclosure, I am the author behind Nice::Try

Perl 1,000 subroutine redefined

I have a Perl script which uses Module::Reload::Selective to load a module. The perl script looks like this, more or less.
#!/usr/bin/perl
use strict;
use warnings;
use Module::Reload::Selective;
&reload;
sub reload {
Module::Reload::Selective->reload(qw(myModule));
import myModule qw($reloadtime);
$reloadtime = ${myModule::reloadtime};
}
The module looks like this:
package myModule;
use Config::General;
use Data::Dumper;
use DBI;
use HTTP::Request::Common qw { POST };
use HTTP::Headers;
use JSON::XS;
use LWP::UserAgent;
use Module::Pluggable search_path => "Bot";
use POSIX qw(strftime ceil);
# stuff here
1;
When I run the main script I get about 100 like this:
Subroutine export_fail redefined at /usr/local/share/perl/5.14.2/Carp.pm line 64.
Subroutine _cgc redefined at /usr/local/share/perl/5.14.2/Carp.pm line 66.
Subroutine longmess redefined at /usr/local/share/perl/5.14.2/Carp.pm line 72.
Subroutine shortmess redefined at /usr/local/share/perl/5.14.2/Carp.pm line 92.
Subroutine croak redefined at /usr/local/share/perl/5.14.2/Carp.pm line 100.
Subroutine confess redefined at /usr/local/share/perl/5.14.2/Carp.pm line 101.
Subroutine carp redefined at /usr/local/share/perl/5.14.2/Carp.pm line 102.
I noticed if I comment out some of the "use" statements in my module these will go away. But I need those. I've searched all over and tried a number of things. to no avail.
Sometimes it is ok to redefine subroutines. If you know what you are doing and want to suppress the warnings, just put
no warnings 'redefine';
at the top of your reload method.
Another option, again, so long as you know what you doing, is to temporarily disable the builtin warnings handler:
sub reload {
local $SIG{__WARN__} = sub {};
... do something that warns ...
}
And as a last resort, since warnings are written to STDERR, you can temporarily redirect STDERR.
sub reload {
open my $devnull, '>/dev/null'; # Windows: >nul
local *STDERR = *$devnull;
... do something that warns ...
}
I had this too. In my case I tracked the error down to the plugins() call in Module::Pluggable. If that's where your noise comes from too this might work for you also.
answer is in the weeds here: http://cpansearch.perl.org/src/SIMONW/Module-Pluggable-5.1/lib/Module/Pluggable.pm
where it explains that plugins() is called more than necessary which can get expensive, so you do something like this:
package Foo;
use strict;
use Module::Pluggable sub_name => '_plugins';
our #PLUGINS;
sub plugins { #PLUGINS ||= shift->_plugins }
1;
That didn't exactly work for me at first, but it did when I fleshed out the plugins() sub into several lines and populated/returned an array ref in my $self.

Perl - New definition of myprint() or Overload print command

I am a newb to Perl. I am writing some scripts and want to define my own print called myprint() which will print the stuff passed to it based on some flags (verbose/debug flag)
open(FD, "> /tmp/abc.txt") or die "Cannot create abc.txt file";
print FD "---Production Data---\n";
myprint "Hello - This is only a comment - debug data";
Can someone please help me with some sample code to for myprint() function?
Do you care more about writing your own logging system, or do you want to know how to put logging statements in appropriate parts of your program which you can turn off (and, incur little performance penalty when they are turned off)?
If you want a logging system that is easy to start using, but also offers a world of features which you can incrementally discover and use, Log::Log4perl is a good option. It has an easy mode, which allows you to specify the desired logging level, and emits only those logging messages that are above the desired level.
#!/usr/bin/env perl
use strict; use warnings;
use File::Temp qw(tempfile);
use Log::Log4perl qw(:easy);
Log::Log4perl->easy_init({level => $INFO});
my ($fh, $filename) = tempfile;
print $fh "---Production Data---\n";
WARN 'Wrote something somewhere somehow';
The snippet also shows a better way of opening a temporary file using File::Temp.
As for overriding the built-in print … It really isn't a good idea to fiddle with built-ins except in very specific circumstances. perldoc perlsub has a section on Overriding Built-in Functions. The accepted answer to this question lists the Perl built-ins that cannot be overridden. print is one of those.
But, then, one really does not need to override a built-in to write a logging system.
So, if an already-written logging system does not do it for you, you really seem to be asking "how do I write a function that prints stuff conditionally depending on the value of a flag?"
Here is one way:
#!/usr/bin/env perl
package My::Logger;
{
use strict; use warnings;
use Sub::Exporter -setup => {
exports => [
DEBUG => sub {
return sub {} unless $ENV{MYDEBUG};
return sub { print 'DEBUG: ' => #_ };
},
]
};
}
package main;
use strict; use warnings;
# You'd replace this with use My::Logger qw(DEBUG) if you put My::Logger
# in My/Logger.pm somewhere in your #INC
BEGIN {
My::Logger->import('DEBUG');
}
sub nicefunc {
print "Hello World!\n";
DEBUG("Isn't this a nice function?\n");
return;
}
nicefunc();
Sample usage:
$ ./yy.pl
Hello World!
$ MYDEBUG=1 ./yy.pl
Hello World!
DEBUG: Isn't this a nice function?
I wasn't going to answer this because Sinan already has the answer I'd recommend, but tonight I also happened to be working on the "Filehandle References" chapter to the upcoming Intermediate Perl. That are a couple of relevant paragraphs which I'll just copy directly without adapting them to your question:
IO::Null and IO::Interactive
Sometimes we don't want to send our output anywhere, but we are forced
to send it somewhere. In that case, we can use IO::Null to create
a filehandle that simply discards anything that we give it. It looks
and acts just like a filehandle, but does nothing:
use IO::Null;
my $null_fh = IO::Null->new;
some_printing_thing( $null_fh, #args );
Other times, we want output in some cases but not in others. If we are
logged in and running our program in our terminal, we probably want to
see lots of output. However, if we schedule the job through cron, we
probably don't care so much about the output as long as it does the job.
The IO::Interactive module is smart enough to tell the difference:
use IO::Interactive;
print { is_interactive } 'Bamboo car frame';
The is_interactive subroutine returns a filehandle. Since the
call to the subroutine is not a simple scalar variable, we surround
it with braces to tell Perl that it's the filehandle.
Now that you know about "do nothing" filehandles, you can replace some
ugly code that everyone tends to write. In some cases you want output
and in some cases you don't, so many people use a post-expression
conditional to turn off a statement in some cases:
print STDOUT "Hey, the radio's not working!" if $Debug;
Instead of that, you can assign different values to $debug_fh based
on whatever condition you want, then leave off the ugly if $Debug
at the end of every print:
use IO::Null;
my $debug_fh = $Debug ? *STDOUT : IO::Null->new;
$debug_fh->print( "Hey, the radio's not working!" );
The magic behind IO::Null might give a warning about "print() on
unopened filehandle GLOB" with the indirect object notation (e.g.
print $debug_fh) even though it works just fine. We don't get that
warning with the direct form.

How do you best attribute errors in a Perl method to the caller

Given a method that may fail with warnings and/or errors, I want the error method to show up at the caller. Fir instance this script:
foo(0); # line 1
sub foo {
1 / shift; # line 4
}
Produces the error Illegal division by zero at foo.pl line 4, but I want Illegal division by zero at foo.pl line 1. There should be several ways if I put the method in a module or if I wrap the method body in eval, but I have not found an easy way like this:
sub foo {
attributeErrorsToCaller; # do some magic
1 / shift;
}
Is there such a way?
EDIT: mirod's answer comes close not what I was looking for:
Foo::foo(0); # line 1
package Foo;
use diagnostics -traceonly;
BEGIN { disable diagnostics; }
sub foo {
enable diagnostics;
1 / shift; # line 9
}
Without enable diagnostics the error message is Illegal division by zero at foo.pl line 9.. With enable diagnostics it is still too verbose, but this may also be useful:
Uncaught exception from user code:
Illegal division by zero at foo.pl line 10.
at foo.pl line 10
Foo::foo(0) called at foo.pl line 2
I bet I could hack diagnostics to get exactely the feature I want, but using diagnostics as raw module is probably more recommended.
Carp is very, very close to "do_some_magic" you are asking for. For instance:
#!/usr/bin/perl -w
use strict;
# I fork to be as close to natural die() as possible.
fork() or Foo::foo();
fork() or Foo::bar();
fork() or Foo::baz();
sleep 1;
package Foo;
use Carp;
sub foo { die "Some error (foo)"; };
sub bar { croak "Some error (bar)"; };
sub baz { bar(); };
As you can see, croak() acts almost like die(), but reports error to the caller (even indirectly -- see baz).
However, it won't handle 1/0 for you -- either use eval (or even Try::Tiny), or check input values* and say "division by zero" yourself.
Carp is standard, which means understandable by further maintainers of your code, and also can print neat stack traces via confess or cluck or even print Carp::longmess (see the doc).
*which is good anyway
Would use diagnostics; be enough for you? It will dump the call stack, so the caller is quite easy to find out.
For example in you example:
#!/usr/bin/perl
use strict;
use warnings;
use diagnostics;
foo(0);
sub foo
{
return 1/$_[0];
}
gives this:
`Illegal division by zero at test_die line 12 (#1)
(F) You tried to divide a number by 0. Either something was wrong in
your logic, or you need to put a conditional in to guard against
meaningless input.
Uncaught exception from user code:
Illegal division by zero at test_die line 12.
at test_die line 12
main::foo(0) called at test_die line 8
Not like you describe. You can implement Debug::Trace to pull off a full back trace.
You may also find the perl caller which is quite useful for this type of debugging. But for a live application you will likely need to do more detailed tracing.
http://perldoc.perl.org/functions/caller.html