我怎样才能进入 Perl 的打印? [英] How can I hook into Perl's print?

查看:38
本文介绍了我怎样才能进入 Perl 的打印?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是一个场景.你有大量的遗留脚本,都使用一个公共库.所述脚本使用打印"语句进行诊断输出.不允许对脚本进行任何更改 - 它们的范围很广,得到了他们的批准,并且早已离开了监督和控制的丰收谷.

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.

现在出现了一个新需求:现在必须将日志添加到库中.这必须自动且透明地完成,标准库的用户无需更改他们的脚本.公共库方法可以简单地添加日志记录调用;这是最简单的部分.困难的部分在于这些脚本的诊断输出始终使用打印"语句显示.必须存储此诊断输出,但同样重要的是,必须对其进行处理.

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.

作为这种处理的一个例子,图书馆应该只记录包含警告"、错误"、注意"或注意"字样的打印行.以下极其琐碎和人为的示例代码 (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 并创建您的自己的文件句柄将完成日志记录工作.– 卡米尔·基西尔

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 文档说你不能子类化它,到目前为止我的尝试都没有结果.有什么特别需要让 sublclassing IO::Handle 工作吗?标准的使用基类 '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 可以工作,如果您不做任何棘手的事情.如果您将 IO::Handle 的任何功能与绑定的 STDOUT 或 STDERR 一起使用,那么让它们可靠地工作基本上是一个废话 - 我找不到让 IO::Handle 的自动刷新方法在我的绑定上工作的方法处理.如果我在绑定手柄之前启用了自动冲洗,它将起作用.如果这对您有用,那么 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 是不能以这种方式工作的内置程序之一.覆盖 print 的困难在这个 perlmonk 的线程中有详细说明.

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天全站免登陆