it-swarm-tr.com

Apache günlüklerini ayrıştırmak için faydalı awk ve grep komut dosyalarınız var mı?

Günlük analizörlerini kullanabilirim, ancak şu anda neler olduğunu görmek için genellikle son web günlüklerini ayrıştırmam gerekiyor.

Bazen belirli bir dosya isteyen en iyi 10 ips'i bulmak gibi şeyler yaparım

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

Araç kutunuzda neler var?

70
deadprogrammer

Sadece awk ile Apache günlük dosyaları ile hemen hemen her şeyi yapabilirsiniz. Apache günlük dosyaları temelde boşlukla ayrılmıştır ve tırnak işaretleri yokmuş gibi yapabilir ve ilgilendiğiniz bilgilere sütun numarasına erişebilirsiniz. Bu işlemin kesildiği tek zaman, birleştirilmiş günlük biçimine sahipseniz ve kullanıcı aracılarıyla ilgileniyorsanız, bu noktada ayırıcı olarak tırnak işareti (") kullanmanız ve ayrı bir awk komutu çalıştırmanız gerekir. dizin sayfasını isteyen her kullanıcı isabet sayısına göre sıralanır:

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

İstenen URL 7 TL. Başlangıçta istediğiniz koşulları ekleyebilirsiniz. '$ 7 == "/" yerine istediğiniz bilgileri yazın.

(İpcount [$ 1] ++) içindeki 1 $ değerini değiştirirseniz, sonuçları diğer ölçütlere göre gruplayabilirsiniz. 7 $ kullanılması, sayfalara hangi sıklıkta erişildiğini ve ne sıklıkta gösterildiğini gösterir. Tabii ki başlangıçta durumu değiştirmek istersiniz. Aşağıda, belirli bir IP'den bir kullanıcı tarafından hangi sayfalara erişildiği gösterilecektir:

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

Ayrıca, sonuçları Shell komutunun bir parçası olarak veya awk betiğinin kendisinde de sırayla almak için sıralama yoluyla çıkış yapabilirsiniz:

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

İkincisi, diğer bilgileri yazdırmak için awk betiğini genişletmeye karar verdiyseniz yararlı olacaktır. Her şey ne öğrenmek istediğinizle ilgili. Bunlar, ilgilendiğiniz her şey için bir başlangıç ​​noktası olmalıdır.

54
Mark

Hiç kimsenin görmediğim bir şey, hayal bile edemediğim için, Apache günlük dosyası biçimini sizin için önemli olan bilgilerle daha kolay ayrıştırılabilir bir sürüme dönüştürmektir.

Örneğin, asla HTTP temel kimlik doğrulamasını kullanmayız, bu nedenle bu alanları günlüğe kaydetmemize gerek yoktur. Ben am her isteğin ne kadar süre ile ilgileneceğiyle ilgileniriz, bu yüzden bunu ekleyeceğiz. Bir proje için, herhangi bir sunucunun isteklerinden daha yavaş istekleri sunup sunmadığını da bilmek istiyoruz (yük dengeleyicimizde) bu nedenle tekrar proxy sunucu olarak kullandığımız sunucunun adını kaydederiz.

İşte bir sunucunun Apache yapılandırmasından bir alıntı:

# 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

Bundan gerçekten anlayamayacağınız şey, her alanın arasında gerçek bir sekme karakteri (\ t) olmasıdır. Bu, Python'da bazı analizler yapmak istersem, örneğin 200 olmayan durumları gösterebilirim, bunu yapabilirim:

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

Ya da 'hotlinking imgeleri kim?' olurdu

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

Bir erişim günlüğündeki IP sayıları için önceki örnek:

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

şöyle bir şey olur:

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

Okuması ve anlaması daha kolay ve 9 GB'lık günlüklerde ne kadar sürdüğü konusunda büyük bir fark yaratan çok daha az hesaplama açısından pahalı (normal ifade yok). Bu GERÇEKTEN temizlendiğinde, aynı şeyi Kullanıcı aracıları için yapmak istiyorsanız. Günlükleriniz boşlukla sınırlandırılmışsa, el ile düzenli ifade eşleştirmesi veya dize araması yapmanız gerekir. Bu formatla, basit:

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

Yukarıdakiyle tamamen aynı. Aslında, yapmak istediğiniz herhangi bir özet aslında aynıdır.

Kesim büyüklük siparişlerini daha hızlı istediğimde yapacağım zaman neden yeryüzünde sistemimin CPU'sunu awk ve grep'e harcayayım?

24
Dan Udey

Awk ve grep'i unut. Check out asql . Günlük dosyasını sorgulamak için sql benzeri sözdizimi kullanabildiğinizde neden okunamayan komut dosyaları yazıyorsunuz? Örneğin.

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

En son URL'leri, en çok yönlendirenleri ve son N günlük girişlerinden en çok kullanılanları bulmak için bir komut dosyası

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

Kaynak

6
anoopjohn

erişim günlüğündeki IP sayıları için:

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

Biraz çirkin, ama işe yarıyor. Ayrıca netstat ile aşağıdakileri kullanıyorum (aktif bağlantıları görmek için):

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

Onlar benim favori "tek gömleklerim" bazıları :)

