Я могу использовать анализаторы логов, но часто мне нужно анализировать последние веб-логи, чтобы увидеть, что происходит в данный момент.
Я иногда делаю вещи, как выяснить топ-10 ips, которые запрашивают определенный файл
cat foo.log | grep request_to_file_foo | awk '{print $1}' | sort -n | uniq -c | sort -rn | head
Что у вас есть в вашем наборе инструментов?
Вы можете делать что угодно с файлами журналов 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 для распечатки другой информации. Все дело в том, что вы хотите узнать. Они должны служить отправной точкой для всего, что вас интересует.
По причинам, которые я не могу себе представить, я никогда не видел, чтобы кто-то еще делал это, изменив формат файла журнала 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 делает то, что я хочу на порядок быстрее?
Забудьте про 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;
Вот скрипт для поиска главных 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
для количества 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
Они одни из моих любимых "лайнеров" :)
Вот мой пример "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'
Почувствуйте силу регулярных выражений :-)
Составление списка общих вопросов было бы отличным показателем для ответов на этот вопрос. Мои общие вопросы:
Я замечаю такие изменения, наблюдая за страницами состояния сервера (через mod_status) на предмет скорости обращения и приблизительного времени ответа для активных и недавно выполненных запросов (прекрасно понимая, что я пропускаю огромную кучу данных, но примеры достаточно хороши).
Я использую следующую директиву LogFormat (% T действительно полезен)
LogFormat "%h %l %u %t \"%r\" %>s %b
\"%{Referer}i\" \"%{User-Agent}i\" %T" custom
Я ищу причинно-следственную связь и то, что произошло первым ... обычно о конкретных подмножествах шаблонов в моих журналах, поэтому мне нужно знать следующее для любого данного шаблона/регулярного выражения:
Я обычно использую Perl, потому что в конце концов он становится достаточно сложным, чтобы быть полезным.
Примером, не относящимся к Perl, был бы быстрый удар в минуту для не-200 кодов состояния:
tail -9000 access_log | grep -v '" 200 ' | cut -d: -f2,3 | uniq -c
Да, я обманываю с этим grep, предполагая, что цитата-пробел-200-пробел совпадает только с http-кодами состояния .... можно использовать awk или Perl для изоляции поля, просто имейте в виду, что это может быть неточно.
Более сложным примером в Perl может быть визуализация изменения битрейта для шаблона.
В приведенном ниже сценарии есть что поработать, особенно если вы не знакомы с Perl.
код следует:
#!/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
);
}
Если вы просто хотите обработать стандартные метрики, оформите заказ
Кто горячо связывает ваши изображения:
awk -F\" '($2 ~ /\.(jpg|gif)/ && $4 !~ /^http:\/\/www\.mydomain\.com/){print $4}' access_log | sort | uniq -c | sort
Я часто использую 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>
Хотя это не 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 }'
В большинстве случаев я обычно читаю разделы журнала, основанные на времени, поэтому я написал следующий скрипт, используя 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
При восстановлении этого старого потока, после отказа от asql для больших файлов журналов, искал решение, также в serverfault, я нашел о wtop здесь это инструмент с открытым исходным кодом, который способен выполнять мониторинг в реальном времени или обрабатывать логи и получать статистику (top N), очень гибкая и мощная, официальное место здесь