Модераторы: korob2001, ginnie
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> парсинг access.log, парсить access.log (непростой формат) 
V
    Опции темы
Danger
Дата 3.7.2008, 12:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 36
Регистрация: 20.9.2006

Репутация: нет
Всего: нет



Hello,

Access.log моего squid-a имеет такой формат:
Код

logformat my_own_format %ts.%03tu %>a HTTP/%rv %rm "%ru" %Hs %<st "%{Referer}>h" "%{User-Agent}>h" %tr %Ss:%Sh


Т.е., записи выглядят примерно так:
Код

970313965.619 192.168.14.2 HTTP/1.1 GET "http://delphimaster.ru/index.html" 200 35992 "Mozilla/5.0; Firefox/3.0" 320 TCP_MISS:DIRECT
970313967.522 192.168.14.5 HTTP/1.1 GET "http://forum.vingrad.ru/" 200 35992 "Mozilla/5.0; Firefox/3.0" 412 TCP_MISS:DIRECT
970313972.111 192.168.14.3 HTTP/1.1 GET "http://danger.artline.kz/template2.jpg" 404 2561219 "Opera/9.50; Linux" 512 TCP_MISS:DIRECT
970313972.111 192.168.14.3 HTTP/1.0 GET "http://alhoster.com/files/base2.dat" 200 349387 "Dangers HTTP Client 2.0" 310 TCP_MISS:DIRECT


Проблема состоит в том, чтобы выделить из таких записей данные, по шаблону. Т.е. выделить каждый элемент (timestamp, url, method, useragent, etc..) из строки. split() для этого случая не годится, т.к. элементы в строке разделены пробелами и сами элементы могут быть ограничены кавычками (внутри кавычек могут пробелы встречаться).

Подскажите, как составить регулярку для этого случая? Или какой-нибудь другой вариант решения.
PM WWW ICQ Jabber   Вверх
GoDleSS
Дата 3.7.2008, 12:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 105
Регистрация: 11.2.2007
Где: Пироговский

Репутация: 2
Всего: 2



Парсите шаблоном напрямую, вот пример(естественно не проверенный, ибо лень):
Код

chomp($string);

my @data = $string =~ m/^(\d+)\.\d+\s((\d{1,3}\.){3,5}\d{1,3})\s[A-Z\/\.01]+\s((GET)|(POST))\s"([^"'\r\n\s\t]+)"\s\d{3}\s"([^"'\r\n\t]+)"\s\d{3}\s[A-Z:]+$/;

my ($timestamp, $rhost, $method, $url) = @data[0, 1, 3, 7];

--------------------
It's a nice day to die my friend!
PM MAIL WWW ICQ   Вверх
Danger
Дата 3.7.2008, 14:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 36
Регистрация: 20.9.2006

Репутация: нет
Всего: нет



Пробовал по вышеприведенному примеру, вот что получилось (с учетом того, что все нужные мне параметры находятся по порядку):

Код

while ( <STDIN> ) {
  chomp;
  my @data = $_ =~ m/^(\d+)\.\d+\s((\d{1,3}\.){3,5}\d{1,3})\s[A-Z\/\.01]+\s((GET)|(POST))\s"([^"'\r\n\s\t]+)"\s\d{3}\s"([^"'\r\n\t]+)"\s\d{3}\s[A-Z:]+$/;
  my ( $lTimestamp, $lIP, $lHttpVer, $lMethod, $lUrl, $lRespCode, $lSize, $lUserAgent, $lRespTime, $lStatus ) = @data[0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
  print  $lTimestamp, " ", $lIP, " ", $lHttpVer, " ", $lMethod, " ", $lUrl, " ", $lRespCode, " ", $lSize, " ", $lUserAgent, " ", $lRespTime, " ",$lStatus, "\n";


Со включенными варнингами пишет, что значения не были инициализированы, примерно так:

Код

Use of uninitialized value in print at ./parser.pl line 116, <STDIN> line 152.
Use of uninitialized value in print at ./parser.pl line 116, <STDIN> line 152.
Use of uninitialized value in print at ./parser.pl line 116, <STDIN> line 152.
Use of uninitialized value in print at ./parser.pl line 116, <STDIN> line 152.
Use of uninitialized value in print at ./parser.pl line 116, <STDIN> line 152.
Use of uninitialized value in print at ./parser.pl line 116, <STDIN> line 152.
Use of uninitialized value in print at ./parser.pl line 116, <STDIN> line 152.


Я не разбираюсь регулярках, мне нужно лишь сделать, чтоб работал разбор для этого случая. Если не составит труда, подскажите точный шаблон... Буду очень признателен.
PM WWW ICQ Jabber   Вверх
GoDleSS
Дата 3.7.2008, 15:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 105
Регистрация: 11.2.2007
Где: Пироговский

Репутация: 2
Всего: 2



Код

while(<STDIN>) {
  chomp;
  my @data = $_ =~ m/^(\d+)\.\d+ ([0-9\.]{7,23}) ([A-Z\/\.0-1]+) ((GET)|(POST)) "([^"'\r\n\s\t]+)" (\d{3}) (\d+) "([^"'\r\n\t]+)" (\d{3}) ([A-Z:_]+)$/s;
  my ( $lTimestamp, $lIP, $lHttpVer, $lMethod, $lUrl, $lRespCode, $lSize, $lUserAgent, $lRespTime, $lStatus ) = @data[0, 1, 2, 3, 6, 7, 8, 9, 10, 11];
  print  join(' ', ($lTimestamp, $lIP, $lHttpVer, $lMethod, $lUrl, $lRespCode, $lSize, $lUserAgent, $lRespTime, $lStatus)), "\n";
}

