$put_perv_real = "/home/www/dvakompa-ru/dopol/"; ?>
1. Виды и модули журналов. Формат логов доступа Apache
1.1 Виды логов Apache
1.2 Модули логов Apache
1.3 Модуль mod_log_config
1.4 Access Log (журнал доступа)
1.5 Как настроить формат логов Apache. Пользовательские форматы журналов
1.6 Директива BufferedLogs
1.7 Директива CustomLog
1.8 Директива GlobalLog
1.9 Директива LogFormat
1.10 Директива TransferLog
1.11 Форматы журналов Apache
1.11.1 Common Log Format (общий формат журнала)
1.11.2 Combined Log Format (Формат комбинированного журнала)
1.11.3 Multiple Access Logs (Журналы множественного доступа)
1.11.4 Conditional Logs (логи с условиями)
1.12 Ротация логов
1.13 Конвейерная обработка (Piped Logs)
1.14 Виртуальные Хосты
1.15 Вопросы безопасности
2. Формат логов ошибок. Журнал событий модулей
3. Программы для анализа логов Apache
4. Криминалистические логи
5. Дополнительные настраиваемые журналы отладки. Журналы выполнения CGI скриптов
Примечание: данный цикл статей посвящён файлам журналов (логам) веб-сервера Apache, рассматривается их настройка, формат, команды, а также специальные программы для анализа журналов веб-сервера. Информация изложена подробно для глубокой проработки темы, а также для использования в качестве справочного материала. Если вам нужна более краткая информация, то рекомендуется обратиться к статье «Apache log (логи): как настроить и анализировать журналы веб-сервера».
Чтобы эффективно управлять веб-сервером, необходимо получать отзывы об активности и производительности сервера, а также о любых проблемах, которые могут возникнуть. HTTP-сервер Apache предоставляет очень широкие и гибкие возможности ведения журналов.
HTTP-сервер Apache предоставляет множество различных механизмов для регистрации всего, что происходит на вашем сервере, от первоначального запроса и процесса сопоставления URL-адресов, до окончательного разрешения соединения, включая любые ошибки, которые могли возникнуть в процессе. В дополнение к этому сторонние модули могут предоставлять возможности ведения журналов или вставлять записи в существующие файлы журналов, а приложения, такие как программы CGI, сценарии PHP или другие обработчики, тоже могут отправлять сообщения в журнал ошибок сервера.
Журналы веб-сервер содержат массу интересной информации! По логам доступа сервера можно составить собирательный портрет аудитории: в каких странах и городах живут, какими операционными системами пользуются, какими браузерами просматривают сайт, в какое время активны больше всего, с каких сайтов пришли к вам, какие поисковые системы предпочитают, сколько страниц просматривают за каждое посещение сайта. И не менее важны логи для мониторинга состояния веб-сервера и сайтов: какие страницы не были найдены, ошибки веб-сервера, степень загруженности, выявление активности ботов, выявление вредоносной активности, поиск следов взлома, выявление путей взлома.
В общем, журналы доступа сервера должны понимать, уметь настраивать и использовать, в первую очередь, веб-мастера и системные администраторы, обслуживающие сервер. В то же самое время, атакующему, или тому, кто исследует последствия действий атакующего, также нужно понимать, что именно сохраняется в логи веб-сервера, какую выгоду из них можно извлечь или как замаскировать свои следы, либо как анализировать файлы журналов доступа для поиска проблем, атак и следов взлома.
Первая часть посвящена настройке формата журналов в веб-сервере Apache. Эта информация пригодится вам даже если даже если у вас нет сайтов и вы не занимаетесь обслуживанием веб-сервера. Она понадобится чтобы уметь анализировать веб журналы с помощью инструментов (как правило в них нужно указать формат анализируемого журнала, для указания которых используются те же спецификаторы, что и в конфиге Apache).
Различные виды журналов Apache управляются разными модулями веб-сервера и имеют разные управляющие директивы и возможности указать формат строки лога.
Имеются следующие виды логов веб-сервера Apache:
Далее дана краткая характеристика каждого вида журнала, а затем в этой первой части будет подробно рассмотрен Журнал доступа. В последующих частях будут подробно рассмотрены другие виды логов.
Журнал ошибок сервера является наиболее важным файлом журнала. Это место, куда Apache httpd будет отправлять диагностическую информацию и записывать любые ошибки, с которыми он сталкивается при обработке запросов. Это первое место, где нужно посмотреть, когда возникает проблема с запуском сервера или работой сервера, поскольку он часто содержит подробности о том, что пошло не так и как это исправить.
Директива LogLevel позволяет вам указывать уровень важности журнала для каждого модуля. Таким образом, если вы устраняете проблему только с одним конкретным модулем, вы можете увеличить его объем в журнале, при этом не получая лишней информации о других модулях, которые вас не интересуют. Это особенно полезно для таких модулей, как mod_proxy или mod_rewrite где вы хотите узнать подробности о том, что он пытается сделать.
Журнал доступа к серверу записывает все запросы, обработанные сервером.
Эта директива заставляет пользовательское сообщение регистрироваться в журнале ошибок. Сообщение может использовать переменные и функции из синтаксиса ap_expr. Ссылки на заголовки HTTP не приводят к добавлению имён заголовков в заголовок Vary. Сообщения регистрируются на уровне лога.
Регистрация ведётся до и после обработки запроса, поэтому журнал судебной экспертизы содержит две строки журнала для каждого запроса. Отличается повышенной строгостью.
Если ScriptLog не указан, журнал ошибок не создаётся. Если ScriptLog установлен, то любые ошибки CGI регистрируются в файле, указанном в качестве аргумента.
В Apache есть несколько модулей, которые отвечают за веб журналы:
Модуль mod_log_config обеспечивает гибкое журналирование клиентских запросов. Логи пишутся в настраиваемом формате и могут быть записаны непосредственно в файл или во внешнюю программу. Предоставляется запись логов под условием, то есть индивидуальные запросы могут быть включены или исключены из журнала на основе характеристики запроса. Этот модуль является ключевым для обеспечения работы Access Log (журнал доступа).
Этот модуль поддерживает следующие директивы:
Директивы TransferLog и CustomLog на каждом сервере могут использоваться несколько раз, чтобы каждый запрос регистрировался в нескольких файлах.
Журнал доступа к серверу записывает все запросы, обработанные сервером. Расположение и содержимое журнала доступа контролируются директивой CustomLog. Директива LogFormat может быть использована для упрощения выбора содержимого журналов. В этом разделе описывается, как настроить сервер для записи информации в журнал доступа.
Конечно, хранение информации в журнале доступа — это только начало управления журналом. Следующим шагом является анализ этой информации для получения полезной статистики. Анализ журналов в целом выходит не является частью работы самого веб-сервера, но будет рассмотрен в одной из последующих статей данного цикла.
Различные версии Apache httpd использовали другие модули и директивы для управления журналом доступа, включая mod_log_referer, mod_log_agent и директиву TransferLog. Директива CustomLog теперь включает в себя функциональность всех старых директив.
Формат журнала доступа легко настраивается. Формат указывается с использованием строки формата, которая очень похожа на строку формата printf(1) в стиле C. Некоторые примеры представлены далее. Полный список возможного содержимого строки формата смотрите в следующем разделе «Как настроить формат логов доступа Apache. Пользовательские форматы журналов».
То есть с практической точки зрения, Access Log (журнал доступа) это то же самое, что и mod_log_config, поскольку именно этот модуль обеспечивает функциональность Access Log. Дополнительно Access Log используют модули mod_logio и mod_setenvif для расширения функциональность. Например, модуль mod_logio позволяет записывать в журнал точный размер переданных и(или) полученных данных во время запроса пользователя и ответа ему.
Поскольку это одно и то же, то директивы у Access Log и mod_log_config одинаковые. Дальнейшая информация в этом разделе относится к Access Log и mod_log_config.
Аргументом формата для директив LogFormat и CustomLog является строка. На основе этой строки будет сформированы записи в файл журнала для каждого запроса. Данная строка может содержать буквальные символы, которые будут скопированные в файлы журнала такими, как они есть, и управляющие символы в стиле C "\n" и "\t" для записи символов new-line (новая строка) и tab (табуляция). Буквальные кавычки и обратные слэши следует экранировать с помощью обратной косой черты (\).
Различные характеристики запроса обозначаются строками, которые начинаются с символа «%». В файле журнала такие строки будут заменены следующими значениями:
Строка формата | Описание | |
---|---|---|
%% | Буквальный знак процента. | |
%a | Клиентский IP адрес запроса (смотрите также модуль mod_remoteip). | |
%{c}a | Лежащий в основе IP-адрес соединения (см. модуль mod_remoteip). | |
%A | Локальный IP-адрес. | |
%B | Размер ответа в байтах, исключая HTTP заголовки. | |
%b | Размер ответа в байтах, исключая HTTP заголовки. В формате CLF, то есть когда баты не отправлены, то будет '-', а не 0. | |
%{VARNAME}C | Содержимое куки VARNAME в запросе, отправленном серверу. Полностью поддерживается только куки версии 0. | |
%D | Время, затраченное на обработку запроса в микросекундах. Дополнительные подробности смотрите в описании %T. | |
%{VARNAME}e | Содержимое переменной окружения VARNAME. | |
%f | Имя файла. | |
%h | Имя удалённого хоста. Запишет IP адрес, если HostnameLookups установлена на Off, это является значением по умолчанию. Если регистрируется имя хоста только для нескольких хостов, возможно, у вас есть директивы контроля доступа, в которых они упоминаются по имени. См. документацию Require host. На этот формат влияют модификации имени удалённого хоста такими модулями, как mod_remoteip. | |
%{c}h | Как %h, но всегда сообщает об имени хоста лежащего в основе TCP-соединения, а не о каких-либо модификациях в имени удалённого хоста такими модулями, как mod_remoteip. | |
%H | Протокол запроса. | |
%{VARNAME}i | Содержимое VARNAME: строка(и) заголовка в запросе, отправленном на сервер. Изменения, сделанные другими модулями (например, mod_headers), влияют на это. Если вас интересует, какой заголовок запроса был до того, когда большинство модулей изменили бы его, используйте mod_setenvif, чтобы скопировать заголовок во внутреннюю переменную среды и запишите в журнал значение описанной выше %{VARNAME}e. Примеры таких переменных: %{Referer}i (реферер), %{User-agent}i (пользовательский агент, браузер). | |
%k | Количество запросов keepalive, обработанных для этого соединения. Интересно, если используется KeepAlive, например, «1» означает первый запрос keepalive после исходного, «2» - второй и т. д.; в противном случае это всегда 0 (указывает на начальный запрос). | |
%l | Имя удалённого журнала (от identd, если есть). Это вернёт тире, если не присутствует mod_ident и для IdentityCheck не установлено значение On. | |
%L | Идентификатор журнала запросов из журнала ошибок (или «-», если в журнал ошибок для этого запроса ничего не было занесено). Найдите соответствующую строку журнала ошибок, чтобы узнать, какой запрос вызвал какую ошибку. | |
%{c}L | Идентификатор журнала подключений из журнала ошибок (или «-», если в журнал ошибок для этого запроса ничего не записано). Найдите соответствующую строку журнала ошибок, чтобы узнать, какой запрос вызвал какую ошибку. | |
%m | Метод запроса. | |
%{VARNAME}n | Содержимое заметки VARNAME из другого модуля. | |
%{VARNAME}o | Содержимое VARNAME: строки заголовка в ответе. | |
%p | Канонический порт сервера, обслуживающего запрос. | |
%{формат}p | Канонический порт сервера, обслуживающего запрос, или фактический порт сервера, или фактический порт клиента. Допустимые форматы: canonical, local или remote. | |
%P | Идентификатор дочернего процесса, который обслуживал запрос. | |
%{формат}P | Идентификатор процесса или идентификатор дочернего потока, который обслуживал запрос. Допустимые форматы: pid, tid и hextid. hextid требует APR 1.2.0 или выше. | |
%q | Строка запроса (с префиксом ? если строка запроса существует, в противном случае — пустая строка). | |
%r | Первая строка запроса | |
%R | Обработчик, генерирующий ответ (если есть). | |
%s | Статус. Для запросов, которые были внутренне перенаправлены, это статус исходного запроса. Используйте %>s для окончательного статуса. | |
%t | Время получения запроса в формате [18/Sep/2011:19:18:28 -0400]. Последнее число указывает на смещение часового пояса от GMT | |
%{format}t |
Время в форме, заданной форматом, которое должно быть в расширенном формате strftime(3) (возможно, локализовано). Если формат начинается с begin: (по умолчанию) время берётся в начале обработки запроса. Если он начинается с end: это время записи в журнал, близкое к концу обработки запроса. В дополнение к форматам, поддерживаемым strftime(3), поддерживаются следующие маркеры формата:
Эти токены в одной строке формата нельзя объединять друг с другом или форматированием strftime(3). Вместо этого вы можете использовать несколько токенов %{format}t. Пример: %{%d/%b/%Y %T}t.%{msec_frac}t %{%z}t |
|
%T |
Время, затраченное на обслуживание запроса, в секундах. Измеренное время начинается, когда HTTP-сервер читает первую строку HTTP-запроса из операционной системы хоста, и заканчивается, когда последний байт ответа записывается HTTP-сервером в операционную систему хоста. Измеренное время не включает в себя ничего из следующего:
|
|
%{UNIT}T | Время, затраченное на обслуживание запроса, в единицах времени, указанных UNIT. Допустимые единицы измерения — ms для миллисекунд, us для микросекунд и s для секунд. Использование s даёт тот же результат, что и %T без какого-либо формата; использование us даёт тот же результат, что и %D. Объединение %T с юнитом доступно в 2.4.13 и более поздних версиях. | |
%u | Удаленный пользователь, если запрос был аутентифицирован. Может быть поддельным, если статус возврата (%s) равен 401 (не авторизован). | |
%U | Запрошенный путь URL, не включая строку запроса. | |
%v | Каноническое ServerName сервера, обслуживающего запрос. | |
%V | Имя сервера в соответствии с настройкой UseCanonicalName. | |
%X |
Состояние соединения, когда ответ завершён:
|
|
%I | Получено байтов, включая запрос и заголовки. Не может быть ноль. Вы должны включить mod_logio, чтобы использовать это. | |
%O | Отправлено байтов, включая заголовки. Может быть в редких случаях нулём, например, когда запрос прерывается перед отправкой ответа. Вы должны включить mod_logio, чтобы использовать это. | |
%S | Переданные (полученные и отправленные) байты, включая запрос и заголовки, не могут быть равны нулю. Это комбинация %I и %O. Вы должны включить mod_logio, чтобы использовать это. | |
%{VARNAME}^ti | Содержимое VARNAME: трейлерные строки в запросе, отправленном на сервер. | |
%{VARNAME}^to | Содержимое VARNAME: трейлерные строки в запросе, отправленном с сервера. |
Модификаторы
Отдельные элементы могут быть ограничены для печати только для ответов с определёнными кодами состояния HTTP, помещая разделённый запятыми список кодов состояния сразу после "%". Списку кодов состояния может предшествовать "!" чтобы указать отрицание.
Строка формата | Значение |
---|---|
%400,501{User-agent}i | Регистрирует User-agent только при возникновении ошибок 400 и ошибок 501. Для других кодов состояния будет записана буквальная строка «-». |
%!200,304,302{Referer}i | Регистрирует Referer всех запросов, которые не возвращают один из трёх указанных кодов, в противном случае будет записано "-". |
Модификаторы «<» и «>» нужны чтобы выбирать, следует ли записывать исходный или окончательный запрос. Это можно использовать для запросов, которые были перенаправлены внутри. По умолчанию % директивы %s, %U, %T, %D и %r смотрят на исходный запрос, а все остальные смотрят на окончательный запрос. Так, например, %>s можно использовать для записи окончательного состояния запроса, а %<u можно использовать для записи исходного аутентифицированного пользователя по запросу, внутренне перенаправленному на неаутентифицированный ресурс.
Примечания к форматам
По соображениям безопасности, начиная с версии 2.0.46, непечатаемые и другие специальные символы в %r, %i и %o экранируются с помощью последовательностей \xhh, где hh обозначает шестнадцатеричное представление необработанного байта. Исключениями из этого правила являются " и \, которые экранируются путём добавления обратной косой черты и всех пробельных символов, которые записываются с использованием нотации в стиле C (\n, \t и т. Д.). В версиях, предшествующих 2.0.46, для этих строк экранирование не выполнялось, поэтому вы должны быть достаточно осторожны при работе с необработанными лог-файлами в этих версиях.
Поскольку в httpd 2.0, в отличие от 1.3, строки формата %b и %B представляют не количество байтов, отправленных клиенту, а просто размер в байтах ответа HTTP (который будет отличаться, например, если соединение прервано) или если используется SSL). Формат %O, предоставляемый mod_logio, регистрирует фактическое количество байтов, отправленных по сети.
Примечание: mod_cache реализован как быстрый обработчик, а не как стандартный обработчик. Следовательно, строка формата %R не будет возвращать никакой информации обработчика, когда задействовано кэширование содержимого.
Примечание. Символ «^» в начале трёхсимвольных форматов не имеет значения, но он должен быть первым символом любого вновь добавленного трёхсимвольного формата, чтобы избежать потенциальных конфликтов с форматами журналов, в которых используются буквальные строки, смежные со спецификатором формата, такие как "%Dus".
Примеры
Некоторые часто используемые строки формата журнала:
1
|
"%h %l %u %t \"%r\" %>s %b" |
1
|
"%v %h %l %u %t \"%r\" %>s %b" |
1
|
"%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\"" |
1
|
"%{Referer}i -> %U" |
1
|
"%{User-agent}i" |
Вы можете использовать директиву %{format}t несколько раз для построения формата времени, используя расширенные маркеры формата, такие как msec_frac:
1
|
"%{%d/%b/%Y %T}t.%{msec_frac}t %{%z}t" |
Описание: Сохраняет записи журнала в памяти перед записью на диск.
Синтаксис:
1
|
BufferedLogs On|Off |
Значение по умолчанию:
1
|
BufferedLogs Off |
Контекст: server config
Директива BufferedLogs заставляет mod_log_config хранить несколько записей журнала в памяти и записывать их вместе на диск, а не записывать их после каждого запроса. В некоторых системах это может привести к более эффективному доступу к диску и, следовательно, к более высокой производительности. Он может быть установлен только один раз для всего сервера; его нельзя настроить для каждого виртуального хоста.
Эту директиву следует использовать с осторожностью, поскольку сбой может привести к потере данных журнала.
Описание: устанавливает имя файла и формат файла журнала.
Синтаксис:
1
|
CustomLog file|pipe|provider format|nickname [env=[!]environment-variable| expr=expression] |
Контекст: server config, виртуальные хосты
Директива CustomLog используется для регистрации запросов к серверу. Указывается формат журнала, способ записи в журнал, здесь же можно указать условие на основе характеристиками запроса с использованием переменных среды при котором будет сделана запись в журнале.
Первый аргумент, который указывает местоположение, в которое будут записываться журналы, может принимать одно из следующих трёх типов значений:
file
Имя файла относительно ServerRoot.
pipe
Символ трубы "|", за которым следует путь к программе которая получит записи логов на её стандартном вводе. Для получения дополнительной информации смотрите ниже раздел Piped Logs (конвейерная обработка).
Безопасность: если используется программа, она будет запущена от имени пользователя, запустившего httpd. Это будет root, если сервер был запущен от root; убедитесь, что программа безопасна.
Примечание: при вводе пути к файлу на платформах, отличных от Unix, необходимо следить за тем, чтобы использовались только прямые косые черты, даже если платформа может разрешать использование обратных косых черт. Как правило, рекомендуется всегда использовать прямые косые черты в файлах конфигурации.
provider
Модули, реализующие поставщиков ErrorLog, также могут использоваться в качестве цели для сообщений CustomLog. Чтобы использовать провайдера ErrorLog в качестве цели, необходимо использовать синтаксис «provider:argument». Например, вы можете использовать mod_journald или mod_syslog в качестве провайдера:
1
2
3
4
5
|
# Журналирование CustomLog к journald CustomLog "journald" "%h %l %u %t \"%r\" %>s %b" # Журналирование CustomLog к syslog с объектом "user" CustomLog "syslog:user" "%h %l %u %t \"%r\" %>s %b" |
Второй аргумент указывает, что будет записано в файл журнала. Он может указывать либо псевдоним, определённый предыдущей директивой LogFormat, либо это может быть явная строка формата, как описано в разделе «Как настроить формат логов Apache. Пользовательские форматы журналов».
Например, следующие два набора директив имеют абсолютно одинаковый эффект:
1.
1
2
3
|
# CustomLog с указанием псевдонима формата LogFormat "%h %l %u %t \"%r\" %>s %b" common CustomLog "logs/access_log" common |
2.
1
2
|
# CustomLog с явно указанной строкой формата CustomLog "logs/access_log" "%h %l %u %t \"%r\" %>s %b" |
Третий аргумент является необязательным и определяет, регистрировать или нет конкретный запрос. Условием может быть наличие или отсутствие (в случае предложения 'env=!name') определённой переменной в среде сервера. Альтернативно, условие может быть выражено как произвольное логическое выражение. Если условие не выполнено, запрос не будет зарегистрирован. Ссылки на заголовки HTTP в выражении не приводят к добавлению имён заголовков в заголовок Vary.
Переменные среды могут быть установлены для каждого запроса с использованием модулей mod_setenvif и/или mod_rewrite (смотрите здесь и здесь). Например, если вы хотите записать запросы для всех изображений GIF на вашем сервере в отдельный файл журнала, но не в свой основной журнал, вы можете использовать:
1
2
3
|
SetEnvIf Request_URI \.gif$ gif-image CustomLog "gif-requests.log" common env=gif-image CustomLog "nongif-requests.log" common env=!gif-image |
Или, чтобы воспроизвести поведение старой директивы RefererIgnore, вы можете использовать следующее:
1
2
|
SetEnvIf Referer example\.com localreferer CustomLog "referer.log" referer env=!localreferer |
Описание: Устанавливает имя файла и формат файла журнала.
Синтаксис:
1
|
GlobalLog file|pipe|provider format|nickname [env=[!]environment-variable| expr=expression] |
Контекст: server config
Совместимость: Доступна в Apache HTTP Server 2.4.19 и более поздних.
Директива GlobalLog определяет журнал, общий для конфигурации основного сервера и всех настроенных виртуальных хостов.
Директива GlobalLog идентична директиве CustomLog, за исключением следующих отличий:
Описание: описывает формат для использования в файле журнала.
Синтаксис:
1
|
LogFormat формат|псевдоним [псевдоним] |
Значение по умолчанию:
1
|
LogFormat "%h %l %u %t \"%r\" %>s %b" |
Контекст: server config, виртуальные хосты.
Эта директива определяет формат файла журнала доступа.
Директива LogFormat может принимать одну из двух форм. В первой форме, где указан только один аргумент, эта директива устанавливает формат журнала, который будет использоваться журналами, указанными в последующих директивах TransferLog. Один аргумент может указывать явный формат, как обсуждалось в разделе о пользовательских форматах журналов выше. Кроме того, он может использовать псевдоним для ссылки на формат журнала, определённый в предыдущей директиве LogFormat, как описано ниже.
Вторая форма директивы LogFormat связывает явный формат с псевдонимом. Этот псевдоним можно затем использовать в последующих директивах LogFormat или CustomLog, а не повторять всю строку формата. Директива LogFormat, определяющая псевдоним, больше ничего не делает, то есть определяет только псевдоним, фактически не применяет формат и не устанавливает его по умолчанию. Следовательно, это не повлияет на последующие директивы TransferLog. Кроме того, LogFormat не может использовать один псевдоним для определения другого псевдонима. Обратите внимание, что псевдоним не должен содержать знаки процента (%).
Пример:
1
|
LogFormat "%v %h %l %u %t \"%r\" %>s %b" vhost_common |
Описание: определяет размещение файла журнала.
Синтаксис:
1
|
TransferLog файл|труба |
Контекст: server config, виртуальные хосты
Эта директива имеет те же аргументы и эффект, что и директива CustomLog, за исключением того, что она не позволяет явно указывать формат журнала или регистрировать запросы на основе условий. Вместо этого формат журнала определяется самой последней указанной директивой LogFormat, которая не определяет псевдоним. Общий формат журнала используется, если не указан другой формат.
Пример:
1
2
|
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\"" TransferLog "logs/access_log" |
Типичная конфигурация для журнала доступа может выглядеть следующим образом.
1
2
|
LogFormat "%h %l %u %t \"%r\" %>s %b" common CustomLog "logs/access_log" common |
Она задаёт псевдоним common и связывает его с определённой строкой формата журнала. Строка формата состоит из директив со знаком процента, каждая из которых указывает серверу регистрировать определённый фрагмент информации. Буквальные символы также могут быть помещены в строку формата и будут скопированы непосредственно в вывод журнала. Символ кавычки (") должен быть экранирован путём размещения обратной косой черты перед ним, чтобы он не интерпретировался как конец строки формата. Строка формата также может содержать специальные управляющие символы "\n" для новой строки и "\t" для табуляции.
Директива CustomLog устанавливает новый файл журнала, используя определённый псевдоним. Имя файла для журнала доступа определяется относительно ServerRoot, если оно не начинается с косой черты.
Приведённая выше конфигурация будет записывать записи журнала в формате, известном как Common Log Format (CLF). Этот стандартный формат может создаваться многими различными веб-серверами и считываться многими программами анализа журналов. Записи файла журнала, созданные в CLF, будут выглядеть примерно так:
1
|
95.152.63.100 - frank [18/Aug/2019:08:58:34 +0300] "GET /ru/?act=myip HTTP/1.1" 200 25858 |
Каждая часть этой записи журнала описана ниже.
95.152.63.100 (%h)
Это IP-адрес клиента (удалённого хоста), который сделал запрос к серверу. Если для HostnameLookups установлено значение On, сервер попытается определить имя хоста и записать его вместо IP-адреса. Однако такая конфигурация не рекомендуется, поскольку она может значительно замедлить работу сервера. Вместо этого лучше всего использовать постпроцессор журнала, такой как logresolve, для определения имён хостов. Указанный здесь IP-адрес не обязательно является адресом машины, на которой сидит пользователь. Если между пользователем и сервером существует прокси-сервер, этот адрес будет адресом прокси, а не исходной машины.
- (%l)
«Дефис» в выходных данных указывает на то, что запрошенная часть информации недоступна. В этом случае информация, которая недоступна, является идентификационной информацией клиента RFC 1413, определённой с помощью identd на клиентском компьютере. Эта информация крайне ненадёжна и почти никогда не должна использоваться, кроме как в жёстко контролируемых внутренних сетях. Apache httpd даже не будет пытаться определить эту информацию, если для IdentityCheck не установлено значение On.
frank (%u)
Это идентификатор пользователя, запрашивающего документ, как он был определён HTTP-аутентификацией. Такое же значение обычно предоставляется сценариям CGI в переменной среды REMOTE_USER. Если код состояния для запроса равен 401, то этому значению не следует доверять, поскольку пользователь ещё не аутентифицирован. Если документ не защищён паролем, эта часть будет "-", как и предыдущая.
[18/Aug/2019:08:58:34 +0300] (%t)
Время получения запроса. Формат такой:
[день/месяц/год:час:минута:секунда зона]
день = 2*цифры
месяц = 3*буквы
год = 4*цифры
час = 2*цифры
минута = 2*цифры
секунда = 2*цифры
зона = (`+' | `-') 4*цифры
Можно отобразить время в другом формате, указав %{format}t в строке формата журнала, где формат такой же, как в strftime(3) из стандартной библиотеки C, или один из поддерживаемых специальных маркеров. Подробности смотрите выше в разделе «Как настроить формат логов Apache. Пользовательские форматы журналов».
"GET /ru/?act=myip HTTP/1.1" (\"%r\")
Строка запроса от клиента указанная в двойных кавычках. Строка запроса содержит много полезной информации. Во-первых, клиент использует метод GET. Во-вторых, клиент запросил ресурс /ru/?act=myip, и в-третьих, клиент использовал протокол HTTP/1.1. Также возможно зарегистрировать одну или несколько частей строки запроса независимо. Например, строка формата "%m %U%q %H" будет регистрировать метод, путь, строку запроса и протокол, что приведёт к точно такому же выводу, что и "%r".
200 (%>s)
Это код состояния, который сервер отправляет обратно клиенту. Эта информация очень ценна, поскольку она показывает, привёл ли запрос к успешному ответу (коды начинаются с 2), к перенаправлению (коды начинаются с 3), к ошибке, вызванной клиентом (коды начинаются с 4), или к ошибкам на сервере (коды начинаются с 5). Полный список возможных кодов состояния можно найти в спецификации HTTP (RFC2616 раздел 10).
25858 (%b)
Последняя часть указывает размер объекта, возвращаемого клиенту, не включая заголовки ответа. Если контент не был возвращён клиенту, это значение будет "-". Чтобы записывался «0» при отсутствии содержимого, используйте %B.
Другая широко используемая строка формата называется Combined Log Format. Может использоваться следующим образом.
1
2
|
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\"" combined CustomLog "log/access_log" combined |
Этот формат точно такой же, как Common Log Format, с добавлением ещё двух полей. Каждое из дополнительных полей использует директиву с процентом %{header}i, где header может быть любым заголовком HTTP-запроса. Журнал доступа в этом формате будет выглядеть так:
1
|
2a02:2168:a13:430b::1 - - [18/Aug/2019:09:38:53 +0300] "POST /ru/?act=locatepicture HTTP/1.1" 200 25627 "https://suip.biz/ru/?act=locatepicture" "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36" |
Обратите внимание, что в качестве IP адреса также может быть IPv6 как в примере выше.
Дополнительными полями являются:
"https://suip.biz/ru/?act=locatepicture" (\"%{Referer}i\")
Это заголовок HTTP запроса "Referer". В этой строке клиент сообщает сайту, с какого сайта и какой страницы он пришёл (это должна быть страница, на которой размещена ссылка на запрошенный адрес, либо страница, которая включает в себя запрошенный файл (например, изображение).
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36" (\"%{User-agent}i\")
Заголовок HTTP-запроса User-Agent. Это идентифицирующая информация, которую клиентский браузер сообщает о себе.
Журналы множественного доступа могут быть созданы просто путём указания нескольких директив CustomLog в файле конфигурации. Например, следующие директивы создадут три журнала доступа. Первый содержит основную информацию CLF, а второй и третий содержат информацию о реферере и браузере. Последние две строки CustomLog показывают, как имитировать эффекты директив ReferLog и AgentLog.
1
2
3
4
|
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 используется для включения или исключения запросов, в которых установлена переменная среды. Некоторые примеры:
1
2
3
4
5
6
|
# Пометить запросы из loop-back (петлевого) интерфейса SetEnvIf Remote_Addr "127\.0\.0\.1" dontlog # Пометить запросы на файл robots.txt SetEnvIf Request_URI "^/robots\.txt$" dontlog # Записать то, что осталось CustomLog "logs/access_log" common env=!dontlog |
В качестве другого примера рассмотрим запись запросов от англоязычных пользователей в один файл журнала, а не говорящих по-английски — в другой файл журнала.
1
2
3
|
SetEnvIf Accept-Language "en" english CustomLog "logs/english_log" common env=english CustomLog "logs/non_english_log" common env=!english |
В сценарии кеширования хотелось бы узнать об эффективности кеша. Очень простой способ выяснить это будет:
1
2
3
|
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:
1
2
|
LogFormat "%400,501{User-agent}i" browserlog LogFormat "%!200,304,302{Referer}i" refererlog |
В первом примере User-agent будет записан в журнал, если код состояния HTTP равен 400 или 501. В других случаях вместо него будет записана буквальная строка «-». Аналогично, во втором примере Referer будет записан в журнал, если код состояния HTTP не равен 200, 204 или 302. (обратите внимание на «!» перед кодами состояния).
Хотя мы только что показали, что условное ведение журнала является очень мощным и гибким, это не единственный способ управления содержимым журналов. Файлы журнала более полезны, когда они содержат полную запись активности сервера. В большинстве случае проще просто обработать полные файлы журналов, чтобы извлечь из них только нужные вам данные или убрать определённую информацию.
Даже на умеренно загруженном сервере количество информации, хранящейся в файлах журнала, очень велико. Файл журнала доступа обычно увеличивается на 1 МБ или более на 10 000 запросов. Следовательно, необходимо периодически ротировать файлы журналов, перемещая или удаляя существующие журналы. Это невозможно сделать во время работы сервера, поскольку Apache httpd продолжит запись в старый файл журнала, пока он удерживает этот файл открытым. Вместо этого сервер должен быть перезапущен после перемещения или удаления файлов журнала, чтобы открыть новые файлы журнала.
Используя graceful перезапуск, сервер может получить команду открывать новые файлы журнала, не теряя ни существующих, ни ожидающих соединений от клиентов. Однако для этого сервер должен продолжать запись в старые файлы журнала, пока он завершает обслуживание старых запросов. Поэтому необходимо подождать некоторое время после перезапуска, прежде чем выполнять какую-либо обработку файлов журнала. Типичный сценарий, который просто ротирует журналы и сжимает старые журналы для экономии места:
1
2
3
4
5
|
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 способен записывать файлы журналов доступа и ошибок по трубе (через канал) к другому процессу, а не напрямую в файл. Эта возможность значительно повышает гибкость ведения журнала без добавления кода на главный сервер. Чтобы записывать журналы в трубу, просто замените имя файла на символ трубы «|», за которым следует имя исполняемого файла, который должен принимать записи журнала на своём стандартном входе. Сервер при старте сервера запустит процесс piped-log и перезапустит его, если он выйдет из строя во время работы сервера (эта последняя функция позволяет назвать эту технику "надёжная передача журнала по трубе".)
Процессы конвейерного журнала порождаются родительским процессом Apache httpd и наследуют идентификатор пользователя этого процесса. Это означает, что программы логов по конвейеру обычно запускаются с правами root. Поэтому очень важно, чтобы программы были простыми и безопасными.
Одно из важных применений конвейерных журналов — разрешить ротацию журналов без перезагрузки сервера. HTTP-сервер Apache включает в себя простую программу rotatelogs для этой цели. Например, чтобы ротировать журналы каждые 24 часа, вы можете использовать:
1
|
CustomLog "|/usr/local/apache/bin/rotatelogs /var/log/access_log 86400" common |
Обратите внимание, что кавычки используются для включения всей команды, которая будет вызываться для трубы. Хотя эти примеры относятся к журналу доступа, тот же метод может быть использован для журнала ошибок.
Как и в случае с ведением логов с условиями, журналы по конвейеру являются очень мощным инструментом, но их не следует использовать там, где доступно более простое решение, такое как автономная постобработка.
По умолчанию процесс передаваемого по трубе журнала порождается без вызова оболочки. Используйте "|$" вместо "|" для запуска с оболочкой (обычно с /bin/sh -c):
1
2
|
# Вызов "rotatelogs" используя оболочку CustomLog "|$/usr/local/apache/bin/rotatelogs /var/log/access_log 86400" common |
Это было поведение по умолчанию для Apache 2.2. В зависимости от специфики оболочки это может привести к дополнительному процессу оболочки на время жизни программы канала журнала и проблемам с обработкой сигналов при перезапуске. По причинам совместимости с Apache 2.2 обозначение «||» также поддерживается и эквивалентно использованию «|».
Примечание для Windows: обратите внимание, что в Windows вы можете столкнуться с проблемами при запуске многих процессов журналирования, особенно когда HTTPD работает как служба. Это вызвано нехваткой heap space рабочего стола. Пространство heap space рабочего стола, предоставляемое каждой службе, задаётся третьим аргументом параметра SharedSection в значении реестра HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\SessionManager\SubSystems\Windows. Измените это значение с осторожностью; применяются обычные предостережения для изменения реестра Windows, но вы можете также исчерпать пул heap space рабочего стола, если число будет установлено слишком высоко.
При запуске сервера со многими виртуальными хостами существует несколько вариантов работы с файлами журналов. Во-первых, возможно использовать журналы точно так же, как на сервере с одним хостом. Просто разместив директивы ведения журналов за пределами разделов <VirtualHost> в контексте основного сервера, можно зарегистрировать все запросы в одном журнале доступа и журнале ошибок. Этот метод не позволяет легко собирать статистику по отдельным виртуальным хостам.
Если директивы CustomLog или ErrorLog помещаются в раздел <VirtualHost>, все запросы или ошибки для этого виртуального хоста будут записываться только в указанный файл. Любой виртуальный хост, у которого нет директив журналирования, все равно будет отправлять свои запросы в журналы главного сервера. Этот метод очень полезен для небольшого количества виртуальных хостов, но если количество хостов очень велико, им может быть сложно управлять. Кроме того, это может часто создавать проблемы с недостаточным количеством файловых дескрипторов.
Для журнала доступа есть очень хороший компромисс. Добавив информацию о виртуальном хосте в строку формата журнала, можно зарегистрировать все хосты в одном журнале, а затем разделить журнал на отдельные файлы. Например, рассмотрим следующие директивы.
1
2
|
LogFormat "%v %l %u %t \"%r\" %>s %b" comonvhost CustomLog "logs/access_log" comonvhost |
%v используется для записи в журнал имени виртуального хоста, который обслуживает запрос. Затем такую программу, как split-logfile, можно использовать для последующей обработки журнала доступа, чтобы разделить его на один файл для каждого виртуального хоста.
Любой, кто может писать в каталог, где Apache httpd пишет файл журнала, почти наверняка может получить доступ к uid, с которого запущен сервер, который обычно является пользователем root. НЕ предоставляйте людям доступ для записи в каталог, в котором хранятся журналы, не зная о последствиях.
Кроме того, файлы журналов могут содержать информацию, предоставленную непосредственно клиентом, без экранирования. Поэтому злонамеренные клиенты могут вставлять управляющие символы в файлы журналов, поэтому необходимо соблюдать осторожность при работе с необработанными журналами.
Разрешения на каталоги ServerRoot
В обычной работе Apache запускается пользователем root и переключается на пользователя, определённого в директиве User, для обслуживания обращений. Как и в случае с любой командой, выполняемой пользователем root, вы должны позаботиться о том, чтобы она была защищена от изменения пользователями без полномочий root. Не только сами файлы должны быть доступны для записи только root, но и каталоги, и родители всех каталогов. Например, если вы решите поместить ServerRoot в /usr/local/apache, то рекомендуется создать этот каталог как root с помощью таких команд:
1
2
3
4
5
6
|
mkdir /usr/local/apache cd /usr/local/apache mkdir bin conf logs chown 0 . bin conf logs chgrp 0 . bin conf logs chmod 755 . bin conf logs |
Предполагается, что /, /usr и /usr/local могут быть изменены только пользователем root. При установке исполняемого файла httpd вы должны убедиться, что он защищён аналогичным образом:
1
2
3
4
|
cp httpd /usr/local/apache/bin chown 0 /usr/local/apache/bin/httpd chgrp 0 /usr/local/apache/bin/httpd chmod 511 /usr/local/apache/bin/httpd |
Вы можете создать подкаталог htdocs, который может изменяться другими пользователями — поскольку root никогда не выполняет никаких файлов оттуда и не должен создавать файлы там.
Если вы позволяете пользователям без полномочий root изменять любые файлы, которые root выполняет или выполняет запись, то вы открываете свою систему для компрометации root. Например, кто-то может заменить двоичный файл httpd, чтобы при следующем запуске он выполнял произвольный код. Если каталог журналов доступен для записи (пользователем без полномочий root), кто-то может заменить файл журнала символической ссылкой на какой-либо другой системный файл, а затем root может перезаписать этот файл произвольными данными. Если сами файлы журнала доступны для записи (пользователем без полномочий root), то кто-то может перезаписать сам журнал поддельными данными.