如何使用tie()重定向STDOUT,STDERR仅用于某些程序包? [英] How can I use tie() to redirect STDOUT, STDERR only for certain packages?

查看:106
本文介绍了如何使用tie()重定向STDOUT,STDERR仅用于某些程序包?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要使用一些不幸记录日志诊断的库 消息发送到STDOUT和STDERR.通过使用tie,我可以重定向那些 写一个捕获那些的函数.因为我不想要所有 我的程序的STDOUT和STDERR输出将通过 绑手柄,我只想对某些包裹这样做.

I need to work with some libraries that unfortunately log diagnostic messages to STDOUT and STDERR. By using tie, I can redirect those writes to a function that captures those. Since I don't want all STDOUT and STDERR output of my programs to be captured thtough the tied handle, I'd like to do this only for certain packages.

我想出了一个确定实际行为的解决方案 通过查看如下所示的caller(),但我有感觉 必须有更好的方法...还有更优雅的解决方案吗?

I have come up with a solution where the actual behavior is determined by looking at caller() as can be seen below, but I have the feeling that there has to be a better way... Is there a more elegant solution?

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.

推荐答案

除了修复库之外,我只能想到一种可能更好的解决方案.

Aside from fixing the libraries, I can think of only one solution that might be better.

您可以将STDOUTSTDERR文件句柄重新打开到您自己的文件句柄中.然后,用捆绑的手柄重新打开STDOUTSTDERR.

You can re-open STDOUT and STDERR file handles into your own file handles. Then, re-open STDOUT and STDERR with your tied handles.

例如,以下是STDOUT的操作方法:

For example, here's how you do it for STDOUT:

open my $fh, ">&", \*STDOUT or die "cannot reopen STDOUT: $!";
close STDOUT; 

open STDOUT, ">", "/tmp/test.txt"; 

say $fh "foo"; # goes to real STDOUT
say "bar";     # goes to /tmp/test.txt

您可以阅读 perldoc -f open 了解有关> &"就是这样.

You can read perldoc -f open for all the gory details on what ">&" and such does.

无论如何,您可以用绑定文件句柄的设置代替该打开的调用,而不是"/tmp/test.txt".

Anyway, instead of "/tmp/test.txt" you can replace that open call with the setup for your tied file handle.

您的代码将必须始终使用显式文件句柄来编写或使用选择切换文件句柄:

Your code will have to always use an explicit file handle to write or use select to switch file handles:

select $fh;
say "foo"; # goes to real STDOUT

select STDOUT;
say "bar"; # goes to /tmp/test.txt

这篇关于如何使用tie()重定向STDOUT,STDERR仅用于某些程序包?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