Получение максимальной отдачи от файлов журнала PHP: практическое руководство

Опубликовано: 2022-03-11

С полным правом можно сказать, что логи — один из самых недооцененных и малоиспользуемых инструментов в распоряжении внештатного php-разработчика. Несмотря на обилие информации, которую они могут предложить, журналы нередко оказываются последним местом, куда разработчик обращается при попытке решить проблему.

По правде говоря, файлы журналов PHP во многих случаях должны быть первым местом для поиска подсказок при возникновении проблем. Часто содержащаяся в них информация может значительно сократить количество времени, затрачиваемого на выдергивание волос в попытках отследить жуткого жука.

Но, возможно, еще более важно то, что, проявив немного творчества и предусмотрительности, ваши файлы журналов можно использовать в качестве ценного источника информации об использовании и аналитики. Творческое использование файлов журналов может помочь ответить на такие вопросы, как: Какие браузеры чаще всего используются для посещения моего сайта? Какое среднее время ответа от моего сервера? Каков был процент запросов к корню сайта? Как изменилось использование с тех пор, как мы развернули последние обновления? И многое, многое другое.

Файлы журнала PHP

В этой статье содержится ряд советов о том, как настроить файлы журналов, а также как обрабатывать содержащуюся в них информацию, чтобы максимально использовать преимущества, которые они предоставляют.

Хотя эта статья с технической точки зрения фокусируется на ведении журналов для PHP-разработчиков, большая часть информации, представленной здесь, не зависит от технологий и применима также к другим языкам и технологическим стекам.

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

Наш пример файла журнала PHP

В качестве примера проекта для обсуждения в этой статье мы возьмем Symfony Standard в качестве рабочего проекта и настроим его на Debian 7 Wheezy с помощью rsyslogd , nginx и PHP-FPM .

 composer create-project symfony/framework-standard-edition my "2.6.*"

Это быстро дает нам рабочий тестовый проект с приятным пользовательским интерфейсом.

Советы по настройке файлов журнала

Вот несколько советов о том, как настроить файлы журналов, чтобы максимизировать их ценность.

Конфигурация журнала ошибок

Журналы ошибок представляют собой самую простую форму ведения журналов; т. е. сбор дополнительной информации и подробностей при возникновении проблем. Итак, в идеальном мире вы хотели бы, чтобы не было ошибок и чтобы ваши журналы ошибок были пустыми. Но когда проблемы действительно возникают (а они всегда случаются), журналы ошибок должны быть одной из первых остановок, которые вы делаете на пути отладки.

Журналы ошибок обычно довольно легко настроить.

Во-первых, все сообщения об ошибках и сбоях могут быть зарегистрированы в журнале ошибок точно в том же формате, в котором они иначе были бы представлены пользователю. С некоторой простой конфигурацией конечному пользователю никогда не придется видеть эти уродливые следы ошибок на вашем сайте, в то время как devops по-прежнему сможет контролировать систему и просматривать эти сообщения об ошибках во всех их кровавых деталях. Вот как настроить такое ведение журнала в PHP:

 log_errors = On error_reporting = E_ALL error_log = /path/to/my/error/log

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

 display_errors = Off display_startup_errors = Off

Системный журнал ( syslog ) Конфигурация

В мире с открытым исходным кодом существует множество общесовместимых реализаций демона syslog , в том числе:

  • syslogd и sysklogd — чаще всего встречаются в системах семейства BSD, CentOS, Mac OS X и других.
  • syslog-ng — по умолчанию для современных сборок Gentoo и SuSE.
  • rsyslogd — широко используется в семействах операционных систем Debian и Fedora.

(Примечание: в этой статье мы будем использовать rsyslogd для наших примеров.)

Базовая конфигурация системного журнала, как правило, достаточна для записи ваших сообщений журнала в общесистемный файл журнала (обычно это /var/log/syslog ; также может быть /var/log/messages или /var/log/system.log в зависимости от дистрибутива). вы используете).

