【问题标题】:Fast parser for logs日志的快速解析器
【发布时间】:2014-09-08 19:51:32
【问题描述】:

需要解析一些以空格(" ")作为分隔符的日志,并观察双引号或单引号。

例如

id=firewall time="2010-05-09 16:07:21 UTC" 1.1.1.1 ...

应该被解析为

id=firewall
time="2010-05-09 16:07:21 UTC"
1.1.1.1

日志是

  • 很长而且
  • 不一定是 key=value 格式
  • 不一定是 csv 格式:

尝试使用 Text::CSV_XS 因为它比纯基于 perl 的解析器快得多。但是,以下代码没有达到我的预期,因为日志不是有效的 csv 字符串。

use Text::CSV_XS;

$a = 'id=firewall time="2010-05-09 16:07:21 UTC"';

$userDefinedSeparator = Text::CSV_XS->new({sep_char => " "});
print "$userDefinedSeparator\n";
$userDefinedSeparator->parse($a);
my $e;
foreach $e ($userDefinedSeparator->fields) {
    print $e, "\n";
}

是否有可以解析上述日志的快速解析器?最好配置 Text::CSV_XS 来进行所需的解析。

感谢@ThisSuitIsBlackNot 建议重写此问题。

【问题讨论】:

  • 说明日志不是什么是没有帮助的:“不一定是 key=value 格式”“不一定是 csv 格式”我>。如果您想要有用的答案,您需要详细描述日志的格式。否则这个问题太宽泛而无法回答。
  • 如果您正在寻找“更快”的解决方案,您应该提供一些基准速度示例进行比较。
  • 这是一种标准的日志文件格式吗?如果是,是否有可以使用的现有解析器(即使它不在 perl 中)?
  • 感谢大家观看。同意你的观点,这个问题的表述不是很清楚。速度要求是解析应该在几微秒内完成。理想情况下,我希望小于 1us,但这可能需要 XS 代码。

标签: perl


【解决方案1】:

我在my response to your comment 中回答了我对您的previous question 的解决方案。

这是我之前给出的答案,以及你在这个问题中显示的新数据。

我对您上一个问题的问题是您只显示了 key=value 对,所以我认为这就是您数据中的全部内容。

我希望这对你有用。

use strict;
use warnings;

my $string = 'id=firewall time="2010-05-09 16:07:21 UTC" 1.1.1.1 ...';

my @fields = $string =~ / (?: "[^"]*" | \S )+ /xg;

print "$_\n" for @fields;

输出

id=firewall
time="2010-05-09 16:07:21 UTC"
1.1.1.1
...

【讨论】:

  • 感谢@Borodin,这个正则表达式解决了这个问题并且相当快:10us 来解析一个表达式。
  • 我真的不相信你对速度的追求。在您将该解析过程整合到一个可以满足您需要的程序中之前,您甚至无法开始寻找可以加快速度的瓶颈。你的日志文件有多大?十分钟内你可以处理 6000 万行,这对于一个日志文件来说是巨大的。在任何情况下,从磁盘文件读取的程序几乎肯定会受到磁盘速度的限制,而您对算法所做的任何事情都不会产生重大影响。 TL;DR - 在担心速度之前完成你的程序。
  • 你是对的,如果你看一下 10 毫秒的寻道时间,磁盘可能是一个巨大的瓶颈。但是你知道,日志也会来自网络,速度非常快:-)
  • @codingFunq:即便如此,在发现代码是否已经足够快运行以及优化工作应该集中在哪里之前优化代码是非常错误的。在这个阶段,您最关心的应该是编程的清晰度功能
  • 好点。最好在花时间进行优化之前进行分析(例如 Devel::NYTProf)。
【解决方案2】:

我有一半的把握,在我提交这个答案后,你会告诉我更多关于日志格式的信息,但这里就可以了。

只有您知道您的日志是什么样的。如果它们的格式是常规的,您将更容易解析它们。

但是鉴于您提供的内容,您可以将空格拆分为一个数组,然后重新组合时间戳:

 my $a = q(id=firewall time="2010-05-09 16:07:21 UTC" 1.1.1.1);
 my @f = split(/ /, $a);
 my $id = $f[0];
 my $time = join(' ', @f[1..3]));

 print "$id\n$time\n$f[4]\n";

【讨论】:

  • 感谢 Len 试一试。部分要求是观察字符串中的“”。
  • 在这种特殊情况下,my $time = join(' ', @f[1..3])); 将完成这项工作。但是,这只是其中一种情况,字符串可能看起来像 id=firewall date="2010-05-09" time="16:07:21" 1.1.1.1 或完全不同的东西。再次感谢您查看它。
猜你喜欢
  • 1970-01-01
  • 2016-05-16
  • 2017-01-06
  • 1970-01-01
  • 1970-01-01
  • 2011-01-26
  • 1970-01-01
  • 1970-01-01
  • 2014-10-14
相关资源
最近更新 更多