Perl5 IO::Tee and verbose
Every stand-alone application I write do have a
Getopt
cycle, often Getopt::Long::Descriptive
, and includes a verbose option to really see what is going on while the application is running.
Now, handling the verbose option is easy and not invasive at all thanks to the well known postfix conditionals:
say 'Here doing stuff...' if ( $opts->verbose );
IO::Tee
(which is an implementation similar to tee(1)
).
But wait a minute, something like that will not work as I would like:
my $tee = IO::Tee->new( \*STDOUT, IO::File->new( 'log.txt', 'w' ) );
...
say {$tee} 'here doing some stuff' if ( $opts->verbose );
STDOUT
and the log only if the verbose mode is on!
But the idea behind a log is to be annoying with verbose messages while the user is not annoyed with other messages on the screen, so I want messages to be placed on the log always without any regard to the verbosity of the program run.
So how to achieve that? The quick and dirty solution is to replicate any message to the respective file handle, so throwing away the IO::Tee
at all:
say 'working..' if ( $opts->verbose );
say {$log} 'working..';
IO::Tee
and apply the following idiom:
my $output = IO::File->new( $log_file_name, 'w' );
...
# options check
if ( $opts->verbose ){
$output = IO::Tee->new( \*STDOUT, $output );
}
...
# and then
say ${output} 'working';
$output
file handle to the log file. In this way, each time I print to the {$output}
I’m sure the message hits at leas the log file.
Later, when I can check the options the user has entered for this particular run, I overwrite the {$output}
file handle with an IO::Tee
(that exploits the $output
itself) with the STDOUT
. This way, each time I say
something, I’m sure it will be at least recorded in the logs, and moreover it will not be subjected to a postfix conditional.
As trivial as it can be, I use this approach quite often.
Of course this does not substitute a more complex and feature rich logging mechanism, rather it proposes a quick idiom to handle message to a log (always) and the standard output (if verbosity mode is on).
As a result of this post, I decided to try to manipulate the IO::Tee
module to place an add
method in order to allow for someone to add an handle after the object has been created. Please see the Pull Request #2 here.