ログアナライザーを使用できますが、多くの場合、最近のWebログを解析して、現在何が起こっているのかを確認する必要があります。
特定のファイルを要求する上位10個のipsを把握したいことがあります
cat foo.log | grep request_to_file_foo | awk '{print $1}' | sort -n | uniq -c | sort -rn | head
ツールボックスには何がありますか?
ログアナライザーを使用できますが、多くの場合、最近のWebログを解析して、現在何が起こっているのかを確認する必要があります。
特定のファイルを要求する上位10個のipsを把握したいことがあります
cat foo.log | grep request_to_file_foo | awk '{print $1}' | sort -n | uniq -c | sort -rn | head
ツールボックスには何がありますか?
回答:
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スクリプトを展開して他の情報を出力することにした場合に役立ちます。それはすべてあなたが知りたいことの問題です。これらは、あなたが興味を持っているものの出発点として役立つはずです。
私が想像することのできない理由で、他の誰も見たことのないことの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が正確に何桁も速くしたいのに、どうしてですか?
cut -f 3 log | uniq -c | sort -n
はユーザーエージェントになりますcut -f 8 log | uniq -c | sort -n
。
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;
最近の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
アクセスログの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
彼らは私のお気に入りの「ライナー」の一部です:)
一般的な質問のリストを作成することは、この質問に対するこの回答の優れたインデックスになります。私のよくある質問は次のとおりです。
アクティブなリクエストと最近完了したリクエストのヒット率とおおよその応答時間をサーバーステータスページ(mod_status経由)で監視することにより、このような変更に気付きます(膨大なデータの山を見逃していることを十分に理解していますが、サンプルで十分です)。
次のLogFormatディレクティブを使用します(%Tは非常に便利です)
LogFormat "%h %l %u %t \"%r\" %>s %b
\"%{Referer}i\" \"%{User-Agent}i\" %T" custom
私は原因と最初に起こったことを探しています...通常、ログ内のパターンの特定のサブセットについてですので、特定のパターン/正規表現について次のことを知る必要があります:
最終的には価値があるほど複雑になるので、私は通常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に慣れていない場合は、以下のスクリプトで多くを噛む必要があります。
コードは次のとおりです。
#!/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
);
}
標準のメトリックを処理する場合は、チェックアウト
ここで私の「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'
正規表現の力を感じてください:-)
私はファイルをテーリングまたは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>
ほとんどの場合、時間に基づいてログのセクションを読み取ることが多いので、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
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 }'