1

I was wanting to implement some logging for a threaded script I have, and I came across File::Tee. However, when attempting to ppm the module on a Windows box, it's not found (and according to activestate, not supported on Windows).

I really liked that you could lock file access though, by doing something like:

tee STDOUT, {mode => '>>', open => '$ENV{DOM}\\threaded_build.log', lock => 1};
tee STDERR, {mode => '>>', open => '$ENV{DOM}\\threaded_debug.log', lock => 1};

Is there a cross-platform, thread-safe alternative?

MrDuk
  • 16,578
  • 18
  • 74
  • 133

1 Answers1

3

File::Tee takes extra care to handle output generated by external programs run through system or XS code that doesn't go through perlio. I think that's what makes it incompatible with Windows.

IO::Tee is more cross-platform and I don't think making it thread safe would be too hard to do. The sync code in File::Tee just looks like:

                    flock($teefh, LOCK_EX) if $target->{lock};
                    print $teefh $cp;
                    flock($teefh, LOCK_UN) if $target->{lock};

You could accomplish the same thing in IO::Tee by modifying a couple of methods:

use Fcntl ':flock';

no warnings 'redefine';
sub IO::Tee::PRINT
{
    my $self = shift;
    my $ret = 1;
    foreach my $fh (@$self) {
        flock($fh, LOCK_EX);
        undef $ret unless print $fh @_;
        flock($fh, LOCK_UN);
    }
    return $ret;
}
sub IO::Tee::PRINTF
{
    my $self = shift;
    my $fmt = shift;
    my $ret = 1;
    foreach my $fh (@$self) { 
        flock($fh, LOCK_EX);
        undef $ret unless printf $fh $fmt, @_;
        flock($fh, LOCK_UN);
    }
    return $ret;
}
mob
  • 117,087
  • 18
  • 149
  • 283
  • Hm, so I started this implementation, but when I do `ppm install IO-Tee` I get `ppm install failed: Can't find any package that provides IO-Tee` – MrDuk Apr 24 '14 at 15:33
  • That's disappointing -- `IO::Tee` has been around a while and it's compatible with Windows. No matter. It's also a pure perl module with a single file, [so you can just copy it] (http://cpansearch.perl.org/src/KENSHAN/IO-Tee-0.64/Tee.pm) into your system libraries folder. – mob Apr 24 '14 at 15:38
  • Thanks! I know this is surplus to the original question, but you do declare it as `my $tee = IO::Tee->new(\*STDOUT, "$ENV{PATH}\\build.log");` and then just do `print $tee "stuff";`, right? – MrDuk Apr 24 '14 at 15:47
  • 2
    See the [EXAMPLE](http://search.cpan.org/~kenshan/IO-Tee-0.64/Tee.pm#EXAMPLE) in the docs. Arguments to `IO::Tee->new` are either file handles or old-style file mode + file name arguments (`>foo.txt`). `$ENV{PATH}/build.log` may create an input file handle unless you write it as `>$ENV{PATH}/build.log`. – mob Apr 24 '14 at 15:56
  • Thank you -- I had (intentionally for some reason) left off the `>` – MrDuk Apr 24 '14 at 15:58