Профессиональная разработка Web-приложений.  
Боишься нашего дизайна?
Новости
PDF журнал
Участники проектa
Сотрудничество
Ссылки
Карта сайта
Комментарии
Комментарии к статье
Добавить комментарий
Обсудить на форуме
Информация об авторе
Оценка статьи

Работа с БД. Анализ логов.

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

Хочу снова похвалиться своим "творчеством".

В декабре я описал, как проще всего собирать логи. Сейчас я покажу, как их можно анализировать.

Что там было в таблице? Дата, адрес от корня виртуального хоста ($PHP_SELF), броузер, реферер, ip-адрес пользователя и имя хоста. Строка вставлялась так:

@mysql_query("INSERT INTO logs (date, ip, host, address, referer, browser) VALUES (NOW(), '$REMOTE_ADDR', '". gethostbyaddr($REMOTE_ADDR). "', '$PHP_SELF', '$HTTP_REFERER', '$HTTP_USER_AGENT')");

А что мы хотим видеть в статистике? Просто посмотрим разные варианты: посещения по дням, распределение посещений по времени суток. Затем эти же две выборки, только не для всех логов, а для главной страницы. Распределение по дням недели, посещаемость за последние недели и месяцы. Количество посетителей, пришедших с других сайтов. Бывает интересно посмотреть, сколько посетителей приходило с определённой ссылки в разные дни. Распределение по времени за определённый день (неделю, месяц). Адреса, куда уходят с такой-то страницы.

Систематизировать это не так сложно, как кажется. Всё вышеописаное укладывается в восемь вариантов группировки таблицы. Адрес, реферер, броузер (увы, тут получается сравнение строчек "HTTP_USER_AGENT", включающих в себя и версии, и ОС, а не отдельных броузеров. Тут без обработки на входе не обойтись), день, неделя, месяц, день недели, час.

На статистику по странам, городам, а так же маршруты пользователей не замахиваемся — тоже нужна дополнительная обработка.

Добавим к выбору группировки выбор ограничения по дням (последние n дней) а так же условия выборки для поля WHERE, которые можно ввести в текстовое поле, и получим систему, в которую укладывается те выборки и распределения, которые я описал.

На самом деле, не так просто оказалось составить список выборок и привести его к удобному для обработки в программе виду. В конце концов, я взял и запихал все запросы в массив, элемент которого выглядит так:

$selection[0] = array(
  "name" => "график по дням",
  "select" => array("date_format(date,'%e.%m.%Y') as dday", "count(date) as visits"),
  "group" => array("dday"),
  "order" => array("date DESC"),
  "type" => 1
  );

Элемент "name" — это название для крутилки, "type" — тип таблицы. Типов таблиц два — просто список и список со "столбиками". Если список сортируется по количеству посещений, то столбики в принципе не нужны, а для удобства восприятия, например, графика посещений по дням, график желателен. Остальные элементы можно не комментировать.

В запросе учитываются так же и временные ограничения, и условие, которое ввёл пользователь. Переменная $type — номер запрашиваемой выборки.

$days = intval($days);
if ($days>0)
  $selection[$type]["where"][] = "date>DATE_SUB(NOW(),INTERVAL $days DAY)";

$where = stripslashes(trim($where));
if (strlen($where)>0)
  $selection[$type]["where"][] = "($where)";

