Magento без сомнения является выдающейся системой для построения e-commerce приложений. Принципы, заложенные в ее архитектуру, позволили не только занять первое место рейтинга в своем классе web-приложений и удерживать его многие годы, но, что более важно, сформировать вокруг себя эко-систему разработчиков, создающих для основного функционала расширения, удовлетворяющие самым экзотическим требованиям пользователей. Но вот чего мне сильно очень сильно не хватало в Magento при первом «подходе к снаряду», так это системы логирования уровня Log4php. Поэтому первое расширение, которое было сделано для Magento — это «обертка» для Log4php. Под катом описание того, как мы используем эту «обертку» в наших Magento-проектах.
«Обертка» для «обертки»
Чтобы уменьшить зависимость других наших модулей от Praxigento_Log, каждый наш модуль содержит свой собственный logger, который в зависимости от конфигурации Magento-приложения использует либо «родной» Magento-logger, либо Log4php, если установлен модуль Praxigento_Log.
class Praxigento_Module_Logger { private static $_isLog4phpUsed = null; private $_loggerLog4php; private $_name; function __construct($name) { /** * switch off/on error reporting to prevent messages like * "ERR (3): Warning: include(Praxigento\Log\Logger.php): failed to open stream: No such file or directory" * in case of Praxigento_Log module is not used. */ $level = error_reporting(0); self::$_isLog4phpUsed = class_exists('Praxigento_Log_Logger', true); error_reporting($level); if (self::$_isLog4phpUsed) { $this->_loggerLog4php = Praxigento_Log_Logger::getLogger($name); } else { $this->_name = is_object($name) ? get_class($name) : (string)$name; } } /** * Override getter to use '$log = Praxigento_Log_Logger::getLogger($this)' form in Mage classes. */ public static function getLogger($name) { $class = __CLASS__; return new $class($name); } public function debug($message, $throwable = null) { $this->doLog($message, $throwable, 'debug', Zend_Log::INFO); } /** * Internal dispatcher for the called log method. */ private function doLog($message, $throwable, $log4phpMethod, $zendLevel) { if (self::$_isLog4phpUsed) { $this->_loggerLog4php->$log4phpMethod($message, $throwable); } else { Mage::log($this->_name . ': ' . $message, $zendLevel); if ($throwable instanceof Exception) { Mage::logException($throwable); } } } public function error($message, $throwable = null) { $this->doLog($message, $throwable, 'error', Zend_Log::ERR); } public function fatal($message, $throwable = null) { $this->doLog($message, $throwable, 'fatal', Zend_Log::CRIT); } public function info($message, $throwable = null) { $this->doLog($message, $throwable, 'info', Zend_Log::NOTICE); } public function trace($message, $throwable = null) { $this->doLog($message, $throwable, 'trace', Zend_Log::DEBUG); } public function warn($message, $throwable = null) { $this->doLog($message, $throwable, 'warn', Zend_Log::WARN); } }
Этот код идентичен для всех наших модулей (за исключением названия самого класса) и позволяет использовать логирование вне зависимости от того есть ли в приложении модуль Praxigento_Log или его нет. Вот, собственно, пример вызова:
$log = Praxigento_Module_Logger::getLogger(__CLASS__); $log->trace('trace level message'); $log->debug('debug level message'); $log->info('info level message'); $log->warn('warn level message'); $log->error('error level message'); $log->fatal('fatal level message');
А вот и сами логи при наличии модуля Praxigento_Log (Log4php framework):
2015/06/25 09:59:55,973 TRACE P\B\T\L\UnitTest: trace level message 2015/06/25 09:59:55,973 DEBUG P\B\T\L\UnitTest: debug level message 2015/06/25 09:59:55,974 INFO P\B\T\L\UnitTest: info level message 2015/06/25 09:59:55,974 WARN P\B\T\L\UnitTest: warn level message 2015/06/25 09:59:55,975 ERROR P\B\T\L\UnitTest: error level message 2015/06/25 09:59:55,975 FATAL P\B\T\L\UnitTest: fatal level message
… и при его отсутствии (Zend_Log framework, файл var/log/system.log):
2015-06-25T10:07:00+00:00 DEBUG (7): Praxigento_Bonus_Test_Logger_UnitTest: trace level message 2015-06-25T10:07:00+00:00 INFO (6): Praxigento_Bonus_Test_Logger_UnitTest: debug level message 2015-06-25T10:07:00+00:00 NOTICE (5): Praxigento_Bonus_Test_Logger_UnitTest: info level message 2015-06-25T10:07:00+00:00 WARN (4): Praxigento_Bonus_Test_Logger_UnitTest: warn level message 2015-06-25T10:07:00+00:00 ERR (3): Praxigento_Bonus_Test_Logger_UnitTest: error level message 2015-06-25T10:07:00+00:00 CRIT (2): Praxigento_Bonus_Test_Logger_UnitTest: fatal level message
Конфигурация Log4php
В Magento указывается путь к конфигурационному файлу Log4php:

