Magento 2 logging

Magento 2 logging

Logging is an important part of every development process. Logs provide insight into system processes of Magento 2 and are a great tool for tracking errors, significant events, exceptions and many more. In order for the logging library to be properly implemented with Magento 2, it must comply with PSR-3 standard.

Magento 2 comes with built-in logging solution based on Monolog Library which will be analyzed further in this article.

Main Magento 2 log class is “Magento\Framework\Logger\Monolog” and is defined in “MAGENTO2_ROOT/app/etc/di.xml”

<preference for=”Psr\Log\LoggerInterface” type=”Magento\Framework\Logger\Monolog”>

As mentioned before Monolog is a powerful logging tool that allows the user to use a wide range of handlers to their benefit, such as logging to files and syslog, sending alerts and e-mails, logging database activity, etc.

Logger class has 8 levels of logs and methods for each of those levels, usage of these methods depends on the type of the message user is logging.

Each of these methods accepts 2 arguments, first one is the message itself ( string) and the second one is an optional array (for example instance of an Exception object)

$this->_logger-> emergency($message, array $context = array());  //saved in var/log/system.log
 
$this->_logger-> alert($message, array $context = array())  //saved in var/log/system.log
 
$this->_logger-> critical($message, array $context = array())  //saved in var/log/system.log
 
$this->_logger-> error($message, array $context = array())  //saved in var/log/system.log
 
$this->_logger-> warning($message, array $context = array())  //saved in  var/log/system.log
 
$this->_logger-> notice($message, array $context = array())  //saved in var/log/system.log
 
$this->_logger-> info($message, array $context = array())  //saved in var/log/system.log
 
$this->_logger-> debug($message, array $context = array())  //saved in var/log/debug.log (does not work in production mode)

There is another method that can be used to log something with an arbitrary level passed as  first parameter

$this->_logger-> log($level, $message, array $context = array())

All exceptions, no matter what log level is used, are saved in var/log/exception.log

Using logger class

Magento 2 uses dependency injection so in order to use logger in our class we must pass it in our class constructor.

Here is an example of how to use logger in a custom class to log an exception.

class Example
{
     private $logger;
 
     public function __construct(\Psr\Log\LoggerInterface $logger) {
         $this->logger = $logger;
     }
 
     public function exampleMethod()
     {
         try {
             //do something
         } catch (\Exception $e) {
             $this->logger->critical('Error message', ['exception' => $e]);
         }
     }
 }

 

Note that we are passing \Psr\Log\LoggerInterface in our constructor, as mentioned at the beginning, preference for LoggerInterface is set to Monolog class in di.xml

In some cases it is not necessary to pass logger in constructor as some classes like  “Magento\Framework\View\Element\Template” and “Magento\Framework\Model\AbstractModel” already have $_logger property so if you extend one of these classes logger is already available.

Debug Logging

By default, Magento writes to the debug log only in default and develop mode, but not in production mode.

To change the default value in default and develop mode following command can be used:

1.  bin/magento setup:config:set –enable-debug-logging=true|false

2. bin/magento cache:flush

Database Logging

Another great Magento 2 functionality is logging database activity. By default, database log is saved in var/debug/db.log. Usage of database logging is highly recommended because it allows us to track all database queries and can help us find performance bottlenecks.

Use the following command to enable/disable database logging:

1.  bin/magento dev:query-log:enable|disable

2.  bin/magento cache:flush

Cron Logging

As of Magento 2.3.1 version cron log is more extensive and is now logged in var/log/cron.log instead of var/log/system.log

These were the basics of Magento 2 logging. Even though Magento 2 uses Monolog logger by default other logging solutions can be used by setting preference for LoggerInterface as long as it complies with PSR-3 standard.

There are also many other possibilities when it comes to logging such as creating custom handlers for custom log files, sending emails with log data, sending log records to a Slack account, etc.

In case you feel you need some extra help, we can offer you a detailed custom report based on our technical audit – feel free to get in touch and see what we can do for you!


Note! This article was revised on Aug 26, 2019. The original article was posted in 2015 by Domagoj Potkoc.

You made it all the way down here so you must have enjoyed this post! You may also like:

3 best open-source eCommerce platforms in 2021 Zrinka Antolovic
Zrinka Antolovic, | 8

3 best open-source eCommerce platforms in 2021

