我需要使用一些不幸地将诊断消息记录到 STDOUT 和 STDERR 的库。通过使用tie
,我可以将这些写入重定向到捕获这些写入的函数。由于我不希望通过绑定句柄捕获我的程序的所有 STDOUT 和 STDERR 输出,因此我只想对某些包执行此操作。
我想出了一个解决方案,其中实际行为是通过查看 caller() 来确定的,如下所示,但我觉得必须有更好的方法......有更优雅的解决方案吗?
package My::Log::Capture;
use strict;
use warnings;
use 5.010;
sub TIEHANDLE {
my ($class, $channel, $fh, $packages) = @_;
bless {
channel => lc $channel,
fh => $fh,
packages => $packages,
}, $class;
}
sub PRINT {
my $self = shift;
my $caller = (caller)[0];
if ($caller ~~ $self->{packages}) {
local *STDOUT = *STDOUT;
local *STDERR = *STDERR;
given ($self->{channel}) {
when ('stdout') {
*STDOUT = $self->{fh};
}
when ('stderr') {
*STDERR = $self->{fh};
}
}
# Capturing/Logging code goes here...
} else {
$self->{fh}->print(@_);
}
}
1;
package main;
use My::Foo;
# [...]
use My::Log::Capture;
open my $stderr, '>&', *STDERR;
tie *STDERR, 'My::Log::Capture', (stderr => $stderr, [qw< My::Foo >]);
# My::Foo's STDERR output will be captured, everyone else's STDERR
# output will just be relayed.