После этого рисуется форма (в крутилках первыми строчками выводятся выбранные значения. Затем строится запрос, которым узнаётся общее количество строк. Это, надо признать, скользкое место, потому что в нём никаких упрощений, просто в отличие от основного запроса, здесь просто отсутствует сортировка. Но количество строк узнаётся "в лоб" — выбирается всё то же самое и потом делается mysql_num_rows. Если у кого будут идеи, можете прислать мне или публиковать свой анализатор (только ссылку на меня поставьте, пожалуйста).

$amount_request = "SELECT ". implode(", ", $selection[$type]["select"]). " FROM logs ";
if (sizeof($selection[$type]["where"])>0)
  $amount_request .= " WHERE ". implode(" AND ", $selection[$type]["where"]);
$amount_request .= " GROUP BY ". implode(", ", $selection[$type]["group"]);

$request = "SELECT ". implode(", ", $selection[$type]["select"]). " FROM logs ";
if (sizeof($selection[$type]["where"])>0)
 $request .= " WHERE ". implode(" AND ", $selection[$type]["where"]);
$request .= " GROUP BY ". implode(", ", $selection[$type]["group"]). 
	" ORDER BY ". implode(", ", $selection[$type]["order"]). " ". 
	get_limit($page, $amount, $in_page);

Как видите, я использую описанный в предыдущем выпуске модуль постраничного вывода запросов (get_limit).

Но мало дать неограниченные возможности построения запросов. Вот, допустим, смотрю я на статистику рефереров по популярности и хочу посмотреть, как народ шёл ко мне с hackzone.ru. Что делать? Выбирать нужные параметры крутилок и писать в текстовом поле "referer like '%hackzone%'" ну просто влом!

Оказывается, это тоже несложно сделать. Два часа мыслительных усилий и редактирования текста, и вот вышла некое подобие возможности детализации выборки. Нажимаю "список рефереров" в закладках (в закладках, потому что в адресе передаётся параметр "referer not like 'http://phpclub.ru%'"), получаю таблицу, в ней в строке "hackzone.ru" нажимаю на ссылку и вот оно, распределение зашедших с этого сайта по дням. Можно нажать на другую ссылку и получить распределение по времени суток — как угодно.

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

В принципе, имея логи у себя на офисной или домашней машине, можно делать с ними всё, что душе угодно. Надо только написать обработчик. Делов-то! :) На SpyLog я не претендую. По крайней мере, для себя я написал такую вещь, которая позволяет делать многое из того, что угодно душе. И, кстати, не грузить лишнюю информацию и рекламу Спайлог-информера и прочего.




For comment register here
   2001-06-14 16:14
Что ж, решение стандартное, каждый веб-программист с такого и начинает :). (нечто подобное делал и я) А что будет с сайтом у которого большой траффик?? Через какое время БД логов забьется под завязку? Сколько потребуется времени MySql-у чтобы переварить свои сотни тысяч записей, для составления статистики? Может необходимо подумать о вычислении каких-то промежуточных результатов, и хранить только их? Скажу, что я эту проблемму еще не решил... Хотелось бы услышать мнения на этот счет

   2001-06-20 08:57
1. Берётся халявная Виртуоза ( http://www.openlinksw.com ), а вовсе не MySql. Хотя бы потому, что primary key будет расти абсолютно монотонно, и MySql "заболеет" после right-edge вставки 100000 записей.
2. Не берётся PHP вообще. (Ау, модератор, здесь дальше сплошной оффтопик).
3. Импорт данных не есть проблема, даже если их глотать просто из Apache-вского лог-файла. Для разбиения каждой строки на поля есть напр. split_and_decode(...), а для особенно изощрённой обработки HTTP-USER-AGENT есть regexp_...(...).
Можно повесить импорт на таймер, напр. читать новые/подросшие файлы каждые 15 минут.
4. Пишется набор тривиальных VSP-страничек. Ну то есть совсем тривиальных. Данные для них можно собрать "на лету", можно готовить при помощи триггера (обновлять табличку с готовыми статистиками after insert of записи из лога с номером кратным 1000), можно опять же повесить функцию на таймер.

Поскольку это Виртуоза, о скорости можно особенно не думать. Специальные хитрости действительно необходимы только при годовом логе по мегабайту в день.

   Unknown 2001-06-27 15:08
По моему этот способ очень хорош для тех случаев когда логи за год просто не требуются. У меня например давно работает подобная вещь и лог чистится еженелдельно потому что мне больше не надо.

   2001-08-17 10:00
Во многом согласен с Андреем. Вычисление статистики делается не для пользователя, а я подожду ;)) Несколько слов об объеме базы. При посещаемости 250 стр/день за год не наберется и одной сотни тысяч. Но для сайтов с иной посещаемостью эта проблема имеется. C желательностью сотавления "промежуточных результатов" (с) я уже столкнулся. На мой взгляд, здесь нет ничего принципиального. Такого рода архивация предусматривает потерю некоторых данны, и, следовательно, невозможности получения некоторых отчетов. Но так ли нам нужны ВСЕ виды отчетов за предыдущий год (полугодие) ? Некоторое неудобство - немного иная структура таблицы и другие программы. Оговорюсь, что программу эту я пока не писал.

   2005-07-07 09:30
А что если в конце каждой недели или в 00:00 не очищать базу, сохраняя данные в виде html страниц с необходимой информацией, а базу очищать cron'ом

 
 
 
    © 1997-2008 PHPClubTeam
[]