我如何了解Perl的印刷品? [英] How can I hook into Perl's print?

查看:94
本文介绍了我如何了解Perl的印刷品?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是一个场景.您有大量的旧脚本,都使用一个公共库.所述脚本将"print"语句用于诊断输出.不允许对脚本进行任何更改-它们的范围很广,已经得到批准,并且早就离开了富有成效的监督和控制谷.

Here's a scenario. You have a large amount of legacy scripts, all using a common library. Said scripts use the 'print' statement for diagnostic output. No changes are allowed to the scripts - they range far and wide, have their approvals, and have long since left the fruitful valleys of oversight and control.

现在已经有了新的需求:现在必须将日志记录添加到库中.必须自动且透明地完成此操作,而标准库的用户无需更改其脚本.普通的库方法可以简单地添加日志调用.那是容易的部分.困难的部分在于,这些脚本的诊断输出始终使用"print"语句显示.此诊断输出必须存储,但同样重要的是要进行处理.

Now a new need has arrived: logging must now be added to the library. This must be done automatically and transparently, without users of the standard library needing to change their scripts. Common library methods can simply have logging calls added to them; that's the easy part. The hard part lies in the fact that diagnostic output from these scripts were always displayed using the 'print' statement. This diagnostic output must be stored, but just as importantly, processed.

作为此处理的一个示例,库只应记录包含单词"warning","error","notice"或"attention"的印刷行.下面的极其琐碎和人为的示例代码(tm)"将记录一些上述输出:

As an example of this processing, the library should only record the printed lines that contain the words 'warning', 'error', 'notice', or 'attention'. The below Extremely Trivial and Contrived Example Code (tm) would record some of said output:

sub CheckPrintOutput
{
    my @output = @_; # args passed to print eventually find their way here.
    foreach my $value (@output) {
         Log->log($value) if $value =~ /warning|error|notice|attention/i;
    }
}

(我想避免诸如实际应记录的内容",不应将打印用于诊断","perl糟透了"或此示例存在xy和z缺陷"之类的问题. .为了简洁和清楚起见,这已大大简化了.)

(I'd like to avoid such issues as 'what should actually be logged', 'print shouldn't be used for diagnostics', 'perl sucks', or 'this example has the flaws x y and z'...this is greatly simplified for brevity and clarity. )

基本问题归结为捕获和处理传递到打印的数据(或任何内置的perl,以及类似的推理方法).是否有可能?有什么办法可以干净地做吗?是否有任何带有钩子的日志记录模块可以帮助您执行此操作?还是像瘟疫这样应该避免的东西,而我应该放弃捕获和处理打印输出的东西?

The basic problem comes down to capturing and processing data passed to print (or any perl builtin, along those lines of reasoning). Is it possible? Is there any way to do it cleanly? Are there any logging modules that have hooks to let you do it? Or is it something that should be avoided like the plague, and I should give up on ever capturing and processing the printed output?

附加:必须跨平台运行-Windows和* nix都一样.脚本的运行过程必须与脚本的输出保持相同.

Additional: This must run cross-platform - windows and *nix alike. The process of running the scripts must remain the same, as must the output from the script.

其他附加项:在codelogic的答案注释中提出了一个有趣的建议:

Additional additional: An interesting suggestion made in the comments of codelogic's answer:

您可以继承 http://perldoc.perl.org/IO/Handle.html并创建您的 自己的文件句柄,它将完成日志记录工作. –卡米尔·基西尔(Kamil Kisiel)

You can subclass http://perldoc.perl.org/IO/Handle.html and create your own file handle which will do the logging work. – Kamil Kisiel

这样做可能有两个注意事项:

This might do it, with two caveats:

1)我需要一种方法将此功能导出到使用公共库的任何人.它必须自动应用到STDOUT,也可能自动应用到STDERR.

1) I'd need a way to export this functionality to anyone who uses the common library. It would have to apply automatically to STDOUT and probably STDERR too.

2) IO :: Handle 文档说您不能对其进行子类化,到目前为止,我的尝试一直没有结果.使子类IO :: Handle工作需要什么特殊的东西吗?标准的'use base'IO :: Handle'然后覆盖new/print方法似乎无济于事.

2) the IO::Handle documentation says that you can't subclass it, and my attempts so far have been fruitless. Is there anything special needed to make sublclassing IO::Handle work? The standard 'use base 'IO::Handle' and then overriding the new/print methods seem to do nothing.

最终看起来IO :: Handle是一个死胡同,但Tie :: Handle可以做到.感谢所有的建议;他们真的很好.我将尝试Tie :: Handle路线.如果它引起问题,我会回来的!

Final edit: Looks like IO::Handle is a dead end, but Tie::Handle may do it. Thanks for all the suggestions; they're all really good. I'm going to give the Tie::Handle route a try. If it causes problems I'll be back!

附录:请注意,经过一些处理后,我发现Tie :: Handle将起作用,如果您不做任何棘手的事情.如果您在绑定的STDOUT或STDERR上使用IO :: Handle的任何功能,则基本上是使它们可靠运行的方法-我找不到找到让IO :: Handle的autoflush方法在绑定上工作的方法处理.如果在系上手柄之前启用了自动刷新功能,它将可以正常工作.如果这样对您有用,那么Tie :: Handle路线可能是可以接受的.

Addendum: Note that after working with this a bit, I found that Tie::Handle will work, if you don't do anything tricky. If you use any of the features of IO::Handle with your tied STDOUT or STDERR, it's basically a crapshoot to get them working reliably - I could not find a way to get the autoflush method of IO::Handle to work on my tied handle. If I enabled autoflush before I tied the handle it would work. If that works for you, the Tie::Handle route may be acceptable.

推荐答案

有许多可以覆盖的内置程序(请参见 perlsub ).但是,print是无法以这种方式工作的内置程序之一. perlmonk的线程中详细介绍了覆盖print的困难.

There are a number of built-ins that you can override (see perlsub). However, print is one of the built-ins that doesn't work this way. The difficulties of overriding print are detailed at this perlmonk's thread.

但是,您可以

  1. 创建一个包
  2. 绑住手柄
  3. 选择此手柄.

现在,有几个人已经给出了基本框架,但是它看起来像这样:

Now, a couple of people have given the basic framework, but it works out kind of like this:

package IO::Override;
use base qw<Tie::Handle>;
use Symbol qw<geniosym>;

sub TIEHANDLE { return bless geniosym, __PACKAGE__ }

sub PRINT { 
    shift;
    # You can do pretty much anything you want here. 
    # And it's printing to what was STDOUT at the start.
    # 
    print $OLD_STDOUT join( '', 'NOTICE: ', @_ );
}

tie *PRINTOUT, 'IO::Override';
our $OLD_STDOUT = select( *PRINTOUT );

您可以用相同的方式覆盖printf:

You can override printf in the same manner:

sub PRINTF { 
    shift;
    # You can do pretty much anything you want here. 
    # And it's printing to what was STDOUT at the start.
    # 
    my $format = shift;
    print $OLD_STDOUT join( '', 'NOTICE: ', sprintf( $format, @_ ));
}

请参见 Tie :: Handle ,了解您可以覆盖STDOUT行为的全部内容

See Tie::Handle for what all you can override of STDOUT's behavior.

这篇关于我如何了解Perl的印刷品?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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