it-swarm-id.com

Apakah Anda memiliki skrip awk dan grep yang berguna untuk mem-parsing log Apache?

Saya dapat menggunakan penganalisis log, tetapi seringkali saya harus mengurai log web terbaru untuk melihat apa yang terjadi saat ini.

Saya terkadang melakukan hal-hal seperti mencari tahu 10 ips teratas yang meminta file tertentu

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

Apa yang Anda miliki di kotak alat Anda?

70
deadprogrammer

Anda dapat melakukan hampir semua hal dengan file log Apache dengan awk saja. File-file log Apache pada dasarnya dipisahkan oleh spasi, dan Anda dapat berpura-pura bahwa kutipan tidak ada, dan mengakses informasi apa pun yang Anda minati berdasarkan nomor kolom. Satu-satunya saat ini rusak adalah jika Anda memiliki format log gabungan dan tertarik pada agen pengguna, di mana Anda harus menggunakan tanda kutip (") sebagai pemisah dan menjalankan perintah awk terpisah. Berikut ini akan menunjukkan kepada Anda IP dari setiap pengguna yang meminta halaman indeks diurutkan berdasarkan jumlah klik:

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

$ 7 adalah url yang diminta. Anda dapat menambahkan kondisi apa pun yang Anda inginkan di awal. Ganti '$ 7 == "/" dengan informasi apa pun yang Anda inginkan.

Jika Anda mengganti $ 1 dalam (ipcount [$ 1] ++), maka Anda dapat mengelompokkan hasilnya berdasarkan kriteria lain. Menggunakan $ 7 akan menunjukkan halaman apa yang diakses dan seberapa sering. Tentu saja Anda ingin mengubah kondisi di awal. Berikut ini akan menunjukkan halaman apa yang diakses oleh pengguna dari IP tertentu:

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

Anda juga bisa menyalurkan output melalui sortir untuk mendapatkan hasil secara berurutan, baik sebagai bagian dari perintah Shell, atau juga dalam skrip awk itu sendiri:

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

Yang terakhir akan berguna jika Anda memutuskan untuk memperluas skrip awk untuk mencetak informasi lainnya. Ini semua masalah apa yang ingin Anda ketahui. Ini harus berfungsi sebagai titik awal untuk apa pun yang Anda minati.

54
Mark

Satu hal yang belum pernah saya lihat dilakukan orang lain, karena alasan yang tidak dapat saya bayangkan, adalah mengubah format file log Apache menjadi versi yang lebih mudah diurai dengan informasi yang benar-benar berarti bagi Anda.

Misalnya, kami tidak pernah menggunakan autentikasi dasar HTTP, jadi kami tidak perlu mencatat bidang-bidang itu. Saya sedang tertarik pada berapa lama setiap permintaan untuk melayani, jadi kami akan menambahkannya. Untuk satu proyek, kami juga ingin tahu (pada load balancer kami) jika ada server yang melayani permintaan lebih lambat daripada yang lain, jadi kami mencatat nama server yang kami proksi kembali.

Berikut adalah kutipan dari konfigurasi Apache satu server:

# 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

Apa yang Anda tidak dapat benar-benar tahu dari ini adalah bahwa antara setiap bidang adalah karakter tab literal (\ t). Ini berarti bahwa jika saya ingin melakukan beberapa analisis dengan Python, mungkin menunjukkan status non-200 misalnya, saya dapat melakukan ini:

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

Atau jika saya ingin melakukan 'siapa yang men-hotlink gambar?' itu akan

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

Untuk jumlah IP dalam log akses, contoh sebelumnya:

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

menjadi sesuatu seperti ini:

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

Lebih mudah untuk membaca dan memahami, dan jauh lebih murah secara komputasi (tanpa regex) yang, pada 9 GB log, membuat perbedaan besar dalam berapa lama. Ketika ini benar-benar rapi adalah jika Anda ingin melakukan hal yang sama untuk agen-pengguna. Jika log Anda dibatasi oleh ruang, Anda harus melakukan pencocokan ekspresi reguler atau pencarian string dengan tangan. Dengan format ini, mudah:

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

Persis sama seperti di atas. Bahkan, setiap ringkasan yang ingin Anda lakukan pada dasarnya sama persis.

Mengapa saya harus menghabiskan CPU sistem saya pada awk dan grep ketika cut akan melakukan apa yang saya inginkan pesanan besarnya lebih cepat?

24
Dan Udey

Lupakan awk dan grep. Lihat asql . Mengapa menulis skrip yang tidak dapat dibaca ketika Anda dapat menggunakan sintaks seperti sql untuk menanyakan logfile. Misalnya.

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;
16
Vihang D

Berikut adalah skrip untuk menemukan url teratas, rujukan teratas, dan agen pengguna teratas dari entri log N terbaru

#!/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

Sumber

6
anoopjohn

untuk jumlah IP dalam log akses:

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

Agak jelek, tapi berhasil. Saya juga menggunakan yang berikut ini dengan netstat (untuk melihat koneksi aktif):

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

Mereka adalah beberapa "one liners" favorit saya :)

