Apacheログの解析に役立つawkおよびgrepスクリプトはありますか?[閉まっている]


69

ログアナライザーを使用できますが、多くの場合、最近のWebログを解析して、現在何が起こっているのかを確認する必要があります。

特定のファイルを要求する上位10個のipsを把握したいことがあります

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

ツールボックスには何がありますか?


1
実際に、Apacheカスタムログをすべて個別のフィールドに解析してデータベースに送信するために、手で書いたこの大きな美しい正規表現がありました。私はもう持っていないことを自慢しています。それは1つのライナーでした。各ログ要素に対して1つの変数を返しました-その後、MySQLに挿入しました。見つかったら、ここに投稿します。
カイルホジソン

回答:


54

awacheだけでapacheログファイルを使ってほとんど何でもできます。Apacheログファイルは基本的に空白で区切られており、引用符が存在しないふりをして、列番号で興味のある情報にアクセスできます。これが壊れるのは、ログ形式が組み合わされており、ユーザーエージェントに関心がある場合のみです。その時点で、区切り文字として引用符( ")を使用し、別のawkコマンドを実行する必要があります。ヒット数でソートされたインデックスページをリクエストするすべてのユーザー:

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

$ 7は要求されたURLです。最初に必要な条件を追加できます。'$ 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

また、シェルコマンドの一部として、またはawkスクリプト自体のいずれかで、ソートを介して出力をパイプ処理して、結果を順番に取得することもできます。

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

後者は、awkスクリプトを展開して他の情報を出力することにした場合に役立ちます。それはすべてあなたが知りたいことの問題です。これらは、あなたが興味を持っているものの出発点として役立つはずです。


うん、クレイジーで長いcat / grep / awkパイプラインを見るのはいつも奇妙に思えます。awkに入ったら、通常はそれで十分です。元の投稿の最初の3つの節は、「awk '/ request_to_file_foo / {print $ 1}' foo.log」と簡単に書くことができます。awkはファイルを入力として受け取り、regexを使用してどの行を気にするかを知ることができます。
ザックトンプソン

エレガントでシンプル。良い。
オリビエデュラック

;-)私たちはこれをやってできるように、すべてのものを破る「AUTHUSER」(第3回)フィールドで許可され、私は個人的には禁止されるべきだと思うようだスペース、用心
Mandark

23

私が想像することのできない理由で、他の誰も見たことのないことの1つは、Apacheログファイル形式を、実際に重要な情報を含むより簡単に解析可能なバージョンに変更することです。

たとえば、HTTP基本認証は使用しないため、これらのフィールドを記録する必要はありません。私は午前各要求がサービスを提供するのにかかる時間の長さに興味を持って、私たちは中にそれを追加します。1つのプロジェクトでは、我々はまた、すべてのサーバーが遅く、他のものより要求にサービスを提供している場合(当社のロードバランサに)知っているしたいので、名前をログに記録しますプロキシするサーバーの

これは、1つのサーバーの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が正確に何桁も速くしたいのに、どうしてですか?


2
新しい形式の例は実際にはまだ複雑すぎます。IPカウントcut -f 3 log | uniq -c | sort -nはユーザーエージェントになりますcut -f 8 log | uniq -c | sort -n
クレシャル

あなたは正しい、それは簡単です。それを反映するように例を更新しました。
ダンウデイ

「cat file | grep string」は役に立たない、なぜ「grep string file」ではないのか?
c4f4t0r

2
言い訳はありませんが、それに応じて例を更新しました。
ダンUdey

15

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;

おもしろいですが、ログが特に大きいと問題が発生する可能性があります。また、カスタムログ形式にどの程度対応していますか?
ヴァグナー09年

現時点では試していますが、ロード時間が非常に遅いです(少なくともバージョン0.9では)。200MBのは、それが5分以上を取るのログロード...
aseques

ロード時間(約15分かかりました)の後、このプログラムの構文は優れているため、並べ替え、カウント、グループ化できます。すごくいい。
aseques

Apache HTTPDには、ログをデータベースに効率的に送信できるメソッドがあります。はい、書き込みには時間がかかる場合がありますが、スレッド化されたプロキシは中間に挟まれた正しいことを行う場合があります。とにかく、これにより、構文のようなSQLでのログのクエリがはるかに高速になります。読み込みも必要ありません-データベースサーバーは常に「ON」です。
-nearora

6

最近の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

ソース


4

アクセスログの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

彼らは私のお気に入りの「ライナー」の一部です:)


3

一般的な質問のリストを作成することは、この質問に対するこの回答の優れたインデックスになります。私のよくある質問は次のとおりです。

  • なぜヒットレートが変わったのですか?
  • 全体的な応答時間が増加しているのはなぜですか?」

