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

In some code I am writing, I have a logging subroutine which directs messages with a time stamp and process ID to a file. If a file name is not passed to the subroutine, the message is to be directed instead to STDERR. While I got this code working as desired through a bit of reading through redirecting STDERR, then back again and perlfunc:open, I am wondering if there is a cleaner way to implement this solution? The current version of my subroutine code follows:

sub write_logfile ($$) { use Time::HiRes 'time'; my ($file, $message) = @_; chomp($message); if (defined($file)) { open OLDERR, ">&STDERR"; open STDERR, ">>$file"; flock STDERR, 8; print OLDERR ""; }; print STDERR time, " [", $$, "] ", $message, "\n"; if (defined($file)) { close STDERR; open STDERR, ">&OLDERR"; }; };

The duplication and restoration of STDERR however seems messy and I'm wondering if TAMBWTDI (there's a much better way to do it).

Note: The print OLDERR ""; line is there to prevent the 'Name "main::OLDERR" used only once: possible typo at blah.perl line 162.' error otherwise generated under -w as per melguin's node here.

 

Ooohhh, Rob no beer function well without!

Replies are listed 'Best First'.
Re: Cleaner redirection of STDERR
by trantor (Chaplain) on Sep 23, 2001 at 10:59 UTC

    You could reverse the logic of your sub:

    if ($file) { open LOGFILE, ">>$file" or die "Error message: $!\n"; } else { open LOGFILE, ">&STDERR" or die "Another error\n"; } print LOGFILE "blah blah"; close LOGFILE or die "Yet another error\n";

    -- TMTOWTDI

Re: Cleaner redirection of STDERR
by RhetTbull (Curate) on Sep 24, 2001 at 07:58 UTC
    You may want to take a look at the Filter::Handle module. Instead of using a separate subroutine to write to your logfile or STDERR you could simply use 'print STDERR "my message";' and let Filter::Handle do what you meant. Take a look at my node about Filter::Handle for an example. Regards,
    -RT
      Did you know that Filter::Handle was written by our own btrott?

      Note that, as always, tie is not friends with any C-level stuff (eg modules, system calls) that don't go through Perl's IO layer, and tie doesn't like local very much. Both of those are gotchas I like to warn people about since I have been bitten by them in the past.

Re: Cleaner redirection of STDERR
by CubicSpline (Friar) on Sep 23, 2001 at 16:38 UTC
    On a note unrelated to the redirection of the output, is there any reason why you want to be using $$ as a parameter to this sub? $$ is global as the process id and you can access it from anywhere within the script. If you really want to be passing the pid of some other process, use a variable to indicate that, rather than changing $$.
      I think you are confusing the first occurance of '$$' and the second, in the code above. The first one is a function prototype, the second is the global var you mention. Prototyping isn't common in perl, so it looks a little funny, but the two '$$'s have nothing to do with one another.

      -Blake