Pull to refresh

Парсинг access.log апача

Reading time3 min
Views7.1K
Как то раз у меня возникла необходимость написать скрипт, который анализирует access.log веб сервера apache. Самому писать времени не было и хотел найти что-нибудь готовое. Но ничего подходящего не нашел и пришлось писать самому. Вот решил поделиться своими наработками.
Собственно опишу общий алгоритм для данной задачи, который каждый уже сможет заточить под свои нужды при необходимости.

Итак, для начала вспомним что же из себя представляет файл access.log. А выглядит он следующим образом:

193.34.12.132 - - [20/Oct/2011:12:46:08 +0400] "GET /scripts/fancyzoom.min.js HTTP/1.1" 200 4435 "http://kropus.amarox.ru/" "Mozilla/5.0 (Windows NT 5.1; rv:7.0.1) Gecko/20100101 Firefox/7.0.1"
193.34.12.132 - - [20/Oct/2011:12:46:08 +0400] "GET /bitrix/js/main/core/css/core_window.css?1318570950 HTTP/1.1" 200 44471 "http://kropus.amarox.ru/" "Mozilla/5.0 (Windows NT 5.1; rv:7.0.1) Gecko/20100101 Firefox/7.0.1"
193.34.12.132 - - [20/Oct/2011:12:46:08 +0400] "GET /bitrix/templates/kropus/components/bitrix/menu/kropus/script.js?1315557673 HTTP/1.1" 200 469 "http://kropus.amarox.ru/" "Mozilla/5.0 (Windows NT 5.1; rv:7.0.1) Gecko/20100101 Firefox/7.0.1"


Как вам наверное уже известно формат записи логов можно менять настройками апача. Выше представлен формат, который устанавливается по умолчанию. В нем можно увидеть IP адрес клиента, дату и время, протокол, размер запроса, строку запроса, браузер и ОС.

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

А теперь подробнее:
Чтобы разобрать каждую строку сначала будет удобнее занести их все в один массив, где каждый элемент это строка из файла. Сделать это можно проще простого функцией file

$file_array = file(‘путь к файлу’);


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

Вот примерно так выглядит функция для получения строки
($fp – указатель на файл, полученный ранее функцией fopen)

function get_log_string()
{
if (feof($fp))
{
return false;
}
$bits='';

for (;!feof($fp) && $bits != "\n";)
{
$bits .= fread($fp, 1);
}
return rtrim($bits, "\n");
}


Таким образом, мы считываем по одному биту до тех пор пока не достигнем конца строки. Если достигнут конец файла то возвращаем false.

Эту функцию необходимо зациклить
while ($string = $get_log_string())
{
//Разбираем полученную строку $string
//И производим с ней нужные действия
}

Теперь собственно переходим непосредственно к самому разбору строки.
Я сделал это с помощью функции preg_match и регулярных выражений. Задаем шаблон

$pattern = "/(\S+) (\S+) (\S+) \[([^:]+):(\d+:\d+:\d+) ([^\]]+)\] \"(\S+) (.*?) (\S+)\" (\S+) (\S+) (\".*?\") (\".*?\")/"


Получаем в итоге

preg_match ($pattern, $line, $result)


$pattern – наш шаблон
$line – строка для разбора
$result – массив, в который будут записаны полученные результаты

Для удобства массив можно привести в удобочитаемый формат

$formated['ip'] = $result [1];
$formated['identity'] = $result [2];
$formated['user'] = $result [3];
$formated['date'] = $result [4];
$formated['time'] = $result [5];
$formated['timezone'] = $result[6];
$formated['method'] = $result [7];
$formated['path'] = $result[8];
$formated['protocol'] = $result[9];
$formated['status'] = $result[10];
$formated['bytes'] = $result[11];
$formated['referer'] = $result[12];
$formated['agent'] = $result[13];


Вот собственно и все. Мы получили массив с данными из строки лога. Теперь с этими данными можно делать то, что вам необходимо в конкретном случае.
Tags:
Hubs:
Total votes 40: ↑7 and ↓33-26
Comments20

Articles