Чи є у вас якісь корисні сценарії awk та grep для розбору журналів apache? [зачинено]


69

Я можу використовувати аналізатори журналів, але часто мені потрібно проаналізувати останні веб-журнали, щоб побачити, що відбувається в даний момент.

Іноді я роблю такі речі, як, щоб з'ясувати топ-10 ips, які вимагають певного файла

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

Що у вас в панелі інструментів?


1
Насправді у мене був цей прекрасний виразний текст, який я написав вручну, щоб проаналізувати всі мої користувацькі журнали apache до окремих полів для подання в базу даних. Я б'ю себе, що більше не маю цього. Це був один лайнер; повернув вам одну змінну для кожного елемента журналу - тоді я вставляв у MySQL. Якщо я знайду це, я опублікую його тут.
Кайл Ходжсон

Відповіді:


54

Ви можете робити майже все що завгодно з файлами журналу apache лише з awk. Файли журналів Apache в основному розділені пробілом, і ви можете зробити вигляд, що котирування не існують, і отримувати доступ до будь-якої інформації, яка вас цікавить, за номером стовпця. Єдиний раз, коли це виходить з ладу, - якщо ви маєте комбінований формат журналу і цікавитесь користувачами-агентами, тоді вам потрібно використовувати лапки (") як роздільник і виконати окрему команду awk. Наступне покаже вам IP-адреси кожен користувач, який запитує сторінку з покажчиком, відсортовану за кількістю звернень:

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

$ 7 - запитуваний URL. Ви можете додати будь-які умови на початку. Замініть "$ 7 ==" / "будь-якою інформацією, яку ви хочете.

Якщо ви заміните $ 1 у (ipcount [$ 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 для друку іншої інформації. Це все питання того, що ви хочете дізнатися. Вони повинні слугувати відправною точкою для всього, що вас цікавить.


Так, завжди дивно бачити божевільні довгі котячі трубопроводи. Після того, як ви в неприємності, цього зазвичай достатньо. Перші три статті оригінальної публікації можна тривіально записати як "awk" / request_to_file_foo / {print $ 1} 'foo.log ". awk може взяти файл як вхідний файл, а також може використовувати регулярний вираз, щоб знати, які рядки потрібно хвилювати.
Зак Томпсон

Елегантний і простий. Добре.
Олів'є Дулак,

Остерігайтеся, пробіли здаються дозволеними у полі "authuser" (3-е), що все порушує, і я особисто вважаю, що це слід забороняти, щоб ми могли це робити ;-)
Mandark

23

Одне, чого я ніколи не бачив, щоб хто-небудь інший робив, з причин, які я не уявляю, - це змінити формат файлу журналу Apache на більш легко розбірливу версію з інформацією, яка насправді має значення для вас.

Наприклад, ми ніколи не використовуємо базовий протокол HTTP, тому нам не потрібно реєструвати ці поля. Я буду зацікавлений в тому , як довго кожен запит займає служити, тому ми додамо , що в. Для одного проекту, ми також хочемо знати (на нашій балансуванню навантаження) , якщо будь-які сервера обслуговувати запити повільніше , ніж інші, тому ми реєструємо ім'я сервера, до якого ми звертаємось.

Ось уривок з конфігурації 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 ГБ журналів робить величезну різницю в тому, як триває це. Коли це дійсно стає акуратним, якщо ви хочете зробити те ж саме для User-агентів. Якщо ваші журнали обмежені місцями, вам потрібно виконати відповідність регулярних виразів або пошук рядків вручну. З цим форматом це просто:

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

Точно так само, як і вище. Насправді, будь-яке резюме, яке ви хочете зробити, є по суті абсолютно однаковим.

Чому на землі я б витрачав процесор своєї системи на awk and grep, коли скорочення буде робити саме те, що я хочу на параметри швидше?


2
Ваші приклади для нового формату насправді все ще складні - підрахунки IP стають cut -f 3 log | uniq -c | sort -n, користувацькими агентами cut -f 8 log | uniq -c | sort -n.
Creshal

Ти маєш рацію, це простіше. Я оновив приклади, щоб це відобразити.
Ден Удей

"cat cat | grep string" є марним, чому б не "grep string string"?
c4f4t0r

2
У мене немає виправдання, і я відповідно оновив приклад.
Dan Udey

15

Забудь про неприємності та греп. Перевірте 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;

Цікаво, але ви можете зіткнутися з проблемами, якщо ваші журнали особливо великі, я думаю. Також наскільки добре він справляється зі спеціальними форматами журналів?
Вагнерр

Я пробую це на даний момент, час завантаження настільки повільний (принаймні у версії 0.9). Завантаження журналу 200 Мбіт займає більше п'яти хвилин ..
наступне

Треба сказати, що після завантаження (це зайняло близько 15 хвилин) синтаксис цієї програми великий, ви можете сортувати, рахувати та групувати за. Дійсно приємно.
наступ

Apache HTTPD має метод, за допомогою якого можна ефективно надсилати журнали до бази даних. Так, написання може зайняти багато часу, але потоковий проксі може зробити саме те, що просякнуте посередині. У будь-якому випадку, це зробить журнали запитів у синтаксисі типу SQL набагато швидше. Жодного завантаження теж не береться - сервер бази даних постійно "ВКЛ."
nearora

6

Ось сценарій, де можна знайти найкращі URL-адреси, найпопулярніші реферери та найпопулярніші користувачі з останніх записів N журналу

#!/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, оскільки з часом він стає досить складним, щоб бути вартим.


Прикладом, який не відповідає дійсності, може бути швидка швидка робота за хвилину для не-200 кодів статусу:

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

Так, я обманюю цей греп, припускаючи, що цитата-простір-200-пробіл відповідає лише кодам статусу http .... може використовувати awk або perl для ізоляції поля, майте на увазі, це може бути неточним.


Складнішим прикладом в perl може бути візуалізація зміни скорочення для шаблону.

У нижченаведеному сценарії можна багато пережовувати, особливо якщо ви не знайомі з perl.

  • читає stdin, щоб ви могли використовувати частини ваших журналів, використовувати хвіст (особливо з хвостом -f), із грейпами або без них та іншим фільтруванням ...
  • видобуток епохи видобутку часових позначок з хаком регексу та використання 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 (або астати або інший загальний аналізатор).

3

Ось мій приклад 'sed', він читає формат журналів apache за замовчуванням і перетворює його в щось більш зручне для автоматичної обробки. Весь рядок визначається як регулярний вираз, змінні зберігаються і записуються на вихід з "#" як роздільник.

Спрощене позначення вводу:% s% s% s [% s] "% s"% s% s "% s" "% s"

Приклад рядка введення: xx.xx.xx.xx - - [29 / березня / 2011: 12: 33: 02 +0200] "GET /index.html HTTP / 1.0" 200 9443 "-" "Mozilla / 4.0"

Приклад вихідного рядка: xx.xx.xx.xx # - # - # 29 / березня 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

Я відчув силу регулярного виразів і просто хотів пройти вздовж моєї власної настройки, яка вирізає "HTML / 1.1" і відокремлює протокол (можливо, нестандартним способом) у власному полі. Насолоджуйтесь: `` `cat access.log | sed 's /^(.*) (. *) (. *) [(. *)] \ "([[: alpha:]] \ +) (. *) HTTP \ / 1 \ .1 \" ( . *) (. *) \ "(. *) \" \ "(. *) \" $ / \ 1 # \ 2 # \ 3 # \ 4 # \ 5 # \ 6 # \ 7 # \ 8 # \ 9 # \ 10 / g '' ``
Джош Румбут

2

Я дуже часто використовую awk, торкаючись чи котячи файл. Щовечора я доставляю собі веб-звіт для кожного сервера. Залежно від вашого файлу журналу та вашого LogFormat, вам потрібно буде відредагувати деякі з одних вкладок, щоб вони працювали для вас ...

Ось простий приклад:

Якщо я хочу створити журнал на моєму сервері лише для 404/500 кодів стану, я б це зробив:

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

Хто посилається на ваші зображення:

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

1

Те, що я, як правило, роблю більшу частину часу, - це читання розділів журналу на основі часу, тому я написав наступний сценарій за допомогою sed, щоб витягнути період, який мене цікавить, він працює на кожному файлі журналу, який я прийшов поперек і може також обробляти архівовані журнали.

#! / бін / баш
# Цей скрипт повинен повертати набір рядків між двома значеннями, головне призначення - пошук у журналі журналу між двома разів
#Script використання: logship.sh "start" "stop" файл

# Якщо файл містить будь-який "/" в діапазоні дат, наступні два рядки додають символ "escape", щоб пошук можна було виконати для цих символів
start = $ (відлуння "$ 1" | sed 's / \ // \\\ // g')
стоп = $ (відлуння "$ 2" | sed 's / \ // \\\ // g')

zipped = $ (відлуння "$ 3" | grep -c "gz $") # фігурується, якщо файл зафіксовано чи ні

if ["$ zipped" == "1"]; то # Якщо файл зафіксовано, то передайте його через zcat перед sed
        zcat $ 3 | sed -n "/ $ start /, / $ stop / p";
ще
        sed -n "/ $ start /, / $ stop / p" $ 3; # якщо це не на блискавці, просто запустіть sed
фі

1

Хоча це не sed або awk, я знайшов корисні для обробки файлів журналів apache та icecast.

AWStats має дуже корисний скрипт під назвою logresolvemerge.pl, який поєднує в собі кілька стислих або нестиснених файлів журналу, знімає дупи та сортує за часовою міткою. Він також може робити пошук DNS і налаштовуватися на запуск багатопотокових. Це особливо корисно при використанні з астатами, оскільки не можуть додавати рядки журналів із часовими позначками, старшими за поточну базу даних, тому все потрібно додати в порядку, але це дуже просто, оскільки ви просто зафіксуєте все на logresolvemerge.pl, і все це добре вискакує.

sed і awk досить погано обробляють дати, тому що вони, як правило, трактують їх як рядки. У awk є деякі функції часу та дати, але їх не дуже багато. Наприклад, витяг діапазону рядків між двома часовими позначками важко, якщо ці точні часові позначки не зустрічаються у файлі (навіть якщо значення між ними є) - у прикладі Кріса є саме ця проблема. Для вирішення цього питання я написав скрипт PHP, який повідомляє про часові позначки файлів журналу, а також може витягти фрагмент за діапазоном часових позначок, використовуючи будь-який формат дати чи часу, який вам подобається (не потрібно відповідати формату часових міток файлу журналу).

Щоб продовжити цю тему, ось декілька корисних айквізмів: Отримайте загальну кількість байтів, що подаються з апачу чи журналу льодовикової передачі:

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

Отримайте загальну кількість секунд, підключених з журналу «Icecast»:

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

+1 для простого
байтування

0

Відновивши цей старий потік, відмовившись від asql для великих файлів журналів, шукав рішення againg, також на сервері за замовчуванням, я знайшов про wtop ось це інструмент з відкритим кодом, який здатний робити моніторинг в реальному часі або обробляти журнали та отримувати статистику (верх N), дуже гнучкий і потужний, офіційне місце тут

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.