5
f4nt

Di sini contoh 'sed' saya, ia membaca format default dari log Apache dan mengubahnya menjadi sesuatu yang lebih nyaman untuk pemrosesan otomatis. Seluruh baris didefinisikan sebagai ekspresi reguler, variabel disimpan dan ditulis ke keluaran dengan '#' sebagai pemisah.

Notasi yang disederhanakan dari input adalah:% s% s% s [% s] "% s"% s% s "% s" "% s"

Contoh input line: xx.xx.xx.xx - - [29/Mar/2011: 12: 33: 02 +0200] "DAPATKAN /index.html HTTP/1.0" 200 9443 "-" "Mozilla/4.0"

Contoh output line: 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'

Rasakan kekuatan ekspresi reguler :-)

3
Kris

Membuat daftar pertanyaan umum akan menjadi indeks yang bagus untuk jawaban atas pertanyaan ini. Pertanyaan umum saya adalah:

  • mengapa hitrate berubah?
  • mengapa waktu respons keseluruhan meningkat? '.

Saya melihat perubahan seperti itu dengan memantau halaman status server (via mod_status) untuk hitrate dan perkiraan waktu respons untuk permintaan yang aktif dan baru-baru ini selesai (mengetahui dengan baik bahwa saya kehilangan setumpuk besar data, tetapi sampel cukup baik).

Saya menggunakan arahan LogFormat berikut (% T sangat berguna)

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

Saya mencari sebab-akibat dan apa yang terjadi pertama kali ... biasanya tentang himpunan bagian pola tertentu dalam log saya, jadi saya perlu mengetahui yang berikut untuk setiap pola/ekspresi reguler yang diberikan:

  • hitcounts per interval (menit atau jam) untuk pola tertentu (alamat ip atau string cgi atau parameter, dll)
  • histogram perkiraan waktu respons (menggunakan% T parameter)

Saya biasanya menggunakan Perl, karena pada akhirnya menjadi cukup kompleks untuk menjadi berharga.


Contoh non-Perl adalah quickrate hitrate per menit untuk kode status non-200:

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

Ya saya selingkuh dengan grep itu, menganggap kutipan-ruang-200-cocok hanya kode status http .... bisa menggunakan awk atau Perl untuk mengisolasi bidang hanya perlu diingat itu bisa tidak akurat.


Contoh yang lebih kompleks dalam Perl mungkin untuk memvisualisasikan perubahan dalam hitrate untuk suatu pola.

Ada banyak yang harus dikunyah dalam skrip di bawah ini, terutama jika Anda tidak terbiasa dengan Perl.

  • membaca stdin sehingga Anda dapat menggunakan bagian dari log Anda, gunakan ekor (terutama dengan ekor -f), dengan atau tanpa greps dan penyaringan lainnya ...
  • menipu ekstraksi cap waktu Epoch dengan retasan regex dan penggunaan Date :: Manip
  • anda dapat memodifikasinya hanya sedikit untuk mengekstrak waktu respons atau data sewenang-wenang lainnya

kode berikut:

#!/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
    );
}

Jika Anda hanya ingin memproses metrik standar, checkout

  • 'mergelog' untuk mengumpulkan semua log Anda (jika Anda memiliki banyak apache di belakang load balancer) dan
  • webalizer (atau awstats atau penganalisa umum lainnya).
3
ericslaw

