Beefy Boxes and Bandwidth Generously Provided by pair Networks
Welcome to the Monastery
 
PerlMonks  

how i capture a script error to a file ?

by gabrielsousa (Sexton)
on Apr 27, 2017 at 12:28 UTC ( #1189032=perlquestion: print w/replies, xml ) Need Help??

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

how i capture a script error to a file ?
did this, but dont work :(
local $SIG{__DIE__} = sub { my $message = shift; system qq(echo "$message" >> log.err); };

Replies are listed 'Best First'.
Re: how i capture a script error to a file ?
by shmem (Chancellor) on Apr 27, 2017 at 12:47 UTC

    Why do you use system? Is your DIE handler actually called? what does that system() return?

    local $SIG{__DIE__} = sub { open my $fh, '>>', 'log.err' or warn "Can't append to 'log.err': $!" and return; print $fh @_; }

    Are you sure you are able to write the file in the current working directory?

    You could also just redirect STDERR to the file log.err -

    $ perl program.pl 2>log.err
    perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'
      i want to capture my script compilation erros ( or other errors ) to a log file
        want to capture my script compilation erros ( or other errors ) to a log file

        To capture compilation errors, redirect the STDERR of the invoking shell to the file as in my previous post:

        $ perl script.pl 2>log.err

        This also captures runtime errors thrown out STDERR. If you want to only capture fatal runtime errors, you might handle these through a DIE handler. However, this handler isn't setup if the compilation fails in the first place.

        perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'
        compilation erros

        Note this from perlvar:

        __DIE__/__WARN__ handlers are very special in one respect: they may be called to report (probable) errors found by the parser. In such a case the parser may be in inconsistent state, so any attempt to evaluate Perl code from such a handler will probably result in a segfault. This means that warnings or errors that result from parsing Perl should be used with extreme caution...

        Using $SIG{__DIE__} to catch runtime errors is fine, though, as well as from inside eval, despite what the above link currently says - the following is a text from the upcoming 5.26 (reference):

        The $SIG{__DIE__} hook is called even inside an eval(). It was never intended to happen this way, but an implementation glitch made this possible. This used to be deprecated, as it allowed strange action at a distance like rewriting a pending exception in $@. Plans to rectify this have been scrapped, as users found that rewriting a pending exception is actually a useful feature, and not a bug. Perl never issued a deprecation warning for this; the deprecation was by documentation policy only. But this deprecation has been lifted in Perl 5.26.

        If you want to reliably log compilation errors, redirect STDERR from outside of the script, like shmem said. Once the Perl script is up and running, you can use eval as a try/catch mechanism (eval { code here ...; 1 } or do { handle error }, or e.g. Try::Tiny), or use a $SIG{__DIE__} handler, however, note that the latter is only called when the program is already dying, so the only thing I'd do in that handler is try to do something with the error message, like rewrite it or attempt to log it to a file - keeping in mind that this may fail, which is why I said before to redirect STDERR from outside of the script.

        Oops, accidentally posted this node before finishing it. Okay, done working on it. No, really, now I am.

Re: how i capture a script error to a file ?
by Corion (Pope) on Apr 27, 2017 at 12:50 UTC

    The error is not passed as an argument to your die handler, but is in $@.

    Why shell out just to print an error message?

    my $message = $@; if( open my $log, '>>', 'log.err' ) { print $log $message; } else { warn "Couldn't write to 'log.err': $!"; warn $message; };

    Also, your __DIE__ handler will also be invoked from within eval { ... } blocks, which is most likely only confusing to you. You should check $^S to see if eval is currently running:

    return if $^S; # we are within an eval block
      The error is not passed as an argument to your die handler, but is in $@.

      How so? $@ is the last eval error. The arguments to die are passed to the DIE handler (whether invoked by perl itself or via die):

      local $SIG{__DIE__} = sub { open my $fh, '>>', 'log.err' or warn "Can't append to 'log.err': $!" and return; print $fh @_, "\n\$\@: |$@|"; }; eval { die "fubar!"; }; # <--- update, semicolon was missing 1 / 0; __END__ Illegal division by zero at foo.pl line 8.

      Contents of log.err:

      @_: |fubar! at foo.pl line 7. | $@: || @_: |Illegal division by zero at foo.pl line 8. | $@: |fubar! at foo.pl line 7. |

      The fubar! at foo.pl line 7. is repeated since $@ hasn't been cleared. If there had been a subsequent succeeding eval, $@ had been cleared.

      Neither die messages nor system errors ($!) are shoehorned into $@ for the DIE handler.

      update 2:

      Also, your __DIE__ handler will also be invoked from within eval { ... } blocks, which is most likely only confusing to you. You should check $^S to see if eval is currently running:
      return if $^S; # we are within an eval block

      This, as a general advice, is misleading. One might very well be interested in eval errors.

      perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'
        eval dont work on me :(
        Number found where operator expected at ./test3.pl line 21, near "1" (Missing semicolon on previous line?) syntax error at ./test3.pl line 21, near "1" Execution of ./test3.pl aborted due to compilation errors.
Re: how i capture a script error to a file ?
by hippo (Chancellor) on Apr 27, 2017 at 16:16 UTC
    did this, but dont work

    Of course it works:

    $ ls log.err ls: cannot access log.err: No such file or directory $ cat dieonpurpose.pl #!/usr/bin/env perl use strict; use warnings; local $SIG{__DIE__} = sub { my $message = shift; system qq(echo "$message" >> log.err); }; die "Afghanistan bananastand\n"; $ ./dieonpurpose.pl Afghanistan bananastand $ cat log.err Afghanistan bananastand $

    "It doesn't work" is as useful to a developer as "I'm ill" is to a medic. Try to be specific.

Re: how i capture a script error to a file ?
by LanX (Sage) on Apr 27, 2017 at 13:00 UTC
Re: how i capture a script error to a file ?
by talexb (Canon) on Apr 27, 2017 at 14:02 UTC

    In the scripts that I've been writing recently (data-munging under the guise of ETL), I've been opening an error log and then using that everywhere to log stuff as I go through.

    # Somewhere early on, so that it can be used everywhere. my $error_log; ... # I don't use 'or die' here because I use autodie. open ( $error_log, '>', 'errors.log' ); ... # Later, wherever it's necessary .. print $error_log "$unique_identifier" . "$useful_variables $more useful variables\n";
    So, you could use this approach by replacing
    system qq(echo "$message" >> log.err);
    in your own die case with
    print $error_log "$message\n";
    Exiting the program will close the error log filehandle. Then you can tail the error log and see what happened.

    There's another debate as to the necessity of crafting your own die handler .. but I'll leave that question unasked.

    Alex / talexb / Toronto

    Thanks PJ. We owe you so much. Groklaw -- RIP -- 2003 to 2013.

Re: how i capture a script error to a file ? (reopen STDERR)
by LanX (Sage) on May 06, 2017 at 16:19 UTC
    see Parsing and translating Perl Regexes for a concise example how to temporarily redirect STDERR and restore it later. (here to a variable instead of a file)

    and Re^3: Capturing STDERR using IO::Handle for even more detailed examples.

    It's documented in the perldocs, but can't remember where...

    edit

    If you just want to redirect STDERR permanently for the lifetime of your Perl execution (beware of modperl !!!), this should do (and capture also all compilation errors)

    BEGIN { close STDERR; open STDERR, ">>", "log.err"; }

    Cheers Rolf
    (addicted to the Perl Programming Language and ☆☆☆☆ :)
    Je suis Charlie!

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1189032]
Approved by 1nickt
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others avoiding work at the Monastery: (4)
As of 2021-09-28 16:48 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found

    Notices?