Файлы журналов
Для эффективного управления веб-сервером необходимо получать сведения о его активности и производительности, а также о возможных проблемах. Сервер Apache HTTP Server предоставляет широкие и гибкие возможности ведения журналов. В этом документе описывается настройка этих возможностей и способы анализа содержимого журналов.
Общие сведения
| Связанные модули | Связанные директивы |
|---|---|
Сервер Apache HTTP Server предоставляет различные механизмы для регистрации всех событий на сервере: от первоначального запроса и процесса сопоставления URL до окончательного завершения соединения, включая ошибки, которые могли возникнуть в процессе. Кроме того, сторонние модули могут предоставлять возможности ведения журналов или добавлять записи в существующие файлы журналов, а приложения, такие как программы CGI, сценарии PHP и другие обработчики, могут отправлять сообщения в журнал ошибок сервера.
В этом документе рассматриваются модули ведения журналов, входящие в стандартную поставку HTTP-сервера.
Предупреждение о безопасности
Любой, кто может записывать данные в каталог, где Apache httpd сохраняет файл журнала, почти наверняка может получить доступ к учётной записи uid, от имени которой запущен сервер, обычно root. НЕ предоставляйте пользователям доступ на запись к каталогу с журналами, не учитывая возможных последствий; подробности см. в документе рекомендации по безопасности.
Кроме того, файлы журналов могут содержать данные, напрямую переданные клиентом и не прошедшие экранирование. Поэтому злоумышленники могут вставлять управляющие символы в файлы журналов, и при работе с необработанными журналами следует соблюдать осторожность.
Журнал ошибок
| Связанные модули | Связанные директивы |
|---|---|
Журнал ошибок сервера, имя и расположение которого задаются директивой ErrorLog, — самый важный файл журнала. В него Apache httpd записывает диагностическую информацию и ошибки, возникающие при обработке запросов. Если возникают проблемы при запуске или работе сервера, в первую очередь следует проверить именно этот журнал: в нём часто содержатся сведения о том, что произошло и как это исправить.
Журнал ошибок обычно записывается в файл (как правило, error_log в системах Unix и error.log в Windows и OS/2). В системах Unix сервер также может отправлять ошибки в syslog или передавать их по каналу программе.
Формат журнала ошибок задаётся директивой ErrorLogFormat, с помощью которой можно настроить, какие значения будут записываться. Если формат не указан, используется формат по умолчанию. Типичное сообщение в журнале выглядит так:
[Fri Sep 09 10:42:29.902022 2011] [core:error] [pid 35708:tid 4328636416] [client 72.15.99.187] File does not exist: /usr/local/apache2/htdocs/favicon.ico
Первым элементом записи журнала являются дата и время сообщения. Далее указаны модуль, создавший сообщение (в данном случае core), и уровень его важности. Затем следуют идентификатор процесса и, если применимо, идентификатор потока, в котором возникла проблема. После этого указывается адрес клиента, отправившего запрос. Последним идёт подробное сообщение об ошибке, которое в данном случае сообщает о запросе несуществующего файла.
В журнале ошибок могут появляться самые разные сообщения. Большинство из них похоже на приведённый выше пример. В журнал ошибок также записываются отладочные сообщения сценариев CGI. Любая информация, записанная сценарием CGI в stderr, будет напрямую скопирована в журнал ошибок.
Если добавить маркер %L и в журнал ошибок, и в журнал доступа, в записях появится идентификатор, позволяющий сопоставить запись в журнале ошибок с записью в журнале доступа. Если загружен mod_unique_id, в качестве идентификатора записи журнала также будет использоваться его уникальный идентификатор запроса.
Во время тестирования часто полезно непрерывно следить за журналом ошибок, чтобы вовремя замечать проблемы. В системах Unix это можно сделать с помощью команды:
tail -f error_log
Ведение журналов для отдельных модулей
Директива LogLevel позволяет задавать уровень важности сообщений журнала отдельно для каждого модуля. Так, если вы устраняете проблему только в одном конкретном модуле, можно увеличить объём его журналирования, не получая подробные сведения о других, не интересующих вас модулях. Это особенно полезно для таких модулей, как mod_proxy или mod_rewrite, когда необходимо знать, что именно они пытаются сделать.
Для этого укажите имя модуля в директиве LogLevel:
LogLevel info rewrite:trace5
Эта настройка устанавливает для основного LogLevel уровень info, но повышает его до trace5 для mod_rewrite.
RewriteLog, которые использовались в предыдущих версиях сервера.Журнал доступа
| Связанные модули | Связанные директивы |
|---|---|
В журнале доступа сервера регистрируются все обработанные им запросы. Расположение и содержимое журнала доступа задаются директивой CustomLog. Директива LogFormat позволяет упростить выбор записываемых в журнал данных. В этом разделе описывается настройка регистрации сведений в журнале доступа.
Сохранение данных в журнале доступа — лишь первый этап работы с журналами. Далее необходимо проанализировать эти данные, чтобы получить полезную статистику. Анализ журналов в целом выходит за рамки этого документа и не относится непосредственно к задачам веб-сервера.
В различных версиях Apache httpd для управления журналированием доступа использовались другие модули и директивы, в том числе mod_log_referer, mod_log_agent и директива TransferLog. Теперь директива CustomLog объединяет возможности всех прежних директив.
Формат журнала доступа можно гибко настраивать. Он задаётся строкой формата, которая во многом похожа на строку формата printf(1) в стиле C. В следующих разделах приведены примеры. Полный список элементов, допустимых в строке формата, см. в разделе mod_log_config строки формата.
Общий формат журнала
Типичная настройка журнала доступа может выглядеть следующим образом.
LogFormat "%h %l %u %t \"%r\" %>s %b" common CustomLog logs/access_log common
Здесь задаётся псевдоним common и ему сопоставляется определённая строка формата журнала. Строка формата состоит из директив с символом процента, каждая из которых указывает серверу записать определённые данные. В строку формата можно также включать обычные символы — они будут напрямую скопированы в журнал. Символ кавычки (") необходимо экранировать, поставив перед ним обратную косую черту, чтобы он не был воспринят как конец строки формата. В строке формата также могут использоваться специальные управляющие символы: «\n» для перевода строки и «\t» для табуляции.
Директива CustomLog создаёт новый файл журнала, используя заданный псевдоним. Имя файла журнала доступа задаётся относительно ServerRoot, если только оно не начинается с косой черты.
В приведённой выше конфигурации записи будут сохраняться в формате, известном как общий формат журнала (Common Log Format, CLF). Этот стандартный формат поддерживается многими веб-серверами и программами анализа журналов. Записи в файле журнала в формате CLF будут выглядеть примерно так:
127.0.0.1 - frank [10/Oct/2000:13:55:36 -0700] "GET /apache_pb.gif HTTP/1.0" 200 2326
Ниже описана каждая часть этой записи.
-
127.0.0.1(%h) - Это IP-адрес клиента (удалённого узла), отправившего запрос серверу. Если для
HostnameLookupsзадано значениеOn, сервер попытается определить имя узла и записать его вместо IP-адреса. Однако такая настройка не рекомендуется, поскольку она может существенно замедлить работу сервера. Вместо этого лучше использовать программу постобработки журналов, напримерlogresolve, чтобы определить имена узлов. Указанный здесь IP-адрес не обязательно принадлежит компьютеру, за которым находится пользователь. Если между пользователем и сервером есть прокси-сервер, здесь будет указан адрес прокси, а не исходного компьютера. -
-(%l) - Дефис в выводе означает, что запрошенные сведения недоступны. В данном случае недоступна идентификационная информация клиента по RFC 1413, которую определяет
identdна компьютере клиента. Этим сведениям нельзя доверять; практически никогда не следует использовать их, за исключением строго контролируемых внутренних сетей. Apache httpd даже не попытается получить эту информацию, если дляIdentityCheckне задано значениеOn. -
frank(%u) - Это идентификатор пользователя, запросившего документ, определённый средствами HTTP-аутентификации. Обычно то же значение передаётся сценариям CGI в переменной окружения
REMOTE_USER. Если код состояния запроса (см. ниже) равен 401, этому значению не следует доверять, так как пользователь ещё не прошёл аутентификацию. Если документ не защищён паролем, в этом поле, как и в предыдущем, будет указано «-». -
[10/Oct/2000:13:55:36 -0700](%t) - Время получения запроса. Формат:
[day/month/year:hour:minute:second zone] day = 2*digit month = 3*letter year = 4*digit hour = 2*digit minute = 2*digit second = 2*digit zone = (`+' | `-') 4*digit
Время можно выводить в другом формате, указав
%{format}tв строке формата журнала, гдеformatсоответствует либо форматуstrftime(3)из стандартной библиотеки C, либо одному из поддерживаемых специальных маркеров. Подробнее см. в разделеmod_log_configстроки формата. -
"GET /apache_pb.gif HTTP/1.0"(\"%r\") - Строка запроса клиента заключается в двойные кавычки. Она содержит много полезной информации. Во-первых, клиент использовал метод
GET. Во-вторых, клиент запросил ресурс/apache_pb.gif. В-третьих, клиент использовал протоколHTTP/1.0. Также можно отдельно записывать одну или несколько частей строки запроса. Например, строка формата «%m %U%q %H» будет записывать метод, путь, строку запроса и протокол, в результате чего получится точно такой же вывод, как и для «%r». -
200(%>s) - Это код состояния, который сервер отправляет клиенту. Эти сведения очень важны, поскольку показывают, был ли запрос успешно обработан (коды, начинающиеся с 2), перенаправлен (коды, начинающиеся с 3), завершился ошибкой со стороны клиента (коды, начинающиеся с 4) или ошибкой сервера (коды, начинающиеся с 5). Полный список возможных кодов состояния приведён в спецификации HTTP (RFC 2616, раздел 10).
-
2326(%b) - Последняя часть указывает размер объекта, возвращённого клиенту, без учёта заголовков ответа. Если клиенту не было возвращено содержимое, здесь будет указано «
-». Чтобы при отсутствии содержимого записывать «0», используйте вместо этого%B.
Объединённый формат журнала
Ещё один широко используемый формат строки называется объединённым форматом журнала (Combined Log Format). Его можно задать следующим образом.
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\"" combined
CustomLog log/access_log combined Этот формат полностью совпадает с общим форматом журнала, но содержит два дополнительных поля. Для каждого из них используется директива %{header}i, где header может быть любым заголовком HTTP-запроса. Журнал доступа в этом формате будет выглядеть так:
127.0.0.1 - frank [10/Oct/2000:13:55:36 -0700] "GET /apache_pb.gif HTTP/1.0" 200 2326 "http://www.example.com/start.html" "Mozilla/4.08 [en] (Win98; I ;Nav)"
Дополнительные поля:
-
"http://www.example.com/start.html"(\"%{Referer}i\") - Заголовок HTTP-запроса «Referer» (так в оригинале). Он указывает сайт, с которого, по сообщению клиента, был выполнен переход. (Это должна быть страница, содержащая ссылку на
/apache_pb.gifили включающая его.) -
"Mozilla/4.08 [en] (Win98; I ;Nav)"(\"%{User-agent}i\") - Заголовок HTTP-запроса User-Agent. Он содержит идентификационные сведения о браузере клиента, которые тот сообщает о себе.
Несколько журналов доступа
Чтобы создать несколько журналов доступа, достаточно указать в файле конфигурации несколько директив CustomLog. Например, следующие директивы создадут три журнала доступа. Первый будет содержать основные сведения в формате CLF, а второй и третий — сведения о ссылке-источнике и браузере. Последние две строки CustomLog показывают, как воспроизвести действие директив ReferLog и AgentLog.
LogFormat "%h %l %u %t \"%r\" %>s %b" common
CustomLog logs/access_log common
CustomLog logs/referer_log "%{Referer}i -> %U"
CustomLog logs/agent_log "%{User-agent}i" Этот пример также показывает, что задавать псевдоним с помощью директивы LogFormat необязательно. Вместо этого формат журнала можно указать непосредственно в директиве CustomLog.
Условное ведение журналов
Иногда удобно исключить из журналов доступа определённые записи на основе характеристик запроса клиента. Это легко сделать с помощью переменных окружения. Сначала необходимо задать переменную окружения, указывающую, что запрос соответствует определённым условиям. Обычно для этого используется SetEnvIf. Затем с помощью условия env= директивы CustomLog включают или исключают запросы, для которых задана переменная окружения. Например:
# Mark requests from the loop-back interface SetEnvIf Remote_Addr "127\.0\.0\.1" dontlog # Mark requests for the robots.txt file SetEnvIf Request_URI "^/robots\.txt$" dontlog # Log what remains CustomLog logs/access_log common env=!dontlog
Рассмотрим ещё один пример: запросы от англоговорящих пользователей записываются в один файл журнала, а запросы от пользователей, не говорящих по-английски, — в другой.
SetEnvIf Accept-Language "en" english CustomLog logs/english_log common env=english CustomLog logs/non_english_log common env=!english
При использовании кэширования может понадобиться оценить его эффективность. Самый простой способ сделать это:
SetEnv CACHE_MISS 1
LogFormat "%h %l %u %t "%r " %>s %b %{CACHE_MISS}e" common-cache
CustomLog logs/access_log common-cache mod_cache выполняется перед mod_env и при успешном выполнении отдаёт содержимое без его участия. В этом случае попадание в кэш будет записано как -, а промах кэша — как 1.
Помимо синтаксиса env=, LogFormat поддерживает условную запись данных в зависимости от кода ответа HTTP:
LogFormat "%400,501{User-agent}i" browserlog
LogFormat "%!200,304,302{Referer}i" refererlog В первом примере User-agent будет записано, если код состояния HTTP равен 400 или 501. В остальных случаях вместо этого будет записан буквальный символ «-». Аналогично, во втором примере Referer будет записано, если код состояния HTTP не равен 200, 304 или 302. (Обратите внимание на «!» перед кодами состояния.)
Хотя условное ведение журналов — очень мощный и гибкий инструмент, это не единственный способ управлять содержимым журналов. Журналы полезнее, когда в них содержится полная запись активности сервера. Часто проще просто обработать файлы журналов после записи и удалить запросы, которые не нужно учитывать.
Ротация журналов
Даже на умеренно загруженном сервере в файлах журналов накапливается очень много данных. Файл журнала доступа обычно увеличивается на 1 МБ или более на каждые 10 000 запросов. Поэтому журналы необходимо периодически ротировать, перемещая или удаляя существующие файлы. Пока сервер работает, этого делать нельзя: Apache httpd продолжит запись в старый файл журнала, пока тот остаётся открытым. Вместо этого после перемещения или удаления файлов журналов сервер необходимо перезапустить, чтобы он открыл новые файлы журналов.
При плавном перезапуске сервер может открыть новые файлы журналов, не разрывая существующие или ожидающие обработки соединения с клиентами. Однако для этого серверу необходимо продолжать записывать данные в старые файлы журналов, пока он завершает обработку старых запросов. Поэтому после перезапуска следует подождать некоторое время, прежде чем выполнять какие-либо действия с файлами журналов. Типичный сценарий, в котором журналы ротируются, а старые файлы сжимаются для экономии места, выглядит так:
mv access_log access_log.old mv error_log error_log.old apachectl graceful sleep 600 gzip access_log.old error_log.old
Другой способ ротации журналов — использовать журналы, передаваемые по каналу, как описано в следующем разделе.
Журналы, передаваемые по каналу
Apache httpd может записывать журналы ошибок и доступа, передавая данные по каналу другому процессу, а не напрямую в файл. Эта возможность значительно расширяет гибкость ведения журналов, не требуя добавления кода в основной сервер. Чтобы записывать журналы через канал, просто замените имя файла символом канала «|», за которым укажите имя исполняемого файла программы, которая будет принимать записи журнала через стандартный ввод. Сервер запускает процесс обработки журнала по каналу при старте и перезапускает его, если тот аварийно завершится во время работы сервера. (Именно поэтому этот способ называют «надёжным ведением журналов через канал».)
Процессы обработки журналов по каналу запускаются родительским процессом Apache httpd и наследуют его идентификатор пользователя. Это означает, что программы обработки журналов по каналу обычно выполняются с правами root. Поэтому очень важно, чтобы такие программы были простыми и безопасными.
Одно из важных применений журналов, передаваемых по каналу, — ротация журналов без перезапуска сервера. Для этого в состав Apache HTTP Server входит простая программа rotatelogs. Например, чтобы ротировать журналы каждые 24 часа, можно использовать:
CustomLog "|/usr/local/apache/bin/rotatelogs /var/log/access_log 86400" common
Обратите внимание: вся команда, которая будет вызвана для канала, заключена в кавычки. Хотя в этих примерах рассматривается журнал доступа, тот же способ можно использовать и для журнала ошибок.
Как и условное ведение журналов, передача журналов по каналу — очень мощный инструмент, но его не следует использовать, если доступно более простое решение, например автономная постобработка.
По умолчанию процесс обработки журнала по каналу запускается без вызова оболочки. Используйте «|$» вместо «|», чтобы запускать процесс через оболочку (обычно с /bin/sh -c):
# Invoke "rotatelogs" using a shell CustomLog "|$/usr/local/apache/bin/rotatelogs /var/log/access_log 86400" common
Такое поведение использовалось по умолчанию в Apache 2.2. В зависимости от особенностей оболочки это может привести к дополнительному процессу оболочки, который будет работать всё время, пока запущена программа обработки журнала, а также к проблемам с обработкой сигналов при перезапуске. Для совместимости с Apache 2.2 также поддерживается запись «||», эквивалентная использованию «|».
Примечание для Windows
Обратите внимание: в Windows при запуске большого числа процессов журналирования по каналу могут возникать проблемы, особенно если HTTPD работает как служба. Это происходит из-за нехватки пространства кучи рабочего стола. Объём пространства кучи рабочего стола, выделяемого каждой службе, задаётся третьим аргументом параметра SharedSection в значении реестра HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\SessionManager\SubSystems\Windows. Изменяйте это значение осторожно: при изменении реестра Windows действуют обычные меры предосторожности, однако слишком большое значение может привести к исчерпанию пула кучи рабочего стола.
Виртуальные хосты
При работе сервера с несколькими виртуальными хостами есть несколько способов организовать файлы журналов. Во-первых, можно использовать журналы так же, как на сервере с одним хостом. Если разместить директивы журналирования за пределами секций <VirtualHost> в контексте основного сервера, все запросы можно записывать в один журнал доступа и один журнал ошибок. Этот способ не позволяет легко собирать статистику по отдельным виртуальным хостам.
Если директивы CustomLog или ErrorLog размещены внутри секции <VirtualHost>, все запросы или ошибки для этого виртуального хоста будут записываться только в указанный файл. Запросы виртуальных хостов, для которых директивы журналирования не заданы, по-прежнему будут попадать в журналы основного сервера. Этот способ очень удобен для небольшого числа виртуальных хостов, но при большом количестве хостов управление журналами может усложниться. Кроме того, это часто приводит к проблемам из-за нехватки файловых дескрипторов.
Для журнала доступа есть удачный компромиссный вариант. Добавив сведения о виртуальном хосте в строку формата журнала, можно записывать данные для всех хостов в один журнал, а затем разделить его на отдельные файлы. Рассмотрим следующие директивы.
LogFormat "%v %l %u %t \"%r\" %>s %b" comonvhost CustomLog logs/access_log comonvhost
Для записи имени виртуального хоста, обрабатывающего запрос, используется %v. Затем для постобработки журнала доступа и разделения его на отдельные файлы для каждого виртуального хоста можно использовать такую программу, как split-logfile.
Другие файлы журналов
| Связанные модули | Связанные директивы |
|---|---|
Регистрация фактического объёма отправленных и полученных данных
mod_logio добавляет два дополнительных поля LogFormat (%I и %O), в которых регистрируется фактическое количество байтов, полученных и отправленных по сети.
Криминалистическое журналирование
mod_log_forensic обеспечивает криминалистическую регистрацию запросов клиентов. Запись выполняется до и после обработки запроса, поэтому для каждого запроса в журнале появляются две строки. Средство криминалистического журналирования строго ограничено и не допускает настройки. Оно может стать незаменимым инструментом отладки и обеспечения безопасности.
Файл PID
При запуске Apache httpd сохраняет идентификатор процесса родительского процесса httpd в файл logs/httpd.pid. Имя этого файла можно изменить с помощью директивы PidFile. Администратор использует идентификатор процесса, чтобы перезапустить или завершить работу демона, отправив сигналы родительскому процессу; в Windows вместо этого используйте параметр командной строки -k. Дополнительные сведения см. на странице Остановка и перезапуск.
Журнал сценариев
Для упрощения отладки директива ScriptLog позволяет записывать входные и выходные данные сценариев CGI. Используйте её только при тестировании, а не на работающих серверах. Дополнительные сведения приведены в документации mod_cgi.
© 2018 The Apache Software Foundation
Licensed under the Apache License, Version 2.0.
https://httpd.apache.org/docs/2.4/en/logs.html