Есть ли у вас полезные скрипты awk и grep для разбора журналов apache? [закрыто]

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

Иногда я делаю такие вещи, как выяснение 10 лучших ips, которые запрашивают определенный файл

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

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

70
задан 27 October 2015 в 23:20
12 ответов

Можно сделать в значительной степени что-либо с апачскими файлами журнала с одним только awk. Файлы журнала Apache являются в основном пробелом, разделенным, и можно притвориться, что кавычки не существуют, и доступ безотносительно информации, которой Вы интересуетесь номером столбца. Единственное время, которое это ломает, - то, если Вы имеете объединенный формат журнала и интересуетесь агентами пользователя, в которой точке необходимо использовать кавычки (") как разделитель и выполнить отдельную команду awk. Следующее покажет Вам дюйм/с каждого пользователя, который запрашивает индексную страницу, отсортированную по количеству хитов:

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 сценарий для распечатывания другой информации. Это - весь вопрос того, что Вы хотите узнать. Они должны служить начальной точкой для того, чем Вы интересуетесь.

54
ответ дан 28 November 2019 в 19:28
  • 1
    Yah, всегда кажется странным видеть сумасшедшие длинные конвейеры cat/grep/awk. Однажды you' ре в awk, that' s обычно достаточно. Первые три пункта исходного сообщения могли быть тривиально записаны как " awk '/request_to_file_foo/{печатают 1$} ' нечто log". awk может взять файл в качестве входа и может использовать regex для знания который строки заботиться о. –  Zac Thompson 4 June 2009 в 09:06

Кто использование горячих ссылок Ваши изображения:

awk -F\" '($2 ~ /\.(jpg|gif)/ && $4 !~ /^http:\/\/www\.mydomain\.com/){print $4}' access_log | sort | uniq -c | sort
2
ответ дан 28 November 2019 в 19:28

поскольку 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
ответ дан 28 November 2019 в 19:28

Забудьте о 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
ответ дан 28 November 2019 в 19:28
  • 1
    Интересный, но Вы могли бы столкнуться с проблемами, если бы Ваши журналы являются особенно большими, я думал бы. Также, как хорошо это справляется с пользовательскими форматами журнала? –  Vagnerr 5 June 2009 в 16:39

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

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

Вот выборка от апачской конфигурации одного сервера:

# 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

Легче читать и понять, и намного менее в вычислительном отношении дорогой (никакой regex), который, на журналах на 9 ГБ, имеет огромное значение в том, сколько времени оно берет. То, когда это становится ДЕЙСТВИТЕЛЬНО аккуратным, - то, если Вы хотите сделать то же самое для Агентов пользователя. Если Ваши журналы разграничены пространством, необходимо сделать некоторое соответствие регулярного выражения или поиск строки вручную. С этим форматом это просто:

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

Точно то же как вышеупомянутое. На самом деле любая сводка, которую Вы хотите сделать, является по существу точно тем же.

С какой стати я потратил бы ЦП своей системы на awk и grep, когда сокращенный сделает точно, что я хочу порядки величины быстрее?

24
ответ дан 28 November 2019 в 19:28

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

  • почему hitrate изменялся?
  • почему полное время отклика повышается?'.

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

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

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

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

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

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


non-perl примером была бы недоброкачественная продукция hitrate в минуту для не200 кодов состояния:

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

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


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

Существует много для жевания в сценарии ниже, особенно если Вы - unfamilar с жемчугом.

  • чтения stdin, таким образом, можно использовать части журналов, используйте хвост (особенно с хвостом-f), с или без властей и другой фильтрации...
  • эпоха обманов добавляет метку времени к извлечению со взломом regex и использованию Даты:: 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 (или awstats или другой общий анализатор).
3
ответ дан 28 November 2019 в 19:28

Здесь мой 'sed' пример, это читает формат по умолчанию апачских журналов и преобразовывает его во что-то более удобное для автоматической обработки. Целая строка определяется как регулярное выражение, переменные сохранены и записаны для вывода с '#' как разделитель.

Упрощенная нотация входа: %s %s %s [%s] "%s" %s %s "%s" "%s"

Пример ввел строку: xx.xx.xx.xx - [29/Mar/2011:12:33:02 +0200] "ПОЛУЧАЮТ /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
ответ дан 28 November 2019 в 19:28

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

Вот простой пример:

Если я хочу отслеживать журналы на моем сервере всего за 404 Коды состояния / 500 Я бы сделал следующее:

# $6 is the status code in my log file

tail -f ${APACHE_LOG} |  awk  '$8 ~ /(404|500)/ {print $6}'

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

2
ответ дан 28 November 2019 в 19:28

Вот сценарий для поиска основных 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
ответ дан 28 November 2019 в 19:28

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

#!/bin/bash
#This script should return a set of lines between 2 values, the main purpose is for searching a log file between 2 times
#Script usage: logship.sh "start" "stop" file

#If the file contains any "/" in the date range the following 2 lines add the escape character so that the search can be performed for those characters
start=$(echo "$1" | sed 's/\//\\\//g')
stop=$(echo "$2" | sed 's/\//\\\//g')

zipped=$(echo "$3" | grep -c "gz$")     #figures out if the file is zipped or not

if [ "$zipped" ==  "1" ]; then          #If the file is zipped then pass it through zcat before sed
        zcat $3 | sed -n "/$start/,/$stop/p";
else
        sed -n "/$start/,/$stop/p" $3;  #if it's not zipped just run sed
fi
1
ответ дан 28 November 2019 в 19:28

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

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

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

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

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

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

cat access.log | awk '{ sum += $13 } END { print sum }'
1
ответ дан 28 November 2019 в 19:28

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

0
ответ дан 28 November 2019 в 19:28

Теги

Похожие вопросы