5
f4nt

Burada benim 'sed' örneğim, Apache günlüklerinin varsayılan biçimini okur ve otomatik işleme için daha uygun bir şeye dönüştürür. Tüm satır normal ifade olarak tanımlanır, değişkenler kaydedilir ve ayırıcı olarak '#' ile çıktıya yazılır.

Girişin basitleştirilmiş gösterimi:% s% s% s [% s] "% s"% s% s "% s" "% s"

Örnek giriş satırı: xx.xx.xx.xx - - [29/Mar/2011: 12: 33: 02 +0200] "GET /index.html HTTP/1.0" 200 9443 "-" "Mozilla/4.0"

Örnek çıktı satırı: 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'

Düzenli ifadelerin gücünü hissedin :-)

3
Kris

Sık sorulan soruların bir listesini oluşturmak, bu sorunun yanıtları için harika bir indeks olacaktır. Sık sorulan sorular:

  • isabet oranı neden değişti?
  • genel tepki süresi neden artıyor? ''.

Bu tür değişiklikleri, sunucu durumu sayfalarını (mod_status aracılığıyla) isabet oranı ve aktif ve yakın zamanda tamamlanan istekler için yaklaşık yanıt süresi izleyerek (büyük bir veri yığınını kaçırdığımı iyi biliyorum, ancak örnekler yeterince iyi) bilerek fark ediyorum.

Aşağıdaki LogFormat yönergesini kullanıyorum (% T gerçekten yararlı)

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

Neden-etkisi ve ilk ne oldu ... genellikle günlükleri belirli desen alt kümeleri hakkında arıyorum, bu yüzden herhangi bir desen/düzenli ifade için aşağıdakileri bilmeniz gerekir:

  • belirli bir model için aralık başına hitcounts (dakika veya saat) (ip adresi veya cgi dizesi veya parametreleri vb.)
  • yaklaşık tepki süresinin histogramları (% T parametresini kullanarak)

Genelde Perl kullanıyorum, çünkü sonunda değerli olacak kadar karmaşık hale geliyor.


Perl olmayan bir örnek, 200 olmayan durum kodu için dakikada hızlı bir isabet oranı olacaktır:

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

Evet bir alıntı-alan-200-boşluk sadece http durum kodları ile eşleşen varsayalım bu grep ile hile yapıyorum .... alan yanlış izole akılda tutmak için awk veya Perl kullanabilirsiniz.


Perl'deki daha karmaşık bir örnek, bir model için isabet oranındaki bir değişikliği görselleştirmek olabilir.

Aşağıdaki senaryoda çiğnemek için çok şey var, özellikle Perl ile tanışmıyorsanız.

  • günlüklerin bölümlerini kullanabilir, kuyrukları (özellikle kuyruk -f ile), açgözlü veya diğer filtrelemeli veya filtresiz olarak kullanabilirsiniz ...
  • düzenbazlık hack ile dönem zaman damgası çıkarma hileleri ve Tarih kullanımı :: Manip
  • yanıt süresini veya diğer keyfi verileri ayıklamak için yalnızca biraz değiştirebilirsiniz.

kodu aşağıdaki gibidir:

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

Yalnızca standart metrikleri işlemek istiyorsanız, ödeme yapın

  • Tüm günlüklerinizi bir araya getirmek için 'mergelog' (bir yük dengeleyicisinin arkasında birden fazla önbellek varsa) ve
  • webalizer (veya awstats veya diğer yaygın analizörler).
3
ericslaw

Görüntülerinizi kim sıcak bağlantılandırıyor:

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

