【发布时间】:2010-09-28 02:41:28
【问题描述】:
这是一个场景。你有大量的遗留脚本,都使用一个公共库。所述脚本使用“打印”语句进行诊断输出。不允许对脚本进行任何更改 - 它们的范围很广,得到了他们的批准,并且早已离开了富有成效的监督和控制谷。
现在出现了一个新需求:现在必须将日志记录添加到库中。这必须自动且透明地完成,标准库的用户无需更改他们的脚本。公共库方法可以简单地添加日志调用;这是容易的部分。困难的部分在于这些脚本的诊断输出总是使用“打印”语句显示的。必须存储此诊断输出,但同样重要的是,必须对其进行处理。
作为此处理的示例,库应仅记录包含“警告”、“错误”、“通知”或“注意”字样的打印行。下面的非常琐碎和人为的示例代码 (tm) 将记录一些所说的输出:
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 缺陷”等问题。 .为了简洁明了,这被大大简化了。)
基本问题归结为捕获和处理传递给打印(或任何 perl 内置,沿着这些推理)的数据。可能吗?有什么办法可以干净利落的吗?是否有任何带有钩子的日志记录模块可以让你做到这一点?还是像瘟疫一样应该避免,我应该放弃捕获和处理打印输出?
附加:这必须跨平台运行 - windows 和 *nix 一样。运行脚本的过程必须保持不变,脚本的输出也必须保持不变。
附加附加:在 codelogic 的答案的 cmets 中提出的一个有趣的建议:
您可以继承 http://perldoc.perl.org/IO/Handle.html 并创建您的 自己的文件句柄,它将完成日志记录工作。 – 卡米尔·基塞尔
这可能会做到,但有两个警告:
1) 我需要一种方法将此功能导出给使用公共库的任何人。它必须自动适用于 STDOUT,也可能适用于 STDERR。
2) the IO::Handle 文档说你不能子类化它,到目前为止我的尝试都没有结果。使子类化 IO::Handle 工作需要什么特别的东西吗?标准的 'use base 'IO::Handle' 然后覆盖 new/print 方法似乎什么都不做。
最终编辑:看起来 IO::Handle 是一个死胡同,但 Tie::Handle 可能会这样做。感谢所有的建议;他们都很好。我要试试 Tie::Handle 路线。如果它引起问题,我会回来!
附录:请注意,在稍微处理一下之后,我发现 Tie::Handle 会起作用,如果你不做任何棘手的事情的话。如果您将 IO::Handle 的任何功能与绑定的 STDOUT 或 STDERR 一起使用,那么让它们可靠地工作基本上是一个废话——我找不到让 IO::Handle 的 autoflush 方法在我的绑定上工作的方法处理。如果我在绑定手柄之前启用了自动冲洗,它会起作用。如果这对您有用,则 Tie::Handle 路线可能是可以接受的。
【问题讨论】:
-
那么是你允许改变什么?命令行?参数文件?例如,假设我说“是的,你可以挂钩打印”,你能做的范围是什么?
-
我可以更改公共库中的任何内容。用户必须不需要以任何不同的方式运行他的脚本,或者必须在命令行中传递任何新内容。 STDOUT 和 STDERR 上的最终数据流必须与之前相同。
-
原始输出会发生什么?你可以tail -f 并从那里处理吗?
-
原始输出由其他程序处理。他们希望它与以前一样。此外,正如下面另一条评论中所提到的,我们也不想改变环境——所以用另一个执行日志处理的程序来屏蔽“perl”是有问题的。