AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / server / 问题 / 11028
Accepted
deadprogrammer
deadprogrammer
Asked: 2009-05-22 14:14:23 +0800 CST2009-05-22 14:14:23 +0800 CST 2009-05-22 14:14:23 +0800 CST

你有任何有用的 awk 和 grep 脚本来解析 apache 日志吗?[关闭]

  • 772
关闭。这个问题需要更加集中。它目前不接受答案。

想改进这个问题?更新问题,使其仅通过编辑此帖子专注于一个问题。

7年前关闭。

改进这个问题

我可以使用日志分析器,但通常我需要解析最近的网络日志以查看当前发生的情况。

我有时会做一些事情,比如找出请求某个文件的前 10 个 ip

cat foo.log | grep request_to_file_foo | awk '{print $1}' |  sort -n | uniq -c | sort -rn | head

你的工具箱里有什么?

logging apache-2.2 grep awk parsing
  • 12 12 个回答
  • 149579 Views

12 个回答

  • Voted
  1. Best Answer
    Mark
    2009-06-03T18:21:56+08:002009-06-03T18:21:56+08:00

    您可以仅使用 awk 对 apache 日志文件执行任何操作。Apache 日志文件基本上是用空格分隔的,您可以假装引号不存在,并通过列号访问您感兴趣的任何信息。唯一出现这种情况的情况是,如果您具有组合日志格式并且对用户代理感兴趣,此时您必须使用引号 (") 作为分隔符并运行单独的 awk 命令。下面将向您显示每个请求索引页面的用户按点击次数排序:

    awk -F'[ "]+' '$7 == "/" { ipcount[$1]++ }
        END { for (i in ipcount) {
            printf "%15s - %d\n", i, ipcount[i] } }' logfile.log
    

    $7 是请求的网址。您可以在开头添加任何您想要的条件。将 '$7 == "/" 替换为您想要的任何信息。

    如果替换 (ipcount[$1]++) 中的 $1,则可以按其他条件对结果进行分组。使用 $7 将显示访问了哪些页面以及访问频率。当然,你会想在一开始就改变条件。以下将显示用户从特定 IP 访问了哪些页面:

    awk -F'[ "]+' '$1 == "1.2.3.4" { pagecount[$7]++ }
        END { for (i in pagecount) {
            printf "%15s - %d\n", i, pagecount[i] } }' logfile.log
    

    您还可以通过 sort 管道输出以按顺序获取结果,可以作为 shell 命令的一部分,也可以在 awk 脚本本身中:

    awk -F'[ "]+' '$7 == "/" { ipcount[$1]++ }
        END { for (i in ipcount) {
            printf "%15s - %d\n", i, ipcount[i] | sort } }' logfile.log
    

    如果您决定扩展 awk 脚本以打印出其他信息,后者会很有用。这完全取决于你想知道什么。这些应该作为您感兴趣的任何内容的起点。

    • 61
  2. Dan Udey
    2009-06-06T13:46:45+08:002009-06-06T13:46:45+08:00

    由于我无法想象的原因,我从未见过其他人做的一件事是将 Apache 日志文件格式更改为更易于解析的版本,其中包含对您而言真正重要的信息。

    例如,我们从不使用 HTTP 基本身份验证,因此我们不需要记录这些字段。我对每个请求的服务时间很感兴趣,因此我们将其添加进去。对于一个项目,我们还想知道(在我们的负载均衡器上)是否有任何服务器服务请求的速度比其他服务器慢,所以我们记录名称我们代理回的服务器。

    这是一个服务器的 apache 配置的摘录:

    # We don't want to log bots, they're our friends
    BrowserMatch Pingdom.com robot
    
    # Custom log format, for testing
    #
    #         date          proto   ipaddr  status  time    req     referer         user-agent
    LogFormat "%{%F %T}t    %p      %a      %>s     %D      %r      %{Referer}i     %{User-agent}i" standard
    CustomLog /var/log/apache2/access.log standard env=!robot
    

    您无法从中真正看出的是,每个字段之间是一个文字制表符 (\t)。这意味着如果我想在 Python 中进行一些分析,例如可能显示非 200 状态,我可以这样做:

    for line in file("access.log"):
      line = line.split("\t")
      if line[3] != "200":
        print line
    

    或者如果我想做“谁在盗链图像?” 这将是

    if line[6] in ("","-") and "/images" in line[5]:
    

    对于访问日志中的 IP 计数,前面的示例:

    grep -o "[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}" logfile | sort -n | uniq -c | sort -n
    

    变成这样:

    cut -f 3 log | uniq -c | sort -n
    

    更容易阅读和理解,而且计算成本要低得多(没有正则表达式),在 9 GB 的日志上,它需要多长时间有很大的不同。如果你想为用户代理做同样的事情,这真的很整洁。如果您的日志是用空格分隔的,则必须手动进行一些正则表达式匹配或字符串搜索。使用这种格式,很简单:

    cut -f 8 log | uniq -c | sort -n
    

    和上面的完全一样。其实,任何你想做的总结,本质上都是一模一样的。

    为什么我要把系统的 CPU 用在 awk 和 grep 上,而 cut 将完全按照我想要的速度快几个数量级?

    • 25
  3. Vihang D
    2009-06-05T18:22:31+08:002009-06-05T18:22:31+08:00

    忘记 awk 和 grep。查看asql。当您可以使用类似 sql 的语法来查询日志文件时,为什么还要编写不可读的脚本。例如。

    asql v0.6 - type 'help' for help.
    asql> load /home/skx/hg/engaging/logs/access.log
    Loading: /home/skx/hg/engaging/logs/access.log
    sasql> select COUNT(id) FROM logs
    46
    asql> alias hits SELECT COUNT(id) FROM logs
    ALIAS hits SELECT COUNT(id) FROM logs
    asql> alias ips SELECT DISTINCT(source) FROM logs;
    ALIAS ips SELECT DISTINCT(source) FROM logs;
    asql> hits
    46
    asql> alias
    ALIAS hits SELECT COUNT(id) FROM logs
    ALIAS ips SELECT DISTINCT(source) FROM logs;
    
    • 17
  4. anoopjohn
    2011-11-28T06:03:38+08:002011-11-28T06:03:38+08:00

    这是一个从最近的 N 个日志条目中查找顶级 url、顶级引用和顶级用户代理的脚本

    #!/bin/bash
    # Usage
    # ls-httpd type count
    # Eg: 
    # ls-httpd url 1000
    # will find top URLs in the last 1000 access log entries
    # ls-httpd ip 1000
    # will find top IPs in the last 1000 access log entries
    # ls-httpd agent 1000
    # will find top user agents in the last 1000 access log entries
    
    type=$1
    length=$2
    
    if [ "$3" == "" ]; then
      log_file="/var/log/httpd/example.com-access_log"
    else
      log_file="$3"
    fi
    
    if [ "$type" = "ip" ]; then
      tail -n $length $log_file | grep -o "[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}" | sort -n | uniq -c | sort -n
    elif [ "$type" = "agent" ]; then
      tail -n $length $log_file | awk -F\" '{print $6}'| sort -n | uniq -c | sort -n
    elif [ "$type" = "url" ]; then
      tail -n $length $log_file | awk -F\" '{print $2}'| sort -n | uniq -c | sort -n
    fi
    

    资源

    • 8
  5. f4nt
    2009-05-22T18:19:11+08:002009-05-22T18:19:11+08:00

    对于访问日志中的 IP 计数:

    cat log | grep -o "[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}" | sort -n | uniq -c | sort -n
    

    这有点难看,但它有效。我还将以下内容与 netstat 一起使用(查看活动连接):

    netstat -an | awk '{print $5}' | grep -o "[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}" | egrep -v "(`for i in \`ip addr | grep inet |grep eth0 | cut -d/ -f1 | awk '{print $2}'\`;do echo -n "$i|"| sed 's/\./\\\./g;';done`127\.|0\.0\.0)" | sort -n | uniq -c | sort -n
    

    它们是我最喜欢的“单衬里” :)

    • 5
  6. Kris
    2011-03-30T07:40:51+08:002011-03-30T07:40:51+08:00

    这是我的“sed”示例,它读取 apache 日志的默认格式并将其转换为更方便自动处理的格式。整行定义为正则表达式,变量被保存并以“#”作为分隔符写入输出。

    输入的简化表示法是: %s %s %s [%s] "%s" %s %s "%s" "%s"

    示例输入行:xx.xx.xx.xx - - [29/Mar/2011:12:33:02 +0200] "GET /index.html HTTP/1.0" 200 9443 "-" "Mozilla/4.0"

    示例输出行:xx.xx.xx.xx#-#-#29/Mar/2011:12:33:02 +0200#GET /index.html HTTP/1.0#200#9443#-#Mozilla/4.0

    cat access.log | \ 
      sed 's/^\(.*\) \(.*\) \(.*\) \[\(.*\)\] \"\(.*\)\" \(.*\) \(.*\) \"\(.*\)\" \"\(.*\)\"$/\1#\2#\3#\4#\5#\6#\7#\8#\9/g'
    

    感受正则表达式的力量:-)

    • 4
  7. ericslaw
    2009-06-06T13:34:03+08:002009-06-06T13:34:03+08:00

    建立一个常见问题列表将是这个问题的答案的一个很好的索引。我的常见问题是:

    • 为什么命中率发生了变化?
    • 为什么整体响应时间会增加?

    我通过监视服务器状态页面(通过 mod_status)的命中率以及活动和最近完成的请求的大致响应时间来注意到这些变化(我完全清楚我错过了一大堆数据,但样本已经足够好了)。

    我使用以下 LogFormat 指令(%T 非常有用)

    LogFormat "%h %l %u %t \"%r\" %>s %b 
        \"%{Referer}i\" \"%{User-Agent}i\" %T" custom
    

    我正在寻找因果关系以及首先发生的事情......通常是关于我的日志中特定的模式子集,因此对于任何给定的模式/正则表达式,我需要了解以下内容:

    • 给定模式(IP 地址或 cgi 字符串或参数等)的每个间隔(分钟或小时)的命中计数
    • 近似响应时间的直方图(使用 %T 参数)

    我通常使用 perl,因为最终它变得足够复杂以至于值得。


    一个非 perl 示例将是非 200 状态代码的每分钟快速命中率:

    tail -9000 access_log | grep -v '" 200 ' | cut -d: -f2,3 | uniq -c
    

    是的,我在用那个 grep 作弊,假设 quote-space-200-space 只匹配 http 状态代码......可以使用 awk 或 perl 来隔离该字段,但请记住它可能不准确。


    perl 中更复杂的示例可能是可视化模式的命中率变化。

    下面的脚本有很多内容需要细细琢磨,尤其是如果您不熟悉 perl。

    • 读取标准输入,因此您可以使用部分日志,使用tail(尤其是tail -f),有或没有greps和其他过滤......
    • 通过破解正则表达式和使用 Date::Manip 来欺骗时代时间戳提取
    • 您可以稍微修改它以提取响应时间或其他任意数据

    代码如下:

    #!/usr/bin/perl
    # script to show changes in hitrates for any regex pattern
    # results displayed with arbitrary intervals
    # and ascii indication of frequency
    # gaps are also displayed properly
    use Date::Manip;
    use POSIX qw(strftime);
    $pattern=shift || ".";
    $ival=shift || 60;
    $tick=shift || 10;
    $minb=undef;
    while (<>){
        next unless /$pattern/;
        $stamp="$1 $2" if m[(../.../....):(..:..:..)];
        $epoch = UnixDate(ParseDate($stamp),"%s");
        $bucket= int($epoch/$ival)*$ival;
        $minb=$bucket if $bucket<$minb || !defined($minb);
        $maxb=$bucket if $bucket>$maxb;
        $count{$bucket}++;
    }
    # loop thru the min/max range to expose any gaps
    for($t=$minb;$t<=$maxb;$t+=$ival){
        printf "%s %s %4d %s\n",
                $t,
                strftime("%m/%d/%Y %H:%M:%S",localtime($t)),
                $count{$t}+0,
                substr("x"x100,0,$count{$t}/$tick
        );
    }
    

    如果您只想处理标准指标,请查看

    • 'mergelog' 将所有日志放在一起(如果负载均衡器后面有多个 apache)和
    • webalizer(或 awstats 或其他常用分析器)。
    • 3
  8. rkthkr
    2009-06-06T06:05:42+08:002009-06-06T06:05:42+08:00

    谁在热链接您的图像:

    awk -F\" '($2 ~ /\.(jpg|gif)/ && $4 !~ /^http:\/\/www\.mydomain\.com/){print $4}' access_log | sort | uniq -c | sort
    
    • 2
  9. Michael Steinfeld
    2011-11-19T19:19:57+08:002011-11-19T19:19:57+08:00

    我通过拖尾或 cat'ing 文件来大量使用 awk。每天晚上,我都会为每台服务器提供一份网络报告。根据您的日志文件和您的 LogFormat,您需要编辑其中一些为您工作的衬垫......

    这是一个简单的例子:

    如果我只想在我的服务器上跟踪日志以获取 404/500 状态代码,我会这样做:

    # $6 is the status code in my log file
    
    tail -f ${APACHE_LOG} |  awk  '$8 ~ /(404|500)/ {print $6}'
    

    <剪辑>

    echo ""
    #echo  "Hits by source IP:"
    echo "======================================================================"
    
    awk '{print $2}' "$1" | grep -ivE "(127.0.0.1|192.168.100.)" | sort | uniq -c | sort -rn | head -25
    
    echo ""
    echo ""
    #echo "The 25 most popular pages:"
    echo "======================================================================"
    
    awk '{print $6}' "$1" | grep -ivE '(mod_status|favico|crossdomain|alive.txt)' | grep -ivE '(.gif|.jpg|.png)' | \
     sed 's/\/$//g' | sort | \
     uniq -c | sort -rn | head -25
    
    echo ""    
    echo ""
    echo "The 25 most popular pages (no js or css):"
    echo "======================================================================"
    
    awk '{print $6}' "$1" | grep -ivE '(mod_status|favico|crossdomain|alive.txt)' | grep -ivE '(.gif|.jpg|.png|.js|.css)' | \
     sed 's/\/$//g' | sort | \
       uniq -c | sort -rn | head -25
    
       echo ""
    
    
    #echo "The 25 most common referrer URLs:"
    echo "======================================================================"
    
    awk '{print $11}' "$1" | \
     grep -vE "(^"-"$|/www.$host|/$host)" | \
     sort | uniq -c | sort -rn | head -25
    
    echo ""
    
    #echo "Longest running requests"
    echo "======================================================================"
    
    awk  '{print $10,$6}' "$1" | grep -ivE '(.gif|.jpg|.png|.css|.js)'  | awk '{secs=0.000001*$1;req=$2;printf("%.2f minutes req time for %s\n", secs / 60,req )}' | sort -rn | head -50
    
    exit 0
    

    </snip>

    • 2
  10. Chris
    2012-05-29T14:28:01+08:002012-05-29T14:28:01+08:00

    我大部分时间都在做的事情是根据时间读取日志的各个部分,所以我使用 sed 编写了以下脚本来提取我感兴趣的时间段,它适用于我来到的每个日志文件并且还可以处理归档日志。

    #!/bin/bash
    #这个脚本应该返回2个值之间的一组行,主要目的是搜索2次之间的日志文件
    #脚本用法:logship.sh "start" "stop" 文件
    
    #如果文件在日期范围内包含任何“/”,则以下两行添加转义字符,以便可以对这些字符执行搜索
    start=$(echo "$1" | sed 's/\//\\\//g')
    停止=$(echo "$2" | sed 's/\//\\\//g')
    
    zipped=$(echo "$3" | grep -c "gz$") #判断文件是否被压缩
    
    如果 [ "$zipped" == "1" ]; then #如果文件被压缩然后在sed之前通过zcat
            零猫 $3 | sed -n "/$start/,/$stop/p";
    别的
            sed -n "/$start/,/$stop/p" $3; #如果没有压缩就运行 sed
    菲
    
    • 1

