2012-07-12 38 views
2

我需要與某些不幸將診斷 消息記錄到STDOUT和STDERR的庫一起工作。通過使用tie,我可以將這些寫入到一個捕獲這些函數的函數中。由於我不希望所有 我的程序的STDOUT和STDERR輸出通過 捆綁手柄被捕獲,我只想爲某些包執行此操作。如何使用tie()重定向STDOUT,STDERR僅適用於某些包?

我想出了在實際行爲是通過看來電顯示()作爲可以看到下面確定 一個解決方案,但我有一種感覺 認爲必須有一個更好的辦法?有沒有更優雅的方案?

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. 

回答

2

除了修復這些庫之外,我只能想到一種解決方案可能更好。

您可以將STDOUTSTDERR文件句柄重新打開到您自己的文件句柄中。然後,用你的繫帶手柄重新打開STDOUTSTDERR

例如,這裏是你如何對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

無論如何,您可以用「/tmp/test.txt」替代打開的調用和綁定文件句柄的設置。

您的代碼必須始終使用明確的文件句柄編寫或使用select切換文件句柄:

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

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

順便說一句,如果你只需要擔心'STDOUT',你也許可以做到這隻用'select'。 – zostay 2012-07-13 12:14:06

+0

感謝您指點我'選擇'。 – hillu 2012-07-15 12:49:54

相關問題