it-swarm.xyz

У вас есть какие-нибудь полезные скрипты awk и grep для разбора логов Apache?

Я могу использовать анализаторы логов, но часто мне нужно анализировать последние веб-логи, чтобы увидеть, что происходит в данный момент.

Я иногда делаю вещи, как выяснить топ-10 ips, которые запрашивают определенный файл

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

Что у вас есть в вашем наборе инструментов?

70
deadprogrammer

Вы можете делать что угодно с файлами журналов 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

Вы также можете передать вывод через sort, чтобы получить результаты по порядку, либо как часть команды Shell, либо также в самом скрипте awk:

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

Последнее будет полезно, если вы решите расширить скрипт awk для распечатки другой информации. Все дело в том, что вы хотите узнать. Они должны служить отправной точкой для всего, что вас интересует.

54
Mark

По причинам, которые я не могу себе представить, я никогда не видел, чтобы кто-то еще делал это, изменив формат файла журнала 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 и grep, когда cut делает то, что я хочу на порядок быстрее?

24
Dan Udey

Забудьте про 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;
16
Vihang D

Вот скрипт для поиска главных 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

Источник

6
anoopjohn

для количества 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

Они одни из моих любимых "лайнеров" :)

5
f4nt

Вот мой пример "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'

Почувствуйте силу регулярных выражений :-)

3
Kris

Составление списка общих вопросов было бы отличным показателем для ответов на этот вопрос. Мои общие вопросы:

  • почему изменился битрейт?
  • почему общее время отклика увеличивается?.

Я замечаю такие изменения, наблюдая за страницами состояния сервера (через mod_status) на предмет скорости обращения и приблизительного времени ответа для активных и недавно выполненных запросов (прекрасно понимая, что я пропускаю огромную кучу данных, но примеры достаточно хороши).

Я использую следующую директиву LogFormat (% T действительно полезен)

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

Я ищу причинно-следственную связь и то, что произошло первым ... обычно о конкретных подмножествах шаблонов в моих журналах, поэтому мне нужно знать следующее для любого данного шаблона/регулярного выражения:

  • количество посещений за интервал (минуты или часы) для данного шаблона (IP-адрес или строка CGI или параметры и т. д.)
  • гистограммы приблизительного времени отклика (с использованием параметра% T)

Я обычно использую Perl, потому что в конце концов он становится достаточно сложным, чтобы быть полезным.


Примером, не относящимся к Perl, был бы быстрый удар в минуту для не-200 кодов состояния:

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

Да, я обманываю с этим grep, предполагая, что цитата-пробел-200-пробел совпадает только с http-кодами состояния .... можно использовать awk или Perl для изоляции поля, просто имейте в виду, что это может быть неточно.


Более сложным примером в Perl может быть визуализация изменения битрейта для шаблона.

В приведенном ниже сценарии есть что поработать, особенно если вы не знакомы с Perl.

  • читает stdin, чтобы вы могли использовать части ваших журналов, использовать tail (особенно с tail -f), с или без greps и другие фильтры ...
  • читы Epoch timestamp извлечение со взломом регулярных выражений и использованием 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', чтобы собрать все ваши журналы (если у вас есть несколько apache за балансировщиком нагрузки) и
  • webalizer (или awstats или другой общий анализатор).
3
ericslaw

Кто горячо связывает ваши изображения:

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

Я часто использую 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
Michael Steinfeld

Хотя это не sed или awk, есть две вещи, которые я нашел полезными для работы с файлами журналов Apache и icecast.

AWStats имеет очень полезный сценарий под названием logresolvemerge.pl , который объединяет несколько сжатых или несжатых файлов журнала, удаляет дубликаты и сортирует по отметке времени. Он также может выполнять поиск DNS и быть настроен для запуска многопоточных. Это особенно полезно при использовании с awstats, потому что awstats не может добавлять строки журнала с метками времени, которые старше текущей базы данных, поэтому все должны быть добавлены по порядку, но это очень просто, поскольку вы просто бросаете все на logresolvemerge.pl, и все это вылезает красиво.

sed и awk довольно плохо справляются с датами, потому что они обычно относятся к ним как к строкам. У awk есть некоторые функции времени и даты, но их не так много. Например, извлечь диапазон строк между двумя временными метками сложно, если эти точные временные метки не встречаются в файле (даже если значения между ними есть) - пример Криса имеет именно эту проблему. Чтобы справиться с этим, я написал a PHP script , который сообщает о диапазонах меток времени файла журнала, а также может извлечь фрагмент по диапазону меток времени, используя любой формат даты или времени, который вам нравится (он не должен соответствовать формату метки времени файла журнала).

Чтобы сохранить это в теме, вот несколько полезных акизм: Получите общее количество байтов, обслуживаемых из Apache или журнала icecast:

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

Получить общее количество секунд, подключенных из журнала Icecast:

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

В большинстве случаев я обычно читаю разделы журнала, основанные на времени, поэтому я написал следующий скрипт, используя sed для извлечения интересующего меня периода, он работает с каждым файлом журнала, к которому я пришел через и может обрабатывать архивированные журналы, а также.

 #!/bin/bash 
 # Этот скрипт должен возвращать набор строк между 2 значениями, основная цель - поиск файла журнала 2 раза 
 # Использование скрипта: logship.sh "start" "stop" file 
 
 # Если в файле есть какой-либо символ "/" в диапазоне дат, в следующих 2 строках добавляется escape-символ, чтобы можно было выполнить поиск для этих символы 
 start = $ (echo "$ 1" | sed 's/\ // \\\ // g') 
 stop = $ (echo "$ 2" | sed 's/\//\\\//g')

zipped=$(echo "$ 3" | grep -c "gz $") # выясняет, был ли файл упакован в архив или нет 
 
 if ["$ zipped" == "1"]; затем # Если файл заархивирован, передайте его через zcat перед sed 
 zcat $ 3 | sed -n "/$start/,/$stop/p";
else
 sed -n"/$ start /,/$ stop/p "$ 3; # если он не заархивирован, просто запустите sed 
 fi 
1
Chris

При восстановлении этого старого потока, после отказа от asql для больших файлов журналов, искал решение, также в serverfault, я нашел о wtop здесь это инструмент с открытым исходным кодом, который способен выполнять мониторинг в реальном времени или обрабатывать логи и получать статистику (top N), очень гибкая и мощная, официальное место здесь

0
aseques