Beefy Boxes and Bandwidth Generously Provided by pair Networks
Come for the quick hacks, stay for the epiphanies.
 
PerlMonks  

How to capture (intercept) output (warnings) of a module

by davidfilmer (Sexton)
on Sep 05, 2020 at 07:04 UTC ( [id://11121361]=perlquestion: print w/replies, xml ) Need Help??

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

Greetings, Masters. I have an oddball module (Graphics::TIFF, but that's not really relevant; my question is not about the module itself). It is emitting warning messages to the console, such as:

TIFFReadDirectory: Warning, Unknown field with tag 37724 (0x935c) encountered.

The method that I am calling (my $count = $tiff->NumberOfDirectories();) succeeds, and the method returns the correct value for $count (NumberOfDirectories), while also emitting that warning message to the console. It does not return the warning message (it returns the number of directories, as it should).

The module is not setting $! or anything (return code is zero, since it counted the directories) - these are just warning messages. But the module doesn't provide any method for me to access these warnings, other than just dumping my program output to a file (which I would then have to subsequently parse through - groan).

I'm running my job in batch - I want to capture these warnings to a log database. So (I think) I need to somehow tell my program to watch STDOUT/STDERR from this module and capture any messages.

How do I do that, Masters?

Replies are listed 'Best First'.
Re: How to capture (intercept) output (warnings) of a module
by swl (Parson) on Sep 05, 2020 at 07:24 UTC
Re: How to capture (intercept) output (warnings) of a module
by LanX (Saint) on Sep 05, 2020 at 07:35 UTC
      But since this is a wrapper around a C lib you might really need to temporarily redirect STDERR and STDOUT to a variable

      That would not work unless the C lib performs IO through the PerlIO layer (instead of the usual stdio C layer), something very unlikely.

      On the other hand, libtiff provides a TIFFSetWarningHandler function just for customizing error reporting. It is not exposed by the Perl wrapper, but adding that feature shouldn't be too difficult.

        Looks like not the OP's (i.e. davidfilmer) case, but, sadly, libtiff shipped with Strawberry Perl generates warnings as ugly pop-up GUI modal boxes, requiring user interaction to dispose. Therefore, without recompilation, the solution with Capture::Tiny won't work.

        On the other hand, libtiff provides a TIFFSetWarningHandler function just for customizing error reporting. It is not exposed by the Perl wrapper, but adding that feature shouldn't be too difficult.

        Ah, then I can do it:

        use strict; use warnings; use Graphics::TIFF; my $fn = 'TIFF01.TIF'; # a file known to generate # a warning (as shown below) DummyTiffLogger::init(); Graphics::TIFF-> Open( $fn, 'r' ) for 1..5; package DummyTiffLogger { sub logMessage { my $s = shift; printf "message logged: <%s>\n", $s } use Inline C => Config => LIBS => '-ltiff'; use Inline C => <<'END_OF_C'; #define BUFSIZE 1024 void _log(char* m, char* fmt, va_list ap) { char* buf; int len; SV* sv; Newxz(buf, BUFSIZE, char); len = vsprintf(buf, fmt, ap); Renew(buf, len + 1, char); sv = newSV(0); sv_usepvn_flags(sv, buf, len, SV_SMAGIC | SV_HAS_TRAILING_NUL); dSP; ENTER; SAVETMPS; PUSHMARK(SP); XPUSHs(sv_2mortal(sv)); PUTBACK; call_pv("DummyTiffLogger::logMessage", G_DISCARD); FREETMPS; LEAVE; } void init() { TIFFSetWarningHandler(&_log); } END_OF_C } # package __END__ message logged: <Unknown field with tag 32781 (0x800d) encountered> message logged: <Unknown field with tag 32781 (0x800d) encountered> message logged: <Unknown field with tag 32781 (0x800d) encountered> message logged: <Unknown field with tag 32781 (0x800d) encountered> message logged: <Unknown field with tag 32781 (0x800d) encountered>
        I've always been under the impression that redirections are inherited to° a child process.

        But you should know better.

        > libtiff provides a TIFFSetWarningHandler function just for customizing error reporting.

        I've recommended this myself, but I'm not sure if this interface allows a Perl sub as call back.

        Cheers Rolf
        (addicted to the Perl Programming Language :)
        Wikisyntax for the Monastery

        °) Correction: to "bequeath", to "pass on" in correct English, "inherit" can't be used that way

Re: How to capture (intercept) output (warnings) of a module
by perlfan (Vicar) on Sep 05, 2020 at 16:55 UTC
    You mentioned logging but didn't say how you were doing it. I encourage you to take a look at utilizing Log::Log4perl. It doesn't help you with your main question, but it really helps manage logging and messaging during run time.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://11121361]
Approved by LanX
Front-paged by marto
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others taking refuge in the Monastery: (3)
As of 2024-04-20 15:43 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found