📜 ⬆️ ⬇️

Using Log4php in Magento Applications

Magento is without doubt an outstanding system for building e-commerce applications. The principles embodied in its architecture allowed not only to take the first place in the class rating of web applications and retain it for many years, but, more importantly, to form around them an eco-system of developers creating extensions for the main functionality that satisfy the most exotic requirements. users. But what Magento really lacked for me when I first approached the projectile was Log4php logging systems . Therefore, the first extension that was made for Magento is the “wrapper” for Log4php. Under the cut description of how we use this "wrapper" in our Magento-projects.


“Wrapper” for “wrapper”


To reduce the dependence of our other modules on Praxigento_Log, each of our modules contains its own logger, which, depending on the configuration of the Magento application, uses either the native Magento-logger or Log4php if the Praxigento_Log module is installed.

Here is the code for this wrapper.
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); } } 


')
This code is identical for all our modules (except for the name of the class itself) and allows you to use logging, regardless of whether the application contains the Praxigento_Log module or not. Here is an example of a call:

  $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'); 


And here are the logs themselves in the presence of the Praxigento_Log module (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 


... and in its absence (Zend_Log framework, file 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 configuration


Magento specifies the path to the Log4php configuration file:
image
in which all logging parameters are configured.

Configuration example
 <?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> 



Bonuses Log4php



Record Source


When creating a logger, the name of the class in which this logger is used is used:
  $log = Praxigento_Module_Logger::getLogger(__CLASS__); 

as a result, the logs can distinguish the messages of one class from the messages of another. So for the Praxigento_Bonus_Test_Logger_UnitTest class, the message in the log will look something like this (depends on the logging settings):
 2015/06/25 09:59:55,973 TRACE P\B\T\L\UnitTest: trace level message 

which is convenient when, in the general stream, you need to select messages from a particular class:
 $ cat ./var/log/old/log4php.log_20150623 | grep 'P\\B\\T\\L\\UnitTest' 


Differentiation by logging level and source


Depending on the level selected in the configuration file, it is possible to detail the output to the log depending on the load or in case of failures in the application. And you can pour in a separate log all messages from any class or group of classes:
  <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 Alerts


In case of errors (levels of fatal, error, warn), you can send the corresponding log entries by 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 logging


In the module, an additional class LoggerAppenderMemory has been added to the original Log4php applications, which allows access to the logs from the Magento application:
  <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> 


In our applications, we use a similar approach if we have to run tasks from the admin panel, which are usually performed via cron. The list of log records is simply displayed in a web interface with the required level of detail:


Installation


At the moment we use Composer to deploy our Magento-projects, therefore the installation description is given for this method. Module installation is also possible through Magento Connect (there it passes under the previous name - Nmmlm_Log).

To connect the module through Composer, you need to specify in the file composer.json:
 { "require": { "praxigento/mage_ext_log4php": "*" }, "repositories": [ { "type": "vcs", "url": "https://github.com/praxigento/mage_ext_log4php" } ] } 


You can also download the source of the module, unpack it and copy the contents from the ./src/ directory to the root directory of your Magento application.

Source: https://habr.com/ru/post/253665/


All Articles