--------------------
It's a nice day to die my friend!
PM MAIL WWW ICQ   Вверх
ginnie
Дата 3.7.2008, 15:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Комодератор
Сообщений: 1287
Регистрация: 6.1.2008
Где: Москва

Репутация: 38
Всего: 49



Уважаемый Danger, предлагаю другой вариант: выберите в качестве разделителя полей другой символ (или группу символов, вместо пробела), которого точно не будет внутри значений, тогда split сработает без проблем.


--------------------
Написать код, понятный компьютеру, может каждый, но только хорошие программисты пишут код, понятный людям. (Мартин Фаулер. Рефакторинг)
PM MAIL Skype Jabber   Вверх
Danger
Дата 3.7.2008, 16:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 36
Регистрация: 20.9.2006

Репутация: нет
Всего: нет



Цитата(GoDleSS @ 3.7.2008,  15:22)
Код

while(<STDIN>) {
  chomp;
  my @data = $_ =~ m/^(\d+)\.\d+ ([0-9\.]{7,23}) ([A-Z\/\.0-1]+) ((GET)|(POST)) "([^"'\r\n\s\t]+)" (\d{3}) (\d+) "([^"'\r\n\t]+)" (\d{3}) ([A-Z:_]+)$/s;
  my ( $lTimestamp, $lIP, $lHttpVer, $lMethod, $lUrl, $lRespCode, $lSize, $lUserAgent, $lRespTime, $lStatus ) = @data[0, 1, 2, 3, 6, 7, 8, 9, 10, 11];
  print  join(' ', ($lTimestamp, $lIP, $lHttpVer, $lMethod, $lUrl, $lRespCode, $lSize, $lUserAgent, $lRespTime, $lStatus)), "\n";
}

Работает замечательно, за исключением интерпретации первого значения в строке: выделяется лишь часть до точки, значение после точки игнорируется (например, в исходной строке было 970313965.619, выделится лишь 970313965). Все остальные отрабатывают корректно. Что нужно подправить в шаблоне, чтобы первое значение тоже бралось корректно?

Спасибо.

Добавлено через 3 минуты и 42 секунды
Цитата(ginnie @ 3.7.2008,  15:28)
Уважаемый Danger, предлагаю другой вариант: выберите в качестве разделителя полей другой символ (или группу символов, вместо пробела), которого точно не будет внутри значений, тогда split сработает без проблем.

Я думал над этим вариантом ранее, но хотелось более красивое решение, коим сейчас видится предложенное GoDleSS. Изящное решение на основе произвольного шаблона (причем остается потенциальная совместимость с другими анализаторами логов, с случае с "нетрадиционным" разделителем может и не быть).
PM WWW ICQ Jabber   Вверх
GoDleSS
Дата 3.7.2008, 19:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 105
Регистрация: 11.2.2007
Где: Пироговский

Репутация: 2
Всего: 2



Код

m/^(\d+)\.\d+ ([0-9\.]{7,23})

заменить на
Код

m/^(\d+\.\d+) ([0-9\.]{7,23})

Всего лишь обратите внимание на разницу, а разница в положении закрывающей скобки, соответствующей выборке $1 или в данном подходе $data[0]

Это сообщение отредактировал(а) GoDleSS - 3.7.2008, 19:11
--------------------
It's a nice day to die my friend!
PM MAIL WWW ICQ   Вверх
Danger
Дата 4.7.2008, 05:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 36
Регистрация: 20.9.2006

Репутация: нет
Всего: нет



Цитата(GoDleSS @  3.7.2008,  19:10 Найти цитируемый пост)
Всего лишь обратите внимание на разницу, а разница в положении закрывающей скобки, соответствующей выборке $1 или в данном подходе $data[0]

Большое спасибо, все работает.

С небольшой лишь поправкой, для моего случая:
Код

my @data = $_ =~ m/^(\d+\.\d+) ([0-9\.]{7,23}) ([A-Z\/\.0-1]+) ((GET)|(POST)|(CONNECT)) "([^"'\r\n\s\t]+)" (\d{3}) (\d+) "([^"'\r\n\t]+)" (\d{3}) ([A-Z:_]+)$/s; 
my ( $lTimestamp, $lIP, $lHttpVer, $lMethod, $lUrl, $lRespCode, $lSize, $lUserAgent, $lRespTime, $lStatus ) = @data[0, 1, 2, 3, 7, 8, 9, 10, 11, 12];


Это сообщение отредактировал(а) Danger - 4.7.2008, 05:32
PM WWW ICQ Jabber   Вверх
arto
Дата 8.7.2008, 13:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1495
Регистрация: 31.10.2004

Репутация: 38
Всего: 40



grep { $_ ne "" } split /(?:\s+"(.+?)"\s+|\s+)/,
PM MAIL ICQ   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Perl"
korob2001
sharq
  • В этом разделе обсуждаются общие вопросы по языку Perl
  • Если ваш вопрос относится к системному программированию, задавайте его здесь
  • Если ваш вопрос относится к CGI программированию, задавайте его здесь
  • Интерпретатор Perl можно скачать здесь ActiveState, O'REILLY, The source for Perl
  • Справочное руководство "Установка perl-модулей", можно скачать здесь


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, korob2001, sharq.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Perl: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0491 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.