Системный журнал предоставляет несколько средств ведения журнала, восемь из которых (от LOG_LOCAL0 до LOG_LOCAL7 ) зарезервированы для пользовательских проектов. Вот, например, как вы можете настроить LOG_LOCAL0 для записи в 4 отдельных файла журнала в зависимости от уровня ведения журнала (т. е. ошибка, предупреждение, информация, отладка):

 # /etc/rsyslog.d/my.conf local0.err /var/log/my/err.log local0.warning /var/log/my/warning.log local0.info -/var/log/my/info.log local0.debug -/var/log/my/debug.log

Теперь всякий раз, когда вы записываете сообщение журнала в средство LOG_LOCAL0 , сообщения об ошибках будут отправляться в /var/log/my/err.log , предупреждающие сообщения будут отправляться в /var/log/my/warning.log и так далее. Обратите внимание, однако, что демон syslog фильтрует сообщения для каждого файла на основе правила «этот уровень и выше». Таким образом, в приведенном выше примере все сообщения об ошибках будут отображаться во всех четырех сконфигурированных файлах, предупреждающие сообщения будут отображаться во всех файлах, кроме журнала ошибок, информационные сообщения будут отображаться в информационных журналах и журналах отладки, а сообщения отладки будут отправляться только в debug.log .

Еще одно важное замечание; Знаки - перед файлами уровня информации и отладки в приведенном выше примере файла конфигурации указывают на то, что запись в эти файлы должна выполняться асинхронно (поскольку эти операции не блокируются). Обычно это нормально (и даже рекомендуется в большинстве ситуаций) для журналов информации и отладки, но лучше всего, чтобы запись в журнал ошибок (и, скорее всего, также в журнал предупреждений) была синхронной.

Чтобы отключить менее важный уровень ведения журнала (например, на рабочем сервере), вы можете просто перенаправить соответствующие сообщения в /dev/null (т. е. в никуда):

 local0.debug /dev/null # -/var/log/my/debug.log

Одна конкретная настройка, которая полезна, особенно для поддержки парсинга файла журнала PHP, который мы обсудим позже в этой статье, заключается в использовании табуляции в качестве символа-разделителя в сообщениях журнала. Это легко сделать, добавив следующий файл в /etc/rsyslog.d :

 # /etc/rsyslog.d/fixtab.conf $EscapeControlCharactersOnReceive off

И, наконец, не забудьте перезапустить демон syslog после внесения любых изменений в конфигурацию, чтобы они вступили в силу:

 service rsyslog restart

Конфигурация журнала сервера

В отличие от журналов приложений и журналов ошибок, в которые вы можете записывать, журналы сервера записываются исключительно соответствующими серверными демонами (например, веб-сервером, сервером базы данных и т. д.) при каждом запросе. Единственный «контроль», который у вас есть над этими журналами, заключается в том, что сервер позволяет вам настраивать его функции ведения журналов. Хотя в этих файлах может быть много всего, что нужно просеять, зачастую они являются единственным способом получить четкое представление о том, что происходит «под капотом» на вашем сервере.