相关问题

  • 在您分发的应用程序中使用 Apache HTTPD 运行 SSL 的最佳方式是什么?

  • 阿帕奇的替代品

  • 如何强制我的网址始终以 www 开头?

  • 在 Linux Xen VPS 上优化 Apache 和 MySQL

  • mod_rewrite 不转发 GET 参数

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    SFTP 使用什么端口?

    • 6 个回答
  • Marko Smith

    从 IP 地址解析主机名

    • 8 个回答
  • Marko Smith

    如何按大小对 du -h 输出进行排序

    • 30 个回答
  • Marko Smith

    命令行列出 Windows Active Directory 组中的用户?

    • 9 个回答
  • Marko Smith

    Windows 中执行反向 DNS 查找的命令行实用程序是什么?

    • 14 个回答
  • Marko Smith

    如何检查 Windows 机器上的端口是否被阻塞?

    • 4 个回答
  • Marko Smith

    我应该打开哪个端口以允许远程桌面?

    • 9 个回答
  • Marko Smith

    什么是 Pem 文件,它与其他 OpenSSL 生成的密钥文件格式有何不同?

    • 3 个回答
  • Marko Smith

    如何确定bash变量是否为空?

    • 15 个回答
  • Martin Hope
    MikeN 在 Nginx 中,如何在维护子域的同时将所有 http 请求重写为 https? 2009-09-22 06:04:43 +0800 CST
  • Martin Hope
    Tom Feiner 如何按大小对 du -h 输出进行排序 2009-02-26 05:42:42 +0800 CST
  • Martin Hope
    0x89 bash中的双方括号和单方括号有什么区别? 2009-08-10 13:11:51 +0800 CST
  • Martin Hope
    kch 如何更改我的私钥密码? 2009-08-06 21:37:57 +0800 CST
  • Martin Hope
    Kyle Brandt IPv4 子网如何工作? 2009-08-05 06:05:31 +0800 CST
  • Martin Hope
    Noah Goodrich 什么是 Pem 文件,它与其他 OpenSSL 生成的密钥文件格式有何不同? 2009-05-19 18:24:42 +0800 CST
  • Martin Hope
    Brent 如何确定bash变量是否为空? 2009-05-13 09:54:48 +0800 CST
  • Martin Hope
    cletus 您如何找到在 Windows 中打开文件的进程? 2009-05-01 16:47:16 +0800 CST

热门标签

linux nginx windows networking ubuntu domain-name-system amazon-web-services active-directory apache-2.4 ssh

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve