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


69

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

Bazen belli bir dosya isteyen ilk 10 ipsi bulmak gibi şeyler yapıyorum.

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

Araç kutunuzda neler var?


1
Aslında tüm apache özel kayıtlarımı bir veritabanına gönderilmek üzere bireysel alanlara ayırmak için elle yazdığım bu büyük güzel regex'e sahibim. Artık ona sahip olmadığım için kendimi tekmeliyorum. Tek bir astardı; Her bir log elemanı için size bir değişken verdim - sonra MySQL'e ekliyordum. Onu bulursam buraya gönderirim.
Kyle Hodgson

Yanıtlar:


54

Sadece awk ile apache günlük dosyaları ile hemen hemen her şeyi yapabilirsiniz. Apache günlük dosyaları temelde boşlukla ayrılmış ve tırnakların olmadığı gibi davranabilir ve sütun numarasına göre ilgilendiğiniz bilgilere erişebilirsiniz. Bu ayrışmanın tek zamanı, birleştirilmiş günlük formatına sahipseniz ve kullanıcı aracılarıyla ilgileniyorsanız, bu noktada ayırıcı olarak tırnak işaretleri (") kullanmanız ve ayrı bir awk komutu çalıştırmanız gerekir. Aşağıda IP’lerin IP’leri gösterilecektir. 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 $. İstediğiniz koşulları başlangıçta ekleyebilirsiniz. '7 $ == "/"' yi istediğiniz bilgiyle değiştirin.

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

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

Çıktıları, kabuk komutunun bir parçası olarak veya awk betiğinin kendisinde de sırayla almak için sıralama yoluyla da yönlendirebilirsiniz:

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

Diğer bilgileri yazdırmak için awk komut dosyasını genişletmeye karar verirseniz, sonuncusu yararlı olacaktır. Hepsi ne öğrenmek istediğinle ilgili. Bunlar, ilgilendiğiniz şey için bir başlangıç ​​noktası görevi görmelidir.


Yah, çılgın uzun kedi / grep / awk boru hatlarını görmek her zaman garip görünüyor. Bir kere işin içindeyken, bu genellikle yeterli. Orjinal gönderinin ilk üç maddesi, "awk '/ request_to_file_foo / {print $ 1}' foo.log" olarak basitçe yazılabilir. awk bir dosyayı girdi olarak alabilir ve hangi satırlara önem vereceğini bilmek için regex'i kullanabilir.
Zac Thompson

Zarif ve basit. İyi.
Olivier Dulac

Dikkat edin, her şeyi kıran "authuser" (3.) alanında boşluk bırakılmış gibi görünüyor ve bunu yapmamıza izin vermenin kişisel olarak yasaklanması gerektiğini düşünüyorum ;-)
Mandark

23

Hiç kimsenin görmediği bir şey, hayal bile edemediğim nedenlerden dolayı, Apache günlük dosyası biçimini, sizin için gerçekten önemli olan bilgilerle daha kolay bir şekilde çözümlenebilir bir sürüme değiştirmek.

Örneğin, hiçbir zaman HTTP temel auth kullanmayız, bu nedenle bu alanları kaydetmemize gerek yoktur. Ben değilim her istek hizmet etmek ne kadar sürdüğünü ilgilenen, bu yüzden de ekleyeceğiz. Bir proje için, biz de herhangi sunucular yavaş diğerlerinden daha istekleri sunmaları durumunda (bizim yük dengeleyici üzerine) bilmek istiyorum, bu yüzden adını log Sunucunun sunucusuna geri dönüyoruz.

İş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 söyleyemeyeceğiniz şey, her alan arasındaki değişmez sekme karakteri (\ t). Bunun anlamı, eğer Python'da bir analiz yapmak istersem, örneğin 200 olmayan statü gösterebilirim, bunu yapabilirim:

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

Ya da 'Resimlerin bağlantılarını kim yapıyor?' Yapmak istesem 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

böyle bir şey olur:

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

Okuması ve anlaması daha kolaydır ve 9 GB'lık kayıtlarda ne kadar sürdüğü konusunda çok büyük bir fark yaratan, daha ucuz (pahalı olmayan). Bu GERÇEKTEN temiz olduğunda, User-agent için aynı şeyi yapmak istiyorsanız. Günlükleriniz boşlukla sınırlandırılmışsa, düzenli ifade eşleştirmesi veya elle dize arama yapmanız gerekir. Bu format ile, basit:

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

Tam olarak yukarıdaki ile aynı. Aslında, yapmak istediğiniz herhangi bir özeti aslında tamamen aynıdır.

Kesikli olarak büyüklük sırasına göre istediğim şeyi yapacağımda neden dünyadaki sistemimin işlemcisini awk ve grep harcayacağım?


