【问题标题】:Processing apache logs quickly快速处理 apache 日志
【发布时间】:2011-01-08 01:38:14
【问题描述】:

我目前正在运行一个 awk 脚本来处理一个大型 (8.1GB) 访问日志文件,而且它需要很长时间才能完成。在 20 分钟内,它写入了我期望它写入的 (1000 +- 500)MB 中的 14MB,我想知道我是否可以以某种方式更快地处理它。

这里是 awk 脚本:

#!/bin/bash awk '{t=$4" "$5; gsub("[\[\]\/]","",t); sub(":"," ",t);printf("%s,",$1);system("date -d \""t"\" +%s");}' $1

编辑:

对于非 awker,脚本读取每一行,获取日期信息,将其修改为实用程序 date 识别的格式,并调用它将日期表示为自 1970 年以来的秒数,最后将其返回为.csv 文件的一行,以及 IP。

示例输入: 189.5.56.113 - - [22/Jan/2010:05:54:55 +0100] "GET (...)"

返回输出: 189.5.56.113,124237889

【问题讨论】:

  • 也许您可以描述脚本的作用,以便我们这些非 awker 可以用另一种语言编写更快的替换?不过乍一看,通过 system() 在每条记录上生成一个新进程肯定很慢。

标签: apache awk large-data-volumes


【解决方案1】:

如果你真的需要它更快,你可以做我做的。我使用 Ragel 重写了一个 Apache 日志文件分析器。 Ragel 允许您将正则表达式与 C 代码混合。正则表达式被转换成非常高效的 C 代码,然后被编译。不幸的是,这要求您非常舒服用 C 编写代码。我不再拥有这个分析器。它在 1 或 2 秒内处理了 1 GB 的 Apache 访问日志。

从 awk 语句中删除不必要的 printfs 并用更简单的东西替换它们可能会取得有限的成功。

【讨论】:

    【解决方案2】:

    如果您使用gawk,您可以将您的日期和时间转换为mktimegawk 函数)可以理解的格式。它将为您提供与您现在使用的相同的时间戳,并为您节省重复的system() 调用的开销。

    【讨论】:

      【解决方案3】:

      这个 Python 小脚本在我的机器上大约 3 分钟内处理了价值约 400MB 的示例行副本,产生了约 200MB 的输出(请记住,您的示例行很短,所以这是一个障碍):

      import time
      
      src = open('x.log', 'r')
      dest = open('x.csv', 'w')
      
      for line in src:
          ip = line[:line.index(' ')]
          date = line[line.index('[') + 1:line.index(']') - 6]
          t = time.mktime(time.strptime(date, '%d/%b/%Y:%X'))
          dest.write(ip)
          dest.write(',')
          dest.write(str(int(t)))
          dest.write('\n')
      
      src.close()
      dest.close()
      

      一个小问题是它不处理时区(strptime() 问题),但您可以对其进行硬编码或添加一些额外内容来处理它。

      但老实说,这么简单的东西用 C 重写应该一样容易。

      【讨论】:

        【解决方案4】:

        @OP,你的脚本很慢,主要是因为对文件中的每一行都过度调用系统日期命令,而且它也是一个大文件(以 GB 为单位)。如果您有 gawk,请使用其内部 mktime() 命令将日期转换为纪元秒

        awk 'BEGIN{
           m=split("Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec",d,"|")
           for(o=1;o<=m;o++){
              date[d[o]]=sprintf("%02d",o)
            }
        }
        {
            gsub(/\[/,"",$4); gsub(":","/",$4); gsub(/\]/,"",$5)
            n=split($4, DATE,"/")
            day=DATE[1]
            mth=DATE[2]
            year=DATE[3]
            hr=DATE[4]
            min=DATE[5]
            sec=DATE[6]
            MKTIME= mktime(year" "date[mth]" "day" "hr" "min" "sec)
            print $1,MKTIME
        
        }' file
        

        输出

        $ more file
        189.5.56.113 - - [22/Jan/2010:05:54:55 +0100] "GET (...)"
        $ ./shell.sh    
        189.5.56.113 1264110895
        

        【讨论】:

        • 删除 system() 调用让我的程序快了 10 倍!
        【解决方案5】:
        gawk '{
            dt=substr($4,2,11); 
            gsub(/\//," ",dt); 
            "date -d \""dt"\" +%s"|getline ts; 
            print $1, ts
        }' yourfile
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-04-23
          • 2014-02-19
          • 2019-04-08
          • 1970-01-01
          相关资源
          最近更新 更多