Siapa yang menautkan panas gambar Anda:

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

Saya sering menggunakan awk dengan mengekor atau melampirkan file. Setiap malam saya mengirimkan sendiri laporan web untuk setiap server. Bergantung pada file log Anda dan LogFormat Anda, Anda perlu mengedit beberapa liner yang sesuai untuk Anda ...

Berikut ini contoh sederhana:

Jika saya ingin mengekstrak log di server saya hanya untuk 404/500 kode status saya akan melakukan ini:

# $6 is the status code in my log file

tail -f ${Apache_LOG} |  awk  '$8 ~ /(404|500)/ {print $6}'

<snip>

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

Meskipun tidak sed atau awk, ada dua hal yang menurut saya berguna untuk menangani file log Apache dan icecast.

AWStats memiliki skrip yang sangat berguna bernama logresolvemerge.pl yang akan menggabungkan beberapa file log terkompresi atau tidak terkompresi, menghapus dupes dan mengurutkan berdasarkan stempel waktu. Itu juga dapat melakukan pencarian DNS dan dikonfigurasi untuk menjalankan multithreaded. Ini sangat berguna saat menggunakan dengan awstats karena awstats tidak dapat menambahkan garis log dengan stempel waktu lebih lama dari database saat ini, jadi semua harus ditambahkan secara berurutan, tetapi itu sangat mudah karena Anda baru saja membuang semuanya di logresolvemerge.pl dan semuanya muncul dengan baik.

sed dan awk cukup buruk dalam menangani kurma karena mereka umumnya memperlakukan mereka sebagai string. awk memiliki beberapa fungsi waktu dan tanggal, tetapi mereka tidak banyak. Misalnya mengekstraksi rentang garis antara dua stempel waktu sulit jika stempel waktu yang tepat tidak muncul dalam file (bahkan jika nilai di antara mereka melakukannya) - contoh Chris 'memiliki masalah ini persis. Untuk mengatasinya, saya menulis a PHP yang melaporkan rentang timestamp file log dan juga dapat mengekstrak bongkahan berdasarkan rentang timestamp, menggunakan format tanggal atau waktu apa pun yang Anda suka (tidak perlu mencocokkan format cap waktu file log).

Untuk mempertahankan topik ini, berikut adalah beberapa contoh berguna: Dapatkan jumlah total byte yang dilayani dari Apache atau log icecast:

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

Dapatkan total jumlah detik yang terhubung dari log icecast:

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

Hal yang saya cenderung lakukan sebagian besar waktu adalah membaca bagian-bagian log berdasarkan waktu, jadi saya menulis skrip berikut menggunakan sed untuk mencabut periode yang saya minati, ini bekerja pada setiap file log yang saya datangi menemukan dan dapat menangani log yang diarsipkan juga.

 #!/bin/bash 
 # Skrip ini harus mengembalikan serangkaian garis antara 2 nilai, tujuan utamanya adalah untuk mencari file log antara 2 kali 
 # Penggunaan skrip: logship.sh "start" "stop" file 
 
 # Jika file tersebut mengandung "/" dalam rentang tanggal 2 baris berikut tambahkan karakter escape sehingga pencarian dapat dilakukan untuk mereka karakter 
 mulai = $ (echo "$ 1" | sed 's/\ // \\' // g ') 
 stop = $ (echo "$ 2" | sed' s/\//\\\//g')[.____.[[.____.[zipped=$(echo "$ 3" | grep -c "gz $") # mencari tahu apakah file tersebut dizip atau tidak 
 
 jika ["$ zip" "==" 1 "]; lalu #Jika file tersebut di-zip lalu lewati zcat sebelum sed 
 zcat $ 3 | sed -n "/$start/,/$stop/p";[.____.[else
 sed -n"/$ start /,/$ stop/p "$ 3; #jika itu tidak di-zip, jalankan saja 
 fi 
1
Chris

Memulihkan utas lama ini, setelah menyerah pada asql untuk file log besar, mencari solusi againg, juga di serverfault, saya menemukan tentang wtop di sini itu adalah alat opensource, yang mampu melakukan pemantauan langsung atau memproses log dan mendapatkan statistik (N teratas), sangat fleksibel dan kuat, tempat resminya adalah di sini

0
aseques