Эта тема на forum.dklab.ru


Enilatiar: Today log
Иногда я заглядываю в лог файл сайта... но уж больно он не читабелен...
Я нарисовал читалку сегодняшнего лога. Предлагаю вам на рассмотрение.
Выглядит это так:
http://qad.ru/cgi-bin/stat.cgi

В качестве примера использования...
Не далее как в предыдущую субботу читаю
170.224.224.121
00:31:09 /forum/ 200 27779 -
00:31:41 /forum/viewtopic.php?p=6&highlight=%2527.$poster=$dbname.%2527 200 21068 -
170.224.224.124
00:31:13 /forum/viewtopic.php?p=44&highlight=%2527.$poster=$dbpasswd.%2527 200 12835 -
00:31:55 /forum/login.php 200 13187 http://qad.ru/forum/memberlist.php
00:32:03 /forum/login.php 200 12556 http://qad.ru/forum/login.php
00:32:11 /admin/ 404 269 -
170.224.224.123
00:31:51 /forum/memberlist.php 200 18033 http://qad.ru/forum/viewtopic.php?p=6&highlight=%2527.$poster=$dbname.%2527
170.224.224.122
00:31:21 /forum/viewtopic.php?p=2&highlight=%2527.$poster=$dbpasswd.%2527 200 12342 -
00:31:26 /forum/viewtopic.php?p=6&highlight=%2527.$poster=$dbpasswd.%2527 200 21066 -
00:32:08 /forum/login.php?redirect= 200 13187 -
Чтение сего заставило меня зашевелиться и обновить движок...
Дмитрий Котеров:
Ошибки и неточности:
1. Надо везде вместо "open ..., ... || die" ставить "or die", потому что иначе трактуется как "open ..., (... || die)".
2. В конце должно быть "$self->{$key} = $value if $key;", иначе лезут warning-и при пустых строках в конфиге.
3. my $previousRequest = '' (иначе warning на undef).
4. next if !$request (для битых строк в логе - такие тоже бывают).

Вот что бывает, когде не используется CGI::WebOut. Куча предупреждений остается незамеченной.
Дмитрий Котеров:
Кроме того, каждая строка лога фактически парсится 2 раза, что замедляет скорость. Почему бы не запоминать ранее распарсенный результат?

Наконец, во внутреннем цикле вывода зачем-то осуществляется перебор на M*N итераций, где M - число уникальных хостов, а N - общее число записей в логе (хотя, очевидно, вполне достаточно и N итераций).

В итоге скрипт просто убивается по тайм-ауту:
http://dklab.ru/cgi/todaylog/todaylog.cgi
Дмитрий Котеров:
Так что на готовые решения пока не очень тянет.
Пусть еще повисит пару дней, и, если за это время не будет исправлений, перенесем в Прочее.

А так - скрипт полезный.
Дмитрий Котеров:
Ветка выделена в отдельную тему «ALLA — Artemy Lomov’s Log Analyzer»,
расположенную в форуме Склад готовых решений :: Perl (08 Декабря 2004, 00:52).
Enilatiar:
Наконец, во внутреннем цикле вывода зачем-то осуществляется перебор на M*N итераций, где M - число уникальных хостов, а N - общее число записей в логе (хотя, очевидно, вполне достаточно и N итераций).

Я не знаю как это сделать иначе. Ибо одна из основных задач лога - группирование запроосов от конкретного хоста в один список (и так для каждого хоста).

Есть два цикла:
Первый собирает список хостов и выводит их (сортируя по времени запроса первой страницы):
foreach my $host (sort { $hosts{$a} <=> $hosts{$b} } keys %hosts)
...

А второй ищет (и выводит) все запросы данного хоста:
foreach (@requests)
{
my ($h, $date, $time, $request) = (/(\S+) \[(\S+) (\S+)\] (.*)/);
next if $h ne $host;
...


Одним из принципов кода была (сюрприз!) работоспособность. Поэтому пеподчтение отдавалалось простым сруктурам:
простой plain-текст со вторичным парсингом...

Что-ж, если код может быть полезен кому-то кроме меня, попробую передалать оный с учетом оптимизации и эффективности.
Я, кстати, вспомнил причину из-за которой я его сделал... Причиной была скупость... Раз в два-три дня, я заглядвал в лог сервера. А поскольку доступ к сайтам у меня только по ftp, то чтобы просмотрел лог, мне приходилось его скачивать... а это два-три мега минумум с каждого сайта... Дикий трафик получается, из "воздуха". :( Поэтому, в этом принтиге я выделил лишь то, что мне было интересно.
Дмитрий Котеров:
Проходитесь по каждой строке только один раз, разбирая ее на части. Затем делайте

push @{$hosts{$hostname}}, { parsed log line }.

Таким образом, у Вас получится хэш массивов, ключи - имена хостов, значения - массивы строк, соответствующих ключам.
Enilatiar:
хэш массивов, ключи - имена хостов, значения - массивы строк, соответствующих ключам
Я, собственно, о этом и писал -- хотел прозрачности объектов. А для них не получается без двойного прохода.
Постараюсь в ближайшее время переписать. Возможно, непросредственно с помощью Вашего примера. Если пойму, как он работает. :)
Enilatiar:
Обновление... Внесены все замечания.

TodayLog 1.1
На больших файлах не проверялся... таймауты, думаю, можно лечить только страничностью.
Дмитрий Котеров:
Ну вот, уже лучше. Только если $conf->{ignoredFolders} не определена, вообще ничего не выводится. Достаточно пропустить строчку в конфиге и - кирдык.

Не понятно еще, зачем делать

my @m = @{$hosts{$host}};
foreach my $r (@m)

когда значительно быстрее будет работать прямо

foreach my $r (@{$hosts{$host}})
Enilatiar:
foreach my $r (@{$hosts{$host}})
Голова моя не вмещает прямого разыменования. Точнее язык не может произнести foreach @{$hosts{$host}} -- "для каждого из массива [...]". Куда проще "@m - это такой массив, который образуется [...]". :)

Кстати, адрес http://dklab.ru/cgi/todaylog/todaylog.cgi рисует 500 ошибку. Попытка отправить на него замечание, рисует 404 ошибку...
А так хочется посмотреть, что происиходит на больших объемах лога...

В частности, если делать пейджин (страничность), то страницы будут видимо "часовые". То есть, что-то типа "00:00-10:00, 10:00-16:00, 16:00-24:00".
Поскольку, я предполагаю, что узким местом производительности является именно прямое чтение огромного файла. На выходе, по-моему, в результате получается не большой объем.
Дмитрий Котеров:
рисует 500 ошибку
Значит, все-таки не хватает процессорного времени.

Эта тема на forum.dklab.ru