【问题标题】:AWK: compare apache dates without using regular expressionAWK:比较 apache 日期而不使用正则表达式
【发布时间】:2011-02-19 23:07:44
【问题描述】:

我正在编写一个日志分析应用程序,并希望在两个特定日期之间获取 apache 日志记录。假设日期格式如下:22/Dec/2009:00:19 (day/month/year:hour:minute)

目前,我正在使用正则表达式将月份名称替换为其数值,删除分隔符,因此上述日期转换为:221220090019 使日期比较变得微不足道.. 但是..

对大文件的每条记录运行正则表达式,比如包含 25 万条记录的记录,成本非常高。还有其他不涉及正则表达式替换的方法吗?

提前致谢

编辑:这是进行转换/比较的函数

function dateInRange(t, from, to) {
    sub(/[[]/, "", t);
    split(t, a, "[/:]");
    match("JanFebMarAprMayJunJulAugSepOctNovDec", a[2]);
    a[2] = sprintf("%02d", (RSTART + 2) / 3);
    s = a[3] a[2] a[1] a[4] a[5];

    return s >= from && s <= to;
}

“from”和“to”是上述格式的间隔,“t”是原始 apache 日志日期/时间字段(例如 [22/Dec/2009:00:19:36)

【问题讨论】:

  • 也许除了您的要求之外,但是当 ISO 8601 即200912220019 有这么多好处时,您到底为什么想要拥有221220090019en.wikipedia.org/wiki/ISO_8601
  • 真的没有想过......这些好处与易于比较/性能有关吗?大多数记录都在同一年、月、日和(偶尔)同一小时内,所以也许是的?
  • 在您的情况下,最重要的好处是 ISO 8601 的时间顺序和字母顺序变得相同。它使年龄排序变得非常简单。也许这不是您现在需要的东西,但请帮自己一个忙,开始使用 8601 做所有事情,除非您有充分的理由不这样做。其他福利也列在cl.cam.ac.uk/~mgk25/iso-time.html

标签: regex apache awk logging


【解决方案1】:

我曾经遇到过一个涉及正则表达式的非常慢的 AWK 程序的问题。当我将整个程序翻译成 Perl 时,它的运行速度要快得多。我猜这是因为 GNU AWK 每次解释表达式时都会编译一个正则表达式,而 perl 只编译一次表达式。

【讨论】:

  • 第二。 awk 非常有趣,但 Perl 快得多。对于仅分析日志文件,请考虑使用任何专用和 快速 工具,例如 Analog。
  • 没错,Perl 速度更快,但我选择 AWK 是因为方便:它比 sun 更老,并且随每个 *nix 一起提供,所以我可以放心地假设它已经安装。珀尔;不太确定。如果要分发应用程序,我必须使用最低分母。此外,在处理文本数据时,Perl 在简单性和简洁性方面无法与 AWK 相提并论(请注意,我的 Perl 能力有限)
【解决方案2】:

好吧,这是一个想法,假设日志中的记录是按日期排序的。

不要在文件的每一行上运行正则表达式并检查该记录是否在要求的范围内,而是执行binary search

获取文件中的总行数。从中间读取一行并检查其日期。如果它早于您的范围 - 那么该行之前的任何内容都可以忽略。把剩下的分成两半,然后再从中间检查一条线。依此类推,直到找到范围边界。

【讨论】:

    【解决方案3】:

    Here is a Python program I wrote 根据日期对日志文件进行二进制搜索。它可以适应您的使用。

    它寻找文件的中间,然后同步到换行符,读取并比较日期,重复将前一半分成两半的过程,这样做直到日期匹配(大于或等于),倒回以确保之前没有相同日期的,然后读取并输出行,直到所需范围的末尾。速度非常快。

    我正在开发一个更高级的版本。最终我会完成它并发布更新版本。

    【讨论】:

      【解决方案4】:

      仅仅为了识别一个范围而截取文件对于这样一个简单的任务来说听起来有点笨拙(不过,二进制搜索值得考虑)

      这是我修改后的函数,由于消除了正则表达式

      ,这显然要快得多
      BEGIN {
          months["Jan"] = 1
          months["Feb"] = 2
          ....
          months["Dec"] = 12
      }
      function dateInRange(t, from, to) {
          split(t, a, "[/:]");
          m = sprintf("%02d", months[a[2]]);
          s = a[3] m a[1] a[4] a[5];
          ok = s >= from && s <= to;
          if(!ok && seen == 1){exit;}
          return ok;
      }
      

      定义了一个数组,随后用于索引月份。 确保一旦日期超出范围,程序不会继续检查记录(变量 seen 在第一次匹配时设置)

      感谢大家的投入。

      【讨论】:

        猜你喜欢
        • 2011-08-01
        • 2012-10-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-12-21
        相关资源
        最近更新 更多