アクティブなリクエストと最近完了したリクエストのヒット率とおおよその応答時間をサーバーステータスページ(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以外のステータスコードの1分あたりのクイックヒット率です。

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

はい、quote-space-200-spaceがhttpステータスコードのみに一致すると仮定して、そのgrepでごまかしています。


perlのより複雑な例は、パターンのヒット率の変化を視覚化することです。

特にperlに慣れていない場合は、以下のスクリプトで多くを噛む必要があります。

  • stdinを読み込むので、ログの一部を使用したり、tail(特にtail -fを使用)を使用したり、grepやその他のフィルタリングを使用したり、使用したりできません。
  • 正規表現のハックと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」(ロードバランサーの背後に複数のアパッチがある場合)
  • webalizer(またはawstatsまたはその他の一般的なアナライザー)。

3

ここで私の「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'

正規表現の力を感じてください:-)


これにより、AWKでの処理が簡単になりました。一般的なデリミネーターをセットアップする簡単な方法を探していたので、これを打ちました。
Citricguy 14年

私は正規表現の力を感じたので、「HTML / 1.1」を切り取り、プロトコルを(おそらく非標準に準拠した方法で)独自のフィールドに分離する、独自の調整を行いたいと思いました。お楽しみください: `` `cat access.log | sed 's /^(.*)(。*)(。*)[(。*)] \ "([[:alpha:]] \ +)(。*)HTTP \ / 1 \ .1 \"( 。*)(。*)\ "(。*)\" \ "(。*)\" $ / \ 1#\ 2#\ 3#\ 4#\ 5#\ 6#\ 7#\ 8#\ 9#\ 10 / g '`` `
ジョシュランバット

2

私はファイルをテーリングまたはcat'ingすることでawkをよく使います。毎晩、各サーバーのWebレポートを配信しています。ログファイルとLogFormatに応じて、1つのライナーの一部を編集して作業する必要があります。

以下に簡単な例を示します。

サーバーのログを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

画像をホットリンクしているのは誰ですか:

awk -F\" '($2 ~ /\.(jpg|gif)/ && $4 !~ /^http:\/\/www\.mydomain\.com/){print $4}' access_log | sort | uniq -c | sort

1

ほとんどの場合、時間に基づいてログのセクションを読み取ることが多いので、sedを使用して次のスクリプトを記述し、興味のある期間を引き出します。アーカイブされたログも処理できます。

#!/ bin / bash
#このスクリプトは、2つの値の間の一連の行を返す必要があります。主な目的は、ログファイルを2回検索することです
#スクリプトの使用:logship.sh "start" "stop"ファイル

#ファイルの日付範囲に「/」が含まれている場合、次の2行でエスケープ文字を追加して、それらの文字を検索できるようにします
start = $(echo "$ 1" | sed 's / \ // \\\ // g')
stop = $(echo "$ 2" | sed 's / \ // \\\ // g')

zipped = $(echo "$ 3" | grep -c "gz $")#ファイルが圧縮されているかどうかを示す

if ["$ zipped" == "1"]; #ファイルがzipされている場合は、sedの前にzcatを介してファイルを渡します
        zcat $ 3 | sed -n "/ $ start /、/ $ stop / p";
他に
        sed -n "/ $ start /、/ $ stop / p" $ 3; #zip圧縮されていない場合は、sedを実行します
fi

1

sedやawkではありませんが、Apacheとicecastのログファイルを処理するのに役立つことがわかった2つのことがあります。

AWStatsにlogresolvemerge.plという非常に便利なスクリプトがあり、複数の圧縮または非圧縮ログファイルを結合し、重複を取り除き、タイムスタンプでソートします。DNSルックアップを実行し、マルチスレッドを実行するように構成することもできます。awstatsは現在のデータベースよりも古いタイムスタンプを持つログ行を追加できないため、awstatsで使用する場合に特に役立ちます。したがって、すべてを順番に追加する必要がありますが、logresolvemerge.plですべてをチャックするだけで非常に簡単になり、すべてがうまく表示されます。

sedとawkは、一般に文字列として扱うため、日付の処理がかなり苦手です。awkには時刻と日付の関数がいくつかありますが、それらはそれほど多くありません。たとえば、2つのタイムスタンプ間の行の範囲を抽出するのは、それらの正確なタイムスタンプがファイル内で発生しない場合(それらの間の値が発生しても)困難です-Chrisの例にはまさにこの問題があります。それに対処するために、ログファイルのタイムスタンプ範囲を報告し、任意の日付または時刻形式を使用してタイムスタンプ範囲ごとにチャンクを抽出できるPHPスクリプトを作成しました(ログファイルのタイムスタンプ形式と一致する必要はありません)。

これをトピックに保つために、いくつかの便利なawkismを以下に示します。apacheまたはicecastログから提供される合計バイト数を取得します。

cat access.log | awk '{ sum += $10 } END { print sum }'

icecastログから接続された合計秒数を取得します。

cat access.log | awk '{ sum += $13 } END { print sum }'

awkを使用した単純なバイト合計Apacheログの+1
rymo

0

この古いスレッドを回復、大きなログファイルのASQLにあきらめた後、またserverfaultの中で、私はWTOPについて見つけ、againgソリューションを探しここに(トップそれは、ライブ監視やプロセスのログを行うことが可能であると統計情報を取得し、それがオープンソースのツールですN)、非常に柔軟で強力な、公式の場所はこちら

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.