в котором и настраиваются все параметры логирования.
<?xml version="1.0" encoding="UTF-8"?> <configuration xmlns="http://logging.apache.org/log4php/"> <!-- *********************************************************************************************** THIS IS SAMPLE CONFIGURATION THAT WILL BE REWRITTEN ON REINSTALL. DON'T USE THIS FILE IN YOUR CONFIGURATION. MAKE A COPY TO "app/etc/log4php.cfg.xml" AND CHANGE "SYSTEM / CONFIGURATION / DEVELOPER / LOG SETTINGS / LOG4PHP CONFIG FILE NAME" VALUE *********************************************************************************************** --> <!-- Available log levels: ALL -> TRACE -> DEBUG -> INFO -> WARN -> ERROR -> FATAL -> OFF Available appenders: http://logging.apache.org/log4php/docs/appenders.html appenders/LoggerAppenderMemory Available layouts: http://logging.apache.org/log4php/docs/layouts.html --> <!-- default appender --> <appender name="fileDefault" class="LoggerAppenderFile"> <layout class="LoggerLayoutPattern"> <param name="conversionPattern" value="%d{Y/m/d H:i:s,u} %p %c{2}: %m%n"/> </layout> <param name="file" value="/absolute/path/to/file/log4php.log"/> <param name="append" value="true"/> </appender> <!-- In-memory log for Adminhtml (backend sync output) --> <appender name="memoryDefault" class="LoggerAppenderMemory" threshold="DEBUG"> <layout class="LoggerLayoutPattern"> <param name="conversionPattern" value="%date{H:i:s,u} %p %c{2}: %msg%n"/> </layout> </appender> <!-- ERROR mail appender --> <appender name="emailError" class="LoggerAppenderMail"> <layout class="LoggerLayoutPattern"> <param name="conversionPattern" value="%d{Y/m/d H:i:s,u} %p %c{2}: %m%n"/> </layout> <param name="to" value="comma-separeted@emails.com"/> <param name="from" value="project-name@praxigento.com"/> <filter class="LoggerFilterLevelRange"> <param name="levelMin" value="ERROR"/> <param name="levelMax" value="FATAL"/> </filter> </appender> <!-- root logger --> <root> <appender_ref ref="fileDefault"/> <appender_ref ref="memoryDefault"/> <appender_ref ref="emailError"/> <level value="ALL"/> </root> </configuration>
Бонусы Log4php
Источник записи
При создании логгера используется имя класса в котором этот логгер используется:
$log = Praxigento_Module_Logger::getLogger(__CLASS__);
в результате, в логах можно отличить сообщения одного класса от сообщений другого. Так для класса Praxigento_Bonus_Test_Logger_UnitTest сообщение в логе будет выглядеть примерно так (зависит от настроек логирования):
2015/06/25 09:59:55,973 TRACE P\B\T\L\UnitTest: trace level message
что бывает удобно, когда в общем потоке нужно выделить сообщения от конкретного класса:
$ cat ./var/log/old/log4php.log_20150623 | grep 'P\\B\\T\\L\\UnitTest'
Дифференциация по уровню логирования и источнику
В зависимости от выбранного в конфигурационном файле уровня можно детализировать вывод в лог в зависимости от нагрузки или в случае возникновения сбоев в приложении. Причем можно лить в отдельный лог все сообщения от какого-либо класса или группы классов:
<root> <appender_ref ref="defaultLog"/> <level value="INFO"/> </root> <logger name="Praxigento_Bonus_Test_Logger_UnitTest"> <appender_ref ref="failureLog"/> <level value="TRACE"/> </logger>
Email-оповещения
В случае возникновения ошибок (уровни fatal, error, warn) можно отправлять соответствующие лог-записи по email’у:
<appender name="emailInfo" class="LoggerAppenderMail"> <layout class="LoggerLayoutPattern"> <param name="conversionPattern" value="%d{Y/m/d H:i:s,u} %p %c{2}: %m%n"/> </layout> <param name="to" value="support@praxigento.com,developers@praxigento.com"/> <param name="from" value="some-project@prxgt.com"/> <filter class="LoggerFilterLevelRange"> <param name="levelMin" value="WARN"/> <param name="levelMax" value="FATAL"/> </filter> </appender>
In-memory логирование
В модуле к оригинальным Log4php апендерам добавлен дополнительный класс LoggerAppenderMemory, который позволяет получать доступ к логам из Magento-приложения:
<appender name="memoryDefault" class="LoggerAppenderMemory" threshold="DEBUG"> <layout class="LoggerLayoutPattern"> <param name="conversionPattern" value="%date{H:i:s,u} %p %c{2}: %msg%n"/> </layout> </appender>
$log = Praxigento_Module_Logger::getLogger(__CLASS__); $log->debug('...'); $debugLog = LoggerAppenderMemory::getEventsAsArray();
<pre class="prxgt_console"> <?php foreach ($debugLog as $entry) { echo trim($entry) . "\n"; }?> </pre>
В наших приложениях мы используем подобный подход в случае, если приходится из админки запускать задачи, которые обычно выполняются через cron. Список лог-записей просто выводится в web-интерфейс с требуемым уровнем детализации:

Установка
На данный момент мы для развертывания наших Magento-проектов используем Composer, поэтому описание установки дается для этого метода. Установка модуля также возможна через Magento Connect (там он проходит под предыдущим названием — Nmmlm_Log).
Для подключения модуля через Composer нужно указать в файле composer.json:
{ "require": { "praxigento/mage_ext_log4php": "*" }, "repositories": [ { "type": "vcs", "url": "https://github.com/praxigento/mage_ext_log4php" } ] }
Можно также закачать исходники модуля, распаковать его и скопировать содержимое из каталога ./src/ в корневой каталог вашего Magento-приложения.
ссылка на оригинал статьи http://habrahabr.ru/post/253665/
Добавить комментарий