1

I have the following error message (with Perl 5):

Tools.pm: Filehandle STDOUT reopened as FH only for input at /usr/local/lib/perl5/site_perl/mach/5.20/Template/Provider.pm line 967.

I understand its cause: It is that STDOUT was closed and later the same FD was used for something unrelated to STDOUT.

The code does the right thing. The only problem is that this error message should not to be logged.

How to stop printing this error message into our log file?

porton
  • 5,214
  • 11
  • 47
  • 95
  • Are these custom modules? What determines whether the error should or not be logged? – zdim Aug 20 '17 at 20:15
  • These are our custom modules used together with standard Template Toolkit. The error should not be logged as determined by the request of my boss – porton Aug 20 '17 at 20:39
  • OK. I meant, what code logs the error? There's got to be something that goes out of its way to log the error. Is that set in Template Toolkit (I don't use it), or by your modules? (One way would be to use `__WARN__` hook, but hopefully there are cleaner ways) – zdim Aug 20 '17 at 20:41
  • @zdim The error is logged by a module from Template Toolkit distribution, which opens a file after `close(STDOUT);` in one of our custom modules. Yes, the error is logged by Template Toolkit not by our custom modules. My question is how to make Template Toolkit not to log the error – porton Aug 20 '17 at 21:00
  • 1
    You shouldn't close STDOUT. Re-open it to /dev/null instead – ikegami Aug 20 '17 at 22:41

1 Answers1

2

Detailed handling of errors is outlined in Template::Manual::Config::ERROR.

It can be categorized in the constructor by specifying templates for exception types

my $template = Template->new({  
     ERRORS => {
         user     => 'user/index.html',
         dbi      => 'error/database',
         default  => 'error/default',
     },
});

which can be raised using the THROW directive

[% THROW user.login 'no user id: please login' %]

or by calling throw method

$context->throw('user.passwd', 'Incorrect Password');  
$context->throw('Incorrect Password');    # type 'undef'

or by Perl code by calling die, perhaps with a Template::Exception object.

How to use this to solve the problem is a matter of details, of which none are provided.

But you really want to find (user) code that triggers this and clean it up. For one, as noted by ikegami in a comment, don't close STDOUT but reopen it to /dev/null. (I'd say, never simply close standard streams.) For instance, if you just don't want to see STDOUT any more

open STDOUT, '>', '/dev/null';

or first copy it (uses dup2) before reopening so that you can restore it later

open my $SAVEOUT, '>&', 'STDOUT';
open STDOUT, '>', '/dev/null';
...
open STDOUT, '>', $SAVEOUT;  # restore STDOUT
close $SAVEOUT;              # if unneeded

(see open), or if feasible create a local *FOO and use that to save STDOUT.

The warning comes about since the lowest unused file descriptor is always used, and here fd 1 was vacated by closing STDOUT; but it is attempted to be used for input what isn't OK. As for why it's not OK and why emit a warning, this thread and an old bug report are useful. This goes beyond Perl.


One generic way is to use the __WARN__ hook

BEGIN {
    $SIG{__WARN__} = sub {
        warn @_ 
            unless $_[0] ~= /Filehandle STDOUT reopened as FH only for input/
    }
};

where the warning is emitted unless it matches the one you want to suppress. This BEGIN block need be before the use statements for modules it is expected to affect. If you know the scope at which this is needed it is better to localize it, local $SIG{__WARN__} = sub {...};

See this post and its links, to other posts and relevant documentation, for more details.

zdim
  • 64,580
  • 5
  • 52
  • 81