Apache Web server может не только показывать
страницы пользователям, но и со всей
тщательностью записывать данные об их
активности и ошибках. По умолчанию, все
сведения о запросах пользователей пишутся
в один лог, а об ошибках - в другой.
Естественно, смысл записей и их положение
на сервере можно произвольно настраивать,
чем мы сегодня и займемся.
Default Logs
Как я уже сказал в предисловии, по
умолчанию сервер пишет лог в два файла - /var/log/httpd/access_log
и error_log в той же директории. Такое положение
дел определяется, конечно, в httpd.conf
параметрами TransferLog и ErrorLog. Примерно это
происходит так:
TransferLog /data/apache/logs/gen_msg
ErrorLog /data/apache/logs/error_msg
Помимо разделения логов по файлам мы
можем создать отдельный лог для каждого
домена, который крутится на Apache.
Предположим, что на сервере крутится два
домена и мы хотим что бы каждый домен писал
лог в свою директорию. Пример:
ServerName www.company_a.com
DocumentRoot /data/apache/co_a/html
TransferLog /data/apache/co_a/logs/gen_msg
ErrorLog /data/apache/co_a/logs/error_msg
ServerName www.company_b.com
DocumentRoot /data/apache/co_b/html
TransferLog /data/apache/co_b/logs/gen_msg
ErrorLog /data/apache/co_b/logs/error_msg
Ясно, что в таком конфиге не только
документы будут разделяться по разным
каталогам, но и логи. Отметьте, что записи лежат вне DocumentRoot,
что довольно неплохо для обеспечения
безопасности.
Уровень логов
Существует несколько уровней при помощи
которых можно настроить глубину записи
активности Web-сервера. Уровни логов такие: emerg,
alert, crit, error, warn, notice, info
и debug. Дописывая определение уровня в
конец директивы, управляющей логгированием,
мы можем определить, что именно писать.
Например, я хочу заставить Apache записывать
неотложные записи и предупреждения только
для одного из доменов. В контейнере нужного
домена делаем так:
...
LogLevel alert
Формат Логов
Формат, в котором сервер делает записи,
так же можно произвольно менять. Делается
это директивой LogFormat все в том же htttpd.conf.
По дефолту выглядит запись примерно так:
12.127.17.72 - russell [21/Jun/2004:11:50:20 -0500]
"GET /cgi-bin/admin/index.cgi HTTP/1.1" 200 5528
В примере записан IP адрес или имя хоста,
идентификационная информация клиента, имя
пользователя, дата и время. В кавычках -
метод запроса и имя запрашиваемого файла с
версией HTTP. После этого - результат, статус и
количество переданных байт. В примере видно,
что код 200 (ОК).
Для изменения формата надо описать его
в LogFormat и передать имя потом в описание лога.
Если описание дается вне контейнера, то его
можно использовать для любого лога, в
данном примере задается путь и формат лога:
LogFormat "Date: %t, Host: %h, User: %u, File Requested: %r" simple
...
...
CustomLog /data/apache/co_a/logs/gen_msg simple
...
Помимо приведенных в примере кодов можно
использовать %a для IP адреса, %b для
количества байт, %f для имени файла, %i для
заголовка запроса, %s для статуса. Полностью
список кодов можно найти
на сайте Apache. Пример работы приведенного
выше лога:
Date: [21/Jun/2004:22:21:10 -0500],
Host: 12.127.17.72, User: russell,
File Requested: GET /cgi-bin/admin/index.cgi HTTP/1.1
Еще один пример - предположим я хочу
получить в лог только заголовок запроса от
другого сайта, поисковой машины.
CustomLog search_eng_log "%{Referer}i"
Обратите внимание, что {Referer} идет между %
и i, а так же на то, что пропущено
создание имени для упрощения описания.
Такой лог будет складировать адрес
поисковика и поисковый параметр - очень
удобно для понимания кто и что находит на
сайте. Для
примера можно попробовать писать {User-agent}
пытаясь узнать кто и каким броузером лазит
на сайт.
Включение и исключение
На своем сайте я предпочитаю запросы с
собственной рабочей станции записывать в
отдельный лог, это упрощает отладку
скриптов и самого сервера. Вводим
переменную и по ней определяем куда и что
класть:
SetEnvIf Remote_Addr "12.127.17.72" my_stuff
CustomLog logs/my_access complex env=my_stuff
CustomLog logs/gen_msg simple env=!my_stuff
Ротация
Всем понятно, что логи приличного сервера
разрастаются довольно быстро. По умолчанию
они очищаются каждую неделю: access_log
копируется в access_log.1, access_log.1 в access_log.2 и так
далее (в обратном порядке разумеется).
Однако если вы устанавливаете собственные
логи, то нужно задать и их ротацию. Сделать
это можно несколькими путями. ИМХО лучше
всего написать простой скрипт для cron, который
затем регулярно выполнять:
#!/bin/bash
mv -f gen_msg.2 gen_msg.3
mv -f gen_msg.1 gen_msg.2
mv -f gen_msg gen_msg.1
apachectl graceful