Давайте развернем наш пример приложения Symfony Standard в среде nginx с серверной частью хранилища MySQL. Вот конфигурация хоста nginx, которую мы будем использовать:

 server { server_name my.log-sandbox; root /var/www/my/web; location / { # try to serve file directly, fallback to app.php try_files $uri /app.php$is_args$args; } # DEV # This rule should only be placed on your development environment # In production, don't include this and don't deploy app_dev.php or config.php location ~ ^/(app_dev|config)\.php(/|$) { fastcgi_pass unix:/var/run/php5-fpm.sock; fastcgi_split_path_info ^(.+\.php)(/.*)$; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param HTTPS off; } # PROD location ~ ^/app\.php(/|$) { fastcgi_pass unix:/var/run/php5-fpm.sock; fastcgi_split_path_info ^(.+\.php)(/.*)$; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param HTTPS off; # Prevents URIs that include the front controller. This will 404: # http://domain.tld/app.php/some-path # Remove the internal directive to allow URIs like this internal; } error_log /var/log/nginx/my_error.log; access_log /var/log/nginx/my_access.log; }

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

Примечание. Это намеренно упрощенный файл конфигурации nginx, который предоставляется только в качестве примера. Он почти не уделяет внимания безопасности и производительности и не должен использоваться как есть в какой-либо «реальной» среде.

Это то, что мы получаем в /var/log/nginx/my_access.log после ввода http://my.log-sandbox/app_dev.php/ в браузере и нажатия Enter .

 192.168.56.1 - - [26/Apr/2015:16:13:28 +0300] "GET /app_dev.php/ HTTP/1.1" 200 6715 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90 Safari/537.36" 192.168.56.1 - - [26/Apr/2015:16:13:28 +0300] "GET /bundles/framework/css/body.css HTTP/1.1" 200 6657 "http://my.log-sandbox/app_dev.php/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90 Safari/537.36" 192.168.56.1 - - [26/Apr/2015:16:13:28 +0300] "GET /bundles/framework/css/structure.css HTTP/1.1" 200 1191 "http://my.log-sandbox/app_dev.php/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90 Safari/537.36" 192.168.56.1 - - [26/Apr/2015:16:13:28 +0300] "GET /bundles/acmedemo/css/demo.css HTTP/1.1" 200 2204 "http://my.log-sandbox/app_dev.php/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90 Safari/537.36" 192.168.56.1 - - [26/Apr/2015:16:13:28 +0300] "GET /bundles/acmedemo/images/welcome-quick-tour.gif HTTP/1.1" 200 4770 "http://my.log-sandbox/app_dev.php/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90 Safari/537.36" 192.168.56.1 - - [26/Apr/2015:16:13:28 +0300] "GET /bundles/acmedemo/images/welcome-demo.gif HTTP/1.1" 200 4053 "http://my.log-sandbox/app_dev.php/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90 Safari/537.36" 192.168.56.1 - - [26/Apr/2015:16:13:28 +0300] "GET /bundles/acmedemo/images/welcome-configure.gif HTTP/1.1" 200 3530 "http://my.log-sandbox/app_dev.php/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90 Safari/537.36" 192.168.56.1 - - [26/Apr/2015:16:13:28 +0300] "GET /favicon.ico HTTP/1.1" 200 6518 "http://my.log-sandbox/app_dev.php/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90 Safari/537.36" 192.168.56.1 - - [26/Apr/2015:16:13:30 +0300] "GET /app_dev.php/_wdt/e50d73 HTTP/1.1" 200 13265 "http://my.log-sandbox/app_dev.php/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90 Safari/537.36"

Это показывает, что для обслуживания одной страницы браузер фактически выполняет 9 вызовов HTTP. 7 из них, однако, являются запросами к статическому контенту, которые являются простыми и легкими. Однако они по-прежнему занимают сетевые ресурсы, и именно это можно оптимизировать с помощью различных спрайтов и методов минификации.

Хотя эти оптимизации будут обсуждаться в другой статье, здесь важно то, что мы можем регистрировать запросы к статическому содержимому отдельно, используя для них другую директиву location :

 location ~ \.(jpg|jpeg|gif|png|ico|css|zip|tgz|gz|rar|bz2|pdf|txt|tar|wav|bmp|rtf|js)$ { access_log /var/log/nginx/my_access-static.log; }

Помните, что nginx location выполняет простое сопоставление регулярных выражений, поэтому вы можете включить столько расширений статического содержимого, сколько ожидаете разместить на своем сайте.

Анализ таких журналов ничем не отличается от анализа журналов приложений.

Другие журналы, о которых стоит упомянуть

Два других журнала PHP, о которых стоит упомянуть, — это журнал отладки и журнал хранения данных.

Журнал отладки

Еще одна удобная вещь в журналах nginx — журнал отладки. Мы можем включить его, заменив строку error_log в конфиге на следующую (требуется установленный модуль отладки nginx):

 error_log /var/log/nginx/my_error.log debug;

Тот же параметр применяется для Apache или любого другого веб-сервера, который вы используете.

Кстати, журналы отладки не связаны с журналами ошибок, хотя они настраиваются в директиве error_log .

Хотя журнал отладки действительно может быть подробным (например, один запрос nginx генерирует 127 КБ данных журнала!), он все же может быть очень полезным. Просмотр файла журнала может быть громоздким и утомительным, но часто он может быстро предоставить подсказки и информацию, которые значительно ускорят процесс отладки.

В частности, журнал отладки может действительно помочь при отладке конфигураций nginx, особенно наиболее сложных частей, таких как сопоставление location и цепочки rewrite .

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

Журналы хранения данных

Другой тип журнала сервера (полезный для отладки) — это журналы хранения данных. В MySQL вы можете включить их, добавив следующие строки:

 [mysqld] general_log = 1 general_log_file = /var/log/mysql/query.log

Эти журналы просто содержат список запросов, выполняемых системой при обслуживании запросов к базе данных в хронологическом порядке, что может быть полезно для различных задач отладки и отслеживания. Однако они не должны оставаться включенными в производственных системах, так как они будут создавать дополнительную ненужную нагрузку ввода-вывода, которая влияет на производительность.

Запись в ваши файлы журнала

Сам PHP предоставляет функции для открытия, записи и закрытия файлов журналов ( openlog() , syslog() и closelog() соответственно).

Существует также множество библиотек ведения журналов для разработчиков PHP, таких как Monolog (популярна среди пользователей Symfony и Laravel), а также различные реализации для конкретных фреймворков, такие как возможности ведения журналов, встроенные в CakePHP. Как правило, такие библиотеки, как Monolog, не только оборачивают вызовы syslog() , но и позволяют использовать другие функциональные возможности и инструменты серверной части.

Вот простой пример записи в лог:

 <?php openlog(uniqid(), LOG_ODELAY, LOG_LOCAL0); syslog(LOG_INFO, 'It works!');

Наш призыв к openlog :

  • настраивает PHP для добавления уникального идентификатора к каждому сообщению системного журнала в течение времени жизни скрипта
  • устанавливает задержку открытия соединения syslog до тех пор, пока не произойдет первый вызов syslog()
  • устанавливает LOG_LOCAL0 в качестве средства ведения журнала по умолчанию

Вот как будет выглядеть содержимое файла журнала после запуска приведенного выше кода:

 # cat /var/log/my/info.log Mar 2 00:23:29 log-sandbox 54f39161a2e55: It works!

Максимизация ценности ваших лог-файлов PHP

Теперь, когда у нас все хорошо с теорией и основами, давайте посмотрим, сколько мы можем получить от журналов, внося как можно меньше изменений в наш пример проекта Symfony Standard.

Во-первых, давайте создадим скрипты src/log-begin.php (для правильного открытия и настройки наших журналов) и src/log-end.php (для регистрации информации об успешном завершении). Обратите внимание, что для простоты мы просто будем записывать все сообщения в информационный журнал.

 # src/log-begin.php <?php define('START_TIME', microtime(true)); openlog(uniqid(), LOG_ODELAY, LOG_LOCAL0); syslog(LOG_INFO, 'BEGIN'); syslog(LOG_INFO, "URI\t{$_SERVER['REQUEST_URI']}"); $browserHash = substr(md5($_SERVER['HTTP_USER_AGENT']), 0, 7); syslog(LOG_INFO, "CLIENT\t{$_SERVER['REMOTE_ADDR']}\t{$browserHash}"); <br /> # src/log-end.php <?php syslog(LOG_INFO, "DISPATCH TIME\t" . round(microtime(true) - START_TIME, 2)); syslog(LOG_INFO, 'END');

И давайте потребуем эти скрипты в app.php :

 <?php require_once(dirname(__DIR__) . '/src/log-begin.php'); syslog(LOG_INFO, "MODE\tPROD"); # original app.php contents require_once(dirname(__DIR__) . '/src/log-end.php');

Для среды разработки мы также хотим потребовать эти скрипты в app_dev.php . Код для этого будет таким же, как и выше, за исключением того, что мы установим MODE в DEV , а не в PROD .

Мы также хотим отслеживать, какие контроллеры вызываются, поэтому добавим еще одну строку в Acme\DemoBundle\EventListener\ControllerListener прямо в начале метода ControllerListener::onKernelController() :

 syslog(LOG_INFO, "CONTROLLER\t" . get_class($event->getController()[0]));

Обратите внимание, что эти изменения составляют всего лишь 15 дополнительных строк кода, но в совокупности могут дать массу информации.

Анализ данных в ваших лог-файлах

Для начала давайте посмотрим, сколько HTTP-запросов требуется для обслуживания каждой загрузки страницы.

Вот информация в журналах для одного запроса в зависимости от того, как мы настроили ведение журнала:

 Mar 3 12:04:20 log-sandbox 54f58724b1ccc: BEGIN Mar 3 12:04:20 log-sandbox 54f58724b1ccc: URI /app_dev.php/ Mar 3 12:04:20 log-sandbox 54f58724b1ccc: CLIENT 192.168.56.1 1b101cd Mar 3 12:04:20 log-sandbox 54f58724b1ccc: MODE DEV Mar 3 12:04:23 log-sandbox 54f58724b1ccc: CONTROLLER Acme\DemoBundle\Controller\WelcomeController Mar 3 12:04:25 log-sandbox 54f58724b1ccc: DISPATCH TIME 4.51 Mar 3 12:04:25 log-sandbox 54f58724b1ccc: END Mar 3 12:04:25 log-sandbox 54f5872967dea: BEGIN Mar 3 12:04:25 log-sandbox 54f5872967dea: URI /app_dev.php/_wdt/59b8b6 Mar 3 12:04:25 log-sandbox 54f5872967dea: CLIENT 192.168.56.1 1b101cd Mar 3 12:04:25 log-sandbox 54f5872967dea: MODE DEV Mar 3 12:04:28 log-sandbox 54f5872967dea: CONTROLLER Symfony\Bundle\WebProfilerBundle\Controller\ProfilerController Mar 3 12:04:29 log-sandbox 54f5872967dea: DISPATCH TIME 4.17 Mar 3 12:04:29 log-sandbox 54f5872967dea: END

Итак, теперь мы знаем, что каждая загрузка страницы фактически обслуживается двумя HTTP-запросами.

Собственно, здесь стоит упомянуть два момента. Во-первых, два запроса на загрузку страницы предназначены для использования Symfony в режиме разработки (что я и делал на протяжении всей этой статьи). Вы можете идентифицировать вызовы режима разработки, выполнив поиск фрагментов URL /app-dev.php/ . Во-вторых, предположим, что каждая загрузка страницы обслуживается двумя последующими запросами к приложению Symfony. Как мы видели ранее в журналах доступа nginx, на самом деле существует больше вызовов HTTP, некоторые из которых предназначены для статического содержимого.

Хорошо, теперь давайте немного побродим по демонстрационному сайту (чтобы создать данные в лог-файлах) и посмотрим, что еще мы можем узнать из этих логов.

Сколько всего запросов было обслужено с начала файла журнала?

 # grep -c BEGIN info.log 10

Был ли какой-либо из них неудачным (скрипт закрылся, не дойдя до конца)?

 # grep -c END info.log 10

Мы видим, что количество записей BEGIN и END совпадает, поэтому это говорит нам, что все вызовы были успешными. (Если бы сценарий PHP не завершился успешно, он не достиг бы выполнения сценария src/log-end.php .)

Каков был процент запросов к корню сайта?

 # `grep -cE "\s/app_dev.php/$" info.log` 2

Это говорит нам о том, что корневая страница сайта была загружена 2 раза. Поскольку ранее мы узнали, что (а) на загрузку страницы приходится 2 запроса к приложению и (б) всего было 10 HTTP-запросов, процент запросов к корню сайта составил 40% (т. е. 2x2/10).

Какой класс контроллера отвечает за обслуживание запросов к корню сайта?

 # grep -E "\s/$|\s/app_dev.php/$" info.log | head -n1 Mar 3 12:04:20 log-sandbox 54f58724b1ccc: URI /app_dev.php/ # grep 54f58724b1ccc info.log | grep CONTROLLER Mar 3 12:04:23 log-sandbox 54f58724b1ccc: CONTROLLER Acme\DemoBundle\Controller\WelcomeController

Здесь мы использовали уникальный идентификатор запроса для проверки всех сообщений журнала, связанных с этим единственным запросом. Таким образом, мы смогли определить, что класс контроллера, отвечающий за обслуживание запросов к корню сайта, — это Acme\DemoBundle\Controller\WelcomeController .

Какие клиенты с IP-адресами подсети 192.168.0.0/16 заходили на сайт?

 # grep CLIENT info.log | cut -d":" -f4 | cut -f2 | sort | uniq 192.168.56.1

Как и ожидалось в этом простом тестовом примере, только мой хост-компьютер получил доступ к сайту. Это, конечно, очень упрощенный пример, но возможности, которые он демонстрирует (возможность анализировать источники трафика на ваш сайт), очевидно, весьма мощны и важны.

Какая часть трафика на мой сайт поступает из FireFox?

Имея 1b101cd в качестве хеша моего пользовательского агента Firefox, я могу ответить на этот вопрос следующим образом:

 # grep -c 1b101cd info.log 8 # grep -c CLIENT info.log 10

Ответ: 80% (т.е. 8/10)

Каков процент запросов, ответ на которые был медленным?

Для целей этого примера мы определим «медленный» как ответ, требующий более 5 секунд. Соответственно:

 # grep "DISPATCH TIME" info.log | grep -cE "\s[0-9]{2,}\.|\s[5-9]\." 2

Ответ: 20% (т.е. 2/10)

Кто-нибудь когда-либо предоставлял параметры GET?

 # grep URI info.log | grep \?

Нет, стандарт Symfony использует только URL-слаги, так что это также говорит нам о том, что никто не пытался взломать сайт.

Это всего лишь несколько относительно элементарных примеров того, как файлы журналов можно творчески использовать для получения ценной информации об использовании и даже базовой аналитики.

Другие вещи, о которых следует помнить

Обеспечение безопасности

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

Борьба с раздуванием файла журнала

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

Самый простой — это чередование журналов . Ротация журналов означает:

  • Периодическая замена лога новым пустым файлом для дальнейшей записи
  • Сохранение старого файла для истории
  • Удаление файлов, которые достаточно «устарели», чтобы освободить место на диске
  • Убедитесь, что приложение может записывать в журналы uninterrupted, когда происходят эти изменения файлов.

Наиболее распространенным решением для этого является logrotate , который предустановлен в большинстве дистрибутивов * nix. Давайте посмотрим на простой файл конфигурации для ротации наших журналов:

 /var/log/my/debug.log /var/log/my/info.log /var/log/my/warning.log /var/log/my/error.log { rotate 7 daily missingok notifempty delaycompress compress sharedscripts postrotate invoke-rc.d rsyslog rotate > /dev/null endscript }

Другой, более продвинутый подход состоит в том, чтобы заставить rsyslogd самостоятельно записывать сообщения в файлы, динамически создаваемые на основе текущей даты и времени. Это по-прежнему потребует специального решения для удаления старых файлов, но позволит devops точно управлять временными рамками для каждого файла журнала. Для нашего примера:

 $template DynaLocal0Err, "/var/log/my/error-%$NOW%-%$HOUR%.log" $template DynaLocal0Info, "/var/log/my/info-%$NOW%-%$HOUR%.log" $template DynaLocal0Warning, "/var/log/my/warning-%$NOW%-%$HOUR%.log" $template DynaLocal0Debug, "/var/log/my/debug-%$NOW%-%$HOUR%.log" local1.err -?DynaLocal0Err local1.info -?DynaLocal0Info local1.warning -?DynaLocal0Warning local1.debug -?DynaLocal0Debug

Таким образом, rsyslog будет каждый час создавать отдельный файл журнала, и не будет необходимости их ротации и перезапуска демона. Вот как можно удалить файлы журналов старше 5 дней, чтобы выполнить это решение:

 find /var/log/my/ -mtime +5 -print0 | xargs -0 rm

Удаленные журналы

По мере роста проекта синтаксический анализ информации из журналов становится все более и более ресурсоемким. Это не только означает дополнительную нагрузку на сервер; это также означает создание пиковой нагрузки на ЦП и диски в то время, когда вы анализируете журналы, что может ухудшить время отклика сервера для пользователей (или, в худшем случае, может даже привести к остановке сайта).

Чтобы решить эту проблему, рассмотрите возможность настройки централизованного сервера ведения журналов . Все, что вам нужно для этого, — это еще одна коробка с открытым UDP-портом 514 (по умолчанию). Чтобы заставить rsyslogd прослушивать соединения, добавьте следующую строку в его файл конфигурации:

 $UDPServerRun 514

Имея это, настроить клиент так же просто, как:

 *.* @HOSTNAME:514

(где HOSTNAME — это имя хоста вашего удаленного сервера регистрации).

Заключение

Хотя в этой статье продемонстрированы некоторые творческие способы, с помощью которых файлы журналов могут предоставить гораздо более ценную информацию, чем вы могли себе представить ранее, важно подчеркнуть, что мы только коснулись того, что возможно. Объем, объем и формат того, что вы можете регистрировать, практически безграничны. Это означает, что если есть данные об использовании или аналитические данные, которые вы хотите извлечь из журналов, вам просто нужно зарегистрировать их таким образом, чтобы впоследствии было легко анализировать и анализировать их. Более того, этот анализ часто можно выполнить с помощью стандартных инструментов командной строки Linux, таких как grep , sed или awk .

Действительно, файлы журналов PHP — это мощнейший инструмент, который может принести огромную пользу.

Ресурсы

Код на GitHub: https://github.com/isanosyan/toptal-blog-logs-post-example


Приложение: Чтение файлов журнала и управление ими в оболочке Unix

Вот краткое введение в некоторые из наиболее распространенных инструментов командной строки * nix, с которыми вам нужно ознакомиться для чтения и управления вашими файлами журналов.

  • cat , пожалуй, самая простая. Он печатает весь файл в выходной поток. Например, следующая команда выведет logfile1 на консоль:

     cat logfile1
  • > позволяет пользователю перенаправить вывод, например, в другой файл. Открывает целевой поток в режиме записи (что означает стирание целевого содержимого). Вот как мы заменяем содержимое tmpfile содержимым logfile1 :

     cat logfile1 > tmpfile
  • >> перенаправляет вывод и открывает целевой поток в режиме добавления. Текущее содержимое целевого файла будет сохранено, новые строки будут добавлены в конец. Это добавит содержимое logfile1 в tmpfile :

     cat logfile1 >> tmpfile
  • grep фильтрует файл по некоторому шаблону и печатает только совпадающие строки. Команда ниже будет печатать только строки logfile1 , содержащие сообщение Bingo :

     grep Bingo logfile1
  • cut выводит содержимое одного столбца (по номерам, начиная с 1). По умолчанию ищет символы табуляции в качестве разделителей между столбцами. Например, если у вас есть файл, полный меток времени в формате YYYY-MM-DD HH:MM:SS , это позволит вам печатать только годы:

     cut -d"-" -f1 logfile1
  • head отображает только первые строки файла

  • tail отображает только последние строки файла

  • sort сортирует строки в выводе

  • uniq отфильтровывает повторяющиеся строки

  • wc подсчитывает слова (или строки при использовании с флагом -l )

  • | (т. е. символ «труба») подает выходные данные одной команды в качестве входных данных для следующей. Pipe очень удобна для объединения команд. Например, вот как мы можем найти месяцы 2014 года, которые встречаются в наборе временных меток:

     grep -E "^2014" logfile1 | cut -d"-" -f2 | sort | uniq

Здесь мы сначала сопоставляем строки с регулярным выражением «начинается с 2014», а затем вырезаем месяцы. Наконец, мы используем комбинацию sort и uniq для печати вхождений только один раз.