2
Yeni formata ilişkin örnekleriniz gerçekte hala karmaşıktır - IP sayıları cut -f 3 log | uniq -c | sort -nkullanıcı aracıları olur cut -f 8 log | uniq -c | sort -n.
Creshal

Haklısın, bu daha basit. Bunu yansıtacak şekilde örnekleri güncelledim.
Dan Udey,

"cat file | grep string" işe yaramaz, neden "grep string file" değil?
c4f4t0r

2
Mazeretim yok ve örneği buna göre güncelledim.
Dan Udey,

15

Awk ve grep'i unut. Check ASQL . Günlük dosyasını sorgulamak için sql benzeri sözdizimi kullanabiliyorken neden okunamayan komut dosyaları yazmalısınız. Ö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;

İlginçtir, ancak günlükleriniz özellikle büyükse sorun yaşayabilirsiniz. Ayrıca özel günlük formatları ile ne kadar iyi başa çıkıyor?
Vagnerr

Şu anda deniyorum, yükleme süresi çok yavaş (en azından 0.9 sürümünde).
200Mb'lık bir log yüklemek

Yükleme süresinden sonra (yaklaşık 15 dakika sürdü) bu programın synstax'inin harika olduğunu söylemeliyim, sıralayabilir, gruplayabilir ve gruplandırabilirsiniz. Gerçekten hoş.
aseques

Apache HTTPD, günlükleri etkin bir şekilde veritabanına gönderebileceğiniz bir metoda sahiptir. Evet, yazarlar uzun sürebilir, ancak dişli bir vekil tam ortasında doğru olanı yapabilir. Her neyse, bu sorgulama günlüklerini SQL benzeri bir sözdiziminde çok daha hızlı hale getirecek. Çok fazla yükleme yapılmaz - veritabanı sunucusu sürekli olarak "AÇIK" tır.
nearora

6

Son N günlüğü girişlerinden en iyi URL'leri, en çok yönlendirilenleri ve en çok kullanılanları bulmak için kullanılan bir betik

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


4

Bir 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

En sevdiğim "bir gömlek" lerden bazıları :)


3

Sık sorulan soruların bir listesini oluşturmak, bu soruya verilen cevaplar için harika bir endeks olacaktır. Benim ortak sorularım:

  • hitrate neden değişti?
  • Genel tepki süresi neden artıyor? '.

Sunucu durumu sayfalarını (mod_status aracılığıyla) hitrate için izleyerek ve aktif ve yakın zamanda tamamlanmış talepler için yaklaşık yanıt süresini (büyük bir veri yığınını özleyeceğimi gayet iyi bilerek, ancak örnekler yeterince iyi olduğunu bilerek) farkettim.

Aşağıdaki LogFormat direktifini kullanıyorum (% T gerçekten kullanışlıdır)

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

Neden-sonuç ve ilk önce olanları ... genellikle günlüklerimdeki belirli desen alt kümeleri hakkında arıyorum, bu nedenle verilen herhangi bir kalıp / düzenli ifade için aşağıdakileri bilmem gerekiyor:

  • Belirli bir desen için aralık başına vuruş sayısı (dakika veya saat) (ip adresi veya cgi dizesi veya parametreleri, vb.)
  • Yaklaşık tepki süresinin histogramları (% T parametresi kullanılarak)

Genelde perl kullanıyorum, çünkü sonunda değecek kadar karmaşıklaşıyor.


Perl dışı bir örnek, 200 olmayan durum kodları için dakika başına kısa bir hitrate olabilir:

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

Evet, bu boşluğu aldatıyorum, bir alıntı-uzay-200-uzayının sadece http durum kodlarıyla eşleştiğini farz ediyorum .... alanı izole etmek için awk veya perl kullanabilir, sadece yanlış olduğunu aklınızda bulundurun.


Perl'de daha karmaşık bir örnek, bir kalıp için hit hızda bir değişimi görselleştirmek olabilir.

Aşağıdaki senaryoda çiğnenecek çok şey var, özellikle de perl ile uyumsuzsanız.

  • stdin okur, böylece kütüklerinizin bazı bölümlerini kullanabilirsiniz, kuyruk (özellikle kuyruk-f ile), grep veya diğer filtreleme olmadan ...
  • regex hack ve Date kullanımı ile epoch zaman damgası çıkarma hileleri
  • Yanıt süresini veya diğer isteğe bağlı verileri çıkarmak için onu yalnızca biraz değiştirebilirsiniz.

kod şöyle:

#!/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 ölçümleri işlemek istiyorsanız, ödeme yapın

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

3

Burada 'sed' örneğim, apache günlüklerinin varsayılan biçimini okuyor ve otomatik işleme için daha uygun bir şeye dönüştürüyor. Tüm satır düzenli 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 :-)