Awk dosyasını dosyalayarak veya dosyalayarak çok kullanıyorum. Her gece kendime her sunucu için bir web raporu gönderiyorum. Günlük dosyanıza ve LogFormat'ınıza bağlı olarak, sizin için çalışacak tek astardan bazılarını düzenlemeniz gerekir.

İşte basit bir örnek:

Sunucumdaki günlükleri yalnızca 404/500 durum kodları için kuyruklamak istersem bunu yapardım:

# $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

Sed veya awk olmasa da, Apache ve icecast günlük dosyalarını işlemek için yararlı bulduğum iki şey var.

AWStats , birden çok sıkıştırılmış veya sıkıştırılmamış günlük dosyasını birleştiren, dupes'leri sıyırıp zaman damgasına göre sıralayan logresolvemerge.pl adında çok kullanışlı bir komut dosyasına sahiptir. Ayrıca DNS aramaları yapabilir ve çok iş parçacıklı çalışacak şekilde yapılandırılabilir. Awstats ile kullanıldığında özellikle kullanışlıdır, çünkü awstats geçerli veritabanından daha eski zaman damgalarına sahip günlük satırları ekleyemez, bu nedenle her şey sırayla eklenmelidir, ancak her şeyi taktığınız için çok kolaydır logresolvemerge.pl ve her şey güzel bir şekilde ortaya çıkıyor.

sed ve awk, tarihleri ​​işlemede oldukça kötüdür, çünkü genellikle onlara dizgi olarak davranırlar. awk bazı saat ve tarih işlevlerine sahiptir, ancak çok fazla değildir. Örneğin, dosyada tam zaman damgaları oluşmazsa (aralarındaki değerler olsa bile) iki zaman damgası arasında bir satır aralığı çıkarmak zordur - Chris örneğinde tam olarak bu sorun vardır. Bununla başa çıkmak için, günlük dosyası zaman damgası aralıklarını bildiren ve ayrıca istediğiniz herhangi bir tarih veya saat biçimini kullanarak zaman damgası aralığına göre bir yığın ayıklayabilen a PHP script yazdım (günlük dosyasının zaman damgası biçimiyle eşleşmesi gerekmez).

Bu konuyu korumak için, birkaç yararlı awkizm var: Apache veya icecast günlüğünden sunulan toplam bayt sayısını alın:

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

Bir buzlanma günlüğünden toplam saniye sayısını bağlayın:

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

Çoğu zaman yapmaya eğilimli olduğum şey, zamana dayalı bir günlüğün bölümlerini okumaktır, bu yüzden ilgilendiğim süreyi çıkarmak için sed kullanarak aşağıdaki komut dosyasını yazdım, geldiğim her günlük dosyasında çalışıyor ve arşivlenen günlükleri de işleyebilir.

 #!/bin/bash 
 # Bu komut dosyası 2 değer arasında bir satır kümesi döndürmelidir, temel amaç 2 kez bir günlük dosyasını aramaktır 
 # Kod kullanımı: logship.sh "başlat" "durdur" dosyası 
 
 # Dosya, tarih aralığında herhangi bir "/" içeriyorsa, aşağıdaki 2 satır kaçış karakterini ekleyerek aramanın yapılabilmesini sağlar karakterler 
 start = $ (echo "$ 1" | sed 's/\ // \\\ // g') 
 stop = $ (echo "$ 2" | sed 's/\//\\\//g')[.____. Cialis[.____. Cialiszipped=$(echo "$ 3" | grep -c "gz $") # dosyanın sıkıştırılıp sıkıştırılmadığını 
 
 eğer ["$ fermuarlı" == "1"]; sonra # Dosya sıkıştırılmışsa, sed'den önce zcat içinden geçirin 
 zcat $ 3 | sed -n "/$start/,/$stop/p";[.____. Cialiselse
 sed -n"/$ start /,/$ stop/p "$ 3; # sıkıştırılmış değilse sadece sed 
 fi 
1
Chris

Bu eski iş parçacığının kurtarılması, büyük günlük dosyaları için asql'den vazgeçtikten sonra, aynı zamanda serverfault'ta da bir çözüm aradı, wtop hakkında buldum burada bu, canlı izleme yapabilen bir açık kaynak aracı veya günlükleri işlemek ve istatistik almak (ilk N), çok esnek ve güçlü, resmi yer burada

0
aseques