Declarative Schema feature in Magento 2 Josip Kovacevic
Josip Kovacevic, | 6

Declarative Schema feature in Magento 2

GDPR compliant Magento 2 database dump Deni Pesic
Deni Pesic, | 3

GDPR compliant Magento 2 database dump

11 comments

  1. Not to necro an old post- But sometimes Magento just logs useless information without a stack trace etc… What are your thoughts on enabling stack trace for every log entry?

  2. If you want to log all your application traces in a custom file without impacting Magento2 logging you must implement and use a Logger and an Handler.

    <?php
    
    namespace Example\Common\Logger;
    
    use Monolog\Logger;
    
    class ExampleLogger extends Logger
    {
    
        CONST LOGGER_NAME = "Example";
    
        /**
         * ExampleLogger constructor.
         * @param string $name
         * @param array $handlers
         * @param array $processors
         * @throws \Exception
         */
        public function __construct($name = "", array $handlers = array(), array $processors = array())
        {
            //var_dump($name);
            //var_dump($handlers);
    
            if (empty($handlers)) {
    
                $handlers = [
                    "example" => new AdamarketHandler()
                ];
            }
            //var_dump($handlers);
    
            if (empty($name)) {
                parent::__construct(self::LOGGER_NAME, $handlers, $processors);
            } else {
                parent::__construct($name, $handlers, $processors);
            }
        }
    
    }
    
    <?php
    
    namespace Example\Common\Logger;
    
    use Magento\Framework\Filesystem\Driver\File;
    use Magento\Framework\Filesystem\DriverInterface;
    use Magento\Framework\Logger\Handler\Base;
    use Monolog\Logger;
    
    class ExampleHandler extends Base
    {
    
        /**
         * File name
         * @var string
         */
        CONST FILE_NAME = '/var/log/example.log';
    
        /**
         * Logging level
         * @var int
         */
        protected $loggerType = Logger::DEBUG;
    
        public function __construct(
            DriverInterface $filesystem = null,
            $filePath = null,
            $fileName = null
        )
        {
            $filesystem = new File();
            parent::__construct($filesystem, $filePath, self::FILE_NAME);
        }
    }

    Nothing in the dependency injection Xml file. Use your logger class directly.

    PS: DO NOT put this in your di.xml !!!

    Hope it helps! ; )

    1. in my previous PS I meant: DO NOT put the following line inside the di.xml

  3. What if we want custom logger class to be used globally instead of ‘Psr\Log\LoggerInterface’?

  4. >>If you want to write a log in your custom file name, in a custom location, then the process is not that simple :-), you will have to create a custom Log handler.

    There is exist other way for doing this , for example you can just use StreamHandler and add it as handler for new instance in your helper ex. :

        /**
         * @var LoggerInterface
         */
        protected $_log;
    
    public function __construct(...,\Psr\Log\LoggerInterface $logLogger)
    {
            $this->_log = $logLogger;
            $this->_log->pushHandler( new \Monolog\Handler\StreamHandler( '/path/to/file.log'));
            $this->_log->debug('message');
    }
  5. Hi Domgoj, good article if you create a model type.
    What about if you want a logger inside an object where you don’t get the instance of logger in the construct passed as a param!?

  6. After testing arround I see that the _logger object is not available, if i extend \Magento\Framework\Model\AbstractModel, bacause its protected.

    So I have to pass the logger object through the constructor and save it in a local property?

  7. Hi Domagoj Potkoc,
    We changed some functionality in our logger. We remove Critical handler. Now all message with level from Alert to Info are writing to system.log file. Debug message are writing to debug.log. But we change some functionality in Magento\Framework\Logger\Handler\System, now if you sand Exception object to method alert, error, critical, notice, info, or any other method from Psr\Log\LoggerInterface except debug, your message will be write in exception.log.

    Please don’t use method “addDebug”. Better way use method “debug”, because Psr\Log\LoggerInterface doesn’t contain method “addDebug” and 3rd party developer can change Monolog\Logger for any other solution implements Psr\Log\LoggerInterface.

    Thanks for you article.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <blockquote cite=""> <code> <del datetime=""> <em> <s> <strike> <strong>. You may use following syntax for source code: <pre><code>$current = "Inchoo";</code></pre>.

Tell us about your project

Drop us a line. We'd love to know more about your project.