Bu işlem AWK ile işlemeyi kolaylaştırdı. Ortak bir sınırlandırıcı ayarlamak için hızlı bir yol arıyordu ve bu onu çivilendi.
Citricguy

Regex'in gücünü hissettim ve sadece "HTML / 1.1" i kesen ve protokolü (muhtemelen standartlara uygun olmayan bir şekilde) kendi alanına ayıran kendi ince ayarımdan geçmek istedim. Keyfini çıkarın: `` `kedi access.log | sed 's /^(.*) (. *) (. *) [(. *)] \ "([[: alfa:]] \ +) (. *) HTTP \ / 1 \ .1 \" ( . *) (. *) \ "(. *) \" \ "(. *) \" $ / \ 1 # \ 2 # \ 3 # \ 4 # \ 5 # \ 6 # \ 7 # \ 8 # \ 9 # \ 10 / g '``
Josh Rumbut

2

Dosyayı kullanarak ya da kedileri izleyerek çok awk kullanıyorum. Her gece kendime her sunucu için bir web raporu veriyorum. Günlük dosyanıza ve LogFormat'ınıza bağlı olarak, sizin için çalışacak astarlardan bazılarını düzenlemeniz gerekir.

İşte basit bir örnek:

Sunucumdaki günlükleri sadece 404/500 durum kodları için yerleştirmek istersem şunu yaparı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

Resimlerinizi kimler bağdaştırıyor:

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

1

Çoğu zaman yapma eğiliminde olduğum şey, zamana bağlı bir logun bölümlerini okumak, bu yüzden ilgilendiğim periyodu çıkarmak için sed kullanarak aşağıdaki betiği yazdım, geldiğim her günlük dosyasına çalışıyor Arşivlenmiş günlükleri de geçip işleyebilir.

#! / Bin / bash
#Bu komut dosyası 2 değer arasında bir satır kümesi döndürmelidir, asıl amaç, 2 kez arasında bir günlük dosyası aramaktır.
#Script kullanımı: logship.sh "start" "stop" dosyası

# Dosya tarih aralığında herhangi bir "/" içeriyorsa, aşağıdaki 2 satır kaçış karakterini ekler, böylece arama bu karakterler için gerçekleştirilebilir
start = $ (echo "$ 1" | sed 's / \ // \\\ // g')
stop = $ (eko "$ 2" | sed 's / \ // \\\ // g')

zipped = $ (echo "$ 3" | grep -c "gz $") # dosya sıkıştırılmış veya sıkıştırılmamışsa çıkar

eğer ["$ fermuarlı" == "1"]; Daha sonra # Eğer dosya sıkıştırılmışsa, sed önce zcat içinden geçirin
        3 $ zcat | sed -n "/ $ start /, / $ stop / p";
Başka
        sed -n "/ $ başlangıç ​​/, / $ stop / p" $ 3; # Fermuarlı değilse sadece koş
fi

1

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

AWStats , logresolvemerge.pl adında çok sayıda sıkıştırılmış veya sıkıştırılmamış günlük dosyasını birleştiren, kopyaları sıyırıp zaman damgasına göre sıralayacak ç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 özellikle kullanışlıdır, çünkü awstats mevcut veri tabanından daha eski zaman damgalarına sahip log satırları ekleyemez, bu yüzden her şey sırayla eklenmelidir, ancak bu her şeyi logresolvemerge.pl adresinden almanız ve her şey güzel bir şekilde çıkarmanız çok kolaydır .

sed ve awk, kullanım tarihlerinde oldukça kötüdür, çünkü genellikle dizeleri gibi davranırlar. awk'nin bazı zaman ve tarih fonksiyonları vardır, fakat fazla bir şey değildir. Örneğin, iki zaman damgası arasına bir dizi satır çıkarmak, dosyada bu tam zaman damgası olmadığında zordur (aralarındaki değerler olsa bile) - Chris'in ö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 istediğiniz herhangi bir tarih veya saat biçimini kullanarak (günlük dosyasının zaman damgası biçimiyle eşleşmesi gerekmez) zaman damgası aralığına göre bir yığın ayıklayabilen bir PHP komut dosyası yazdım .

Bu konuyu açık tutmak için işte birkaç yararlı bilgi var: apache veya icecast günlüklerinden sunulan toplam bayt sayısını al:

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

Bir icecast günlüğüne bağlı toplam saniye sayısını edinin:

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

Awk ile basit bayt toplama apache günlüğü için +1
rymo

0

Bu eski iş parçacığını kurtarmak, büyük günlük dosyalarına sorulduktan sonra, sunucuda da hataya yol açan bir çözüm arayışına girdim, burada wtop hakkında canlı izleme izleme veya işlem kayıtlarını yapabilme ve istatistik alma yeteneğine sahip bir açık kaynak kodlu araç buldum. N), çok esnek ve güçlü, resmi yer burada

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.