142

In Magento 1, if you wanted to send a message to the logs, you'd use a static method on the global Mage class.

Mage::log($message, Zend_Log::DEBUG, "my-log-file.log");

Is there an equivalent in Magento 2? I've googled through the dev docs site and haven't seen anything obvious that pops out. There's this Inchoo article, but it's from almost a year ago and so much has changed since then.

As a Magento 2 module developer, if I want to replace code like the following in Magento 1

Mage::log($message, Zend_Log::DEBUG, "my-log-file.log");

What's the bare minimum I need to do?

3

22 Answers 22

168
protected $logger;
public function __construct(\Psr\Log\LoggerInterface $logger)
{
    $this->logger = $logger;
}

You use debug, exception, system for PSR Logger for example:

$this->logger->info($message);
$this->logger->debug($message);

HINT:

Don't forget to run php bin/magento setup:di:compile

5
  • 13
    +1 Thank you, that's a useful interface/class/type to know about -- but it's not clear from your answer where the information will be logged and how (if possible) to change that location. Dec 3, 2015 at 7:21
  • You check Manager.php for following class Magento\Framework\Event and add this line $this->logger->debug($eventName); than after refresh page and check debug.txt file you get all evant name for specific page.
    – Pratik
    Dec 3, 2015 at 7:30
  • 4
    Technically, this is the 'correct' way to instantiate a logger in your own custom classes - particularly if you intend to keep it around rather than just some quick debug. However, there are several core classes - particularly Block classes - which automatically instantiate and store a _logger property. If you extend one of these core classes then there's no need to repeat the logic. Other answers dig into creating handlers to define your own log file, but the default logs are always /var/log/system.log or /var/log/debug.log. I believe the specific logging function determines which is used. Jul 6, 2017 at 16:11
  • 7
    For me, the "debug" level started to work only when I enabled "Log to file" in Configuration > Advanced > Developer > Debug. Using 2.2
    – SlimDeluxe
    Nov 15, 2017 at 9:45
  • Does it correspond to Magento 2.3 also? thanks in advance May 18, 2020 at 12:03
186

In magento2, You can also write to the logs using the Zend library like below :

$writer = new \Zend\Log\Writer\Stream(BP . '/var/log/test.log');
$logger = new \Zend\Log\Logger();
$logger->addWriter($writer);
$logger->info('Your text message');

Edited

You can also print PHP objects and arrays like below :

$logger->info(print_r($yourArray, true));
13
  • 3
    @AlanStorm - Yes you can, check my updated answer.! Dec 3, 2015 at 11:05
  • 2
    @Manashvibirla : PHP objects are not printing... Mar 1, 2016 at 6:43
  • 2
    @KeyurShah The solution was provided by keeping ubuntu in mind, as i was using ubuntu.! thanks for the feedback Nov 16, 2016 at 9:43
  • 5
    Several of these answers have their place and use. Obviously this solution requires almost as much code as using DI to instantiate the standard logger -- but it's a simple in-place drop-in which lets you set your own log file. Sometimes it's rather annoying to search through the standard log files - which tend to get cluttered - to find your own logs. So this is a nice 'quick' solution for that. Jul 6, 2017 at 16:17
  • 18
    It's king of embaressing how often I come here to copy and use this... <3
    – Lez
    Oct 4, 2019 at 19:15
89
\Magento\Framework\App\ObjectManager::getInstance()
    ->get(\Psr\Log\LoggerInterface::class)->debug('message');
6
  • 9
    +1 Thank you, that's a useful interface/class/type to know about -- but it's not clear from your answer where the information will be logged and how (if possible) to change that location. Dec 3, 2015 at 7:21
  • 1
    That's the correct answer.
    – medina
    May 23, 2016 at 5:14
  • 5
    I would not advice to use the ObjectManager directly. Use DI instead
    – 7ochem
    Nov 4, 2016 at 12:18
  • 16
    While I agree with @7ochem if you're creating a permanent logging function, it can be necessary to inject temporary logging into core (or third party) classes from time to time to debug issues. Going through the arduous process of adding a Logger class to the constructor is pointlessly over-complicated in these cases. For a simple, single-line debug function this is probably the best solution. However, you will have to deal with searching through the default log files to find your own debug output. Jul 6, 2017 at 16:02
  • Also keep in mind that there are several core classes - particularly Block classes - which have a _logger property you can access without instantiating a new copy. Jul 6, 2017 at 16:06
55

Temporary print log with new file

$writer = new \Zend\Log\Writer\Stream(BP . '/var/log/logfile.log');
$logger = new \Zend\Log\Logger();
$logger->addWriter($writer);
$logger->info('Simple Text Log'); // Simple Text Log
$logger->info('Array Log'.print_r($myArrayVar, true)); // Array Log

Factory Method

You need to inject \Psr\Log\LoggerInterface class into constructor to call logger object

protected $_logger;
public function __construct(
...
\Psr\Log\LoggerInterface $logger
...
) {
    $this->_logger = $logger;
}

public function logExample() {

    //To print string Output in debug.log
    $this->_logger->addDebug('Your Text Or Variables'); 
    
    // To print array Output in system.log
    $this->_logger->log('600', print_r($yourArray, true));

}

Or you directly use this code in phtml file:

To print string Output in debug.log

\Magento\Framework\App\ObjectManager::getInstance()
   ->get('Psr\Log\LoggerInterface')->debug('Your Message');

To print array Output in system.log

$myArray = array('test1'=>'123', 'test2'=>'123', 'test3'=>'123');
$level = '100'; // use one of: 100, 200, 250, 300, 400, 500, 550, 600
\Magento\Framework\App\ObjectManager::getInstance()
    ->get('Psr\Log\LoggerInterface')
    ->log($level, print_r($myArray, true));

Update: Latest Magento version:

Write logs using the Lamina library:

$writer = new \Laminas\Log\Writer\Stream(BP . '/var/log/logfile.log');
$logger = new \Laminas\Log\Logger();
$logger->addWriter($writer);
$logger->info('Simple Text Log'); // Simple Text Log
$logger->info('Array Log'.print_r($myArrayVar, true)); // Array Log
1
  • 1
    Thanks man. I always search for it and use it whenever needed.
    – Avesh Naik
    Sep 11, 2020 at 14:26
14

In a simple way if you don't want to create dependency injection or anything else use below code it will store log in system.log file

$logger = \Magento\Framework\App\ObjectManager::getInstance()->get(\Psr\Log\LoggerInterface::class);
$logger->info('message');

That's all..

14

Magento 2.4+

$writer = new \Zend_Log_Writer_Stream(BP . '/var/log/testlog.log');
$logger = new \Zend_Log();
$logger->addWriter($writer);
$logger->info('testt'); // Print string type data
$logger->info('Data::' . print_r($arrData, true)); // Print array type data
11

If you want to use default logger but custom file for logging (or other custom logic) you need to use custom logger handler:

class Logger extends Magento\Framework\Logger\Handler\Base
{
  /**
   * @var string
   */
  protected $fileName = '/var/log/my-log-file.log';

  /**
   * @var int
   */
  protected $loggerType = MonologLogger::DEBUG;
}

Then add it as handler somewhere within your code:

protected function addCustomLogHandler()
{
    $logger = Data::getCustomLogger();
    if(isset($this->_logger)){
        $this->_logger->pushHandler($logger);
    }
}

A step back in convenience IMO

3
  • +1 Useful information, thank you! However, it's not clear how you use this logger context with the PSR-3 autoloader interface - i.e. if you're logging with $this->logger->info($message, $level); -- how do you say "use my context"? Dec 3, 2015 at 17:39
  • 2
    Well the thing is that all handlers that are available to Monolog are looped and first that can handle the level of record (DEBUG, INFO etc.) is used. So the only way I see to be absolutely sure that your handler is used, is to push it before you need it, so its at top of the stack and comes first in the loop. Another way would be to just SET it as handler, removing all others, but that won't be very friendly thing to do. Dec 3, 2015 at 18:42
  • If you try to introduce additional handlers in the 2.0.0 GA, or work with specifying the handlers in di.xml you may want to be aware of this issue github.com/magento/magento2/issues/2529 I ran into this issue trying to get a custom logger to have a custom log file handle, and a custom handler that writes some entries to a database table.
    – mttjohnson
    Dec 7, 2015 at 3:47
9

You can use this packages

composer require cleatsquad/logger

Examples

\CleatSquad\Logger::log('test', 'test.log');
\CleatSquad\Logger::log('test', 'test.log', \Monolog\Logger::WARNING);
\CleatSquad\Logger::log(['test' => 'is an array'], 'test.log');

Or you can use Laminas

After magento 2.3.5 we replace Zend By Laminas

You can also write to the logs using the Lamina library like below :

$writer = new \Laminas\Log\Writer\Stream(BP . '/var/log/test.log');
$logger = new \Laminas\Log\Logger();
$logger->addWriter($writer);
$logger->info('Your text message');


$data = ["test" => "testing"];
$logger->debug(var_export($data, true));
6

No, there is no direct equivalent. It's a bit complicated now.

See: Logging to a custom file in Magento 2

1
  • 2
    +1, thank you! However -- other answers make it sound like there may be a single logger, and the extend/create a handle approach is no longer necessary. Do you know if that's true? Dec 3, 2015 at 7:22
6

UPDATED: 19/08/2019

If you are looking for elegant custom log handler, I recommend you to use Virtual Types (which doesn't need to add any PHP code)

Inspired from the answer of Petar Dzhambazov and halk, ladies and gentlemen I introduced you a better and shorter way instead of duplicated custom log code all the time.

StackOverflow\Example\etc\di.xml

<!-- Custom log file for StackOverflow ; Duplicate it as much as you want separate log file -->
<virtualType name="StackOverflow\Example\Model\Logger\VirtualDebug" type="Magento\Framework\Logger\Handler\Base">
    <arguments>
        <argument name="fileName" xsi:type="string">/var/log/stackoverflow/donald_trump.log</argument>
    </arguments>
</virtualType>
<virtualType name="StackOverflow\Example\Model\Logger\VirtualLogger" type="Magento\Framework\Logger\Monolog">
    <arguments>
        <argument name="name" xsi:type="string">DonaldTrump</argument>
        <argument name="handlers" xsi:type="array">
            <item name="debug" xsi:type="object"> StackOverflow\Example\Model\Logger\VirtualDebug</item>
        </argument>
    </arguments>
</virtualType>

USAGE

Vendor\Something\Model\DonaldTrump.php

<?php
/**
 * Copyright © 2016 Toan Nguyen <https://nntoan.github.io>. All rights reserved.
 * See COPYING.txt for license details.
 *
 * This is the file you want to inject your custom logger.
 * Of course, your logger must be an instance of \Psr\Log\LoggerInterface.
 */

namespace Vendor\Something\Model;

/**
 * DonaldTrump business logic file
 *
 * @package Vendor\Something\Model
 * @author  Toan Nguyen <https://github.com/nntoan>
 */
class DonaldTrump
{
    /**
     * @var \Psr\Log\LoggerInterface
     */
    private $logger;

    /**
     * DonaldTrump constructor.
     *
     * @param \Psr\Log\LoggerInterface $logger
     */
    public function __construct(
        \Psr\Log\LoggerInterface $logger,
    ) {
        $this->logger = $logger;
    }

    // 1 billion lines of code after this line
}

StackOverflow\Example\etc\frontend\di.xml

<type name="Vendor\Something\Model\DonaldTrump">
    <arguments>
        <argument name="logger" xsi:type="object">StackOverflow\Example\Model\Logger\VirtualLogger</argument>
    </arguments>
</type>

That's all, no extra PHP files or lines - use the advantages of Magento 2: Virtual Types!!!

Hope this helps ;)

2
  • 6
    Is this code implementing PSI? (Political Statements Injection) :P
    – 7ochem
    May 12, 2017 at 14:56
  • 3
    @7ochem Oh yes, it is :v May 14, 2017 at 6:23
5

for magento 2.3.4 you can use :

$writer = new \Zend_Log_Writer_Stream(BP . '/var/log/custom.log');
$logger = new \Zend_Log();
$logger->addWriter($writer);
$logger->info('text message');
4

Include psr logger class in your file using use and then call addDebug() method. This will print log message in var/log/debug.log file

use Psr\Log\LoggerInterface;

class demo {
  function demo()
  {
    //EDIT: Using debug instead of addDebug for PSR compatiblity
    $this->_objectManager->get('Psr\Log\LoggerInterface')->debug("your message goes here");
  }

}
1
  • 2
    you shouldn't ujse addDebug as that's not psr logger compatible. use just debug instead. Nov 9, 2016 at 15:56
3
$writer = new \Zend\Log\Writer\Stream(BP . '/var/log/test.log');
$logger = new \Zend\Log\Logger();
$logger->addWriter($writer);
$logger->info('Your text message');
1
  1. Inject $logger class in constructor \Psr\Log\LoggerInterface $logger
    This is achieved by passing $logger as argument.

  2. Initialize $logger in constructor

    $this->logger = $logger
    
  3. In function within the class you want to log use the below line

    $this->logger->debug($message);
    $this->logger->log($level, $message);
    
1

If you need it within your single class with custom log file:

public function __construct(\Psr\Log\LoggerInterface $logger, \Magento\Framework\App\Filesystem\DirectoryList $dir) 
{
    $this->logger = $logger;
    $this->dir = $dir;

    $this->logger->pushHandler(new \Monolog\Handler\StreamHandler($this->dir->getRoot().'/var/log/custom.log'));
}
1

There is one update for logger in 2.2. You can enable logger for production mode by run SQL:

 "INSERT INTO core_config_data (scope, scope_id, path, value) VALUES ('default', '0', 'dev/debug/debug_logging', '1');"

Then you can use \Psr\Log\LoggerInterface for print log just like above answers:

protected $logger;

public function __construct(
  \Psr\Log\LoggerInterface $logger
) {
    $this->logger = $logger;
  }

public function yourFunction() {
    $data = ["test" => "testing"];
    $this->logger->debug(var_export($data, true));
}
1
  • 1
    thanks, and you can also use this instead of QUERY SQL: In the Magento admin panel, go to "Stores" -> "Configuration" -> "Advanced" -> "Developer" -> "Debug" -> "Log to File". Setting this to "Yes" will cause debug information to be logged to var/log/debug.log in your Magento application directory.
    – fudu
    Oct 31, 2018 at 3:47
1

magento 2 logs

you can try it...

$writer = new \Zend\Log\Writer\Stream(BP . '/var/log/test.log');
$logger = new \Zend\Log\Logger(); $logger->addWriter($writer);
$logger->info($category->getData());

1

For me in M2.3.4, this is the one-liner that works and allows me to log into any file:

(new \Zend_Log())->addWriter(new \Zend_Log_Writer_Stream(BP . '/var/log/custom.log'))->info(print_r($foo, true));

Though I am not sure if the Zend_Log_Writer_Stream is coming from my environment or from Magento, so just try it out.

1

You can use several formats.

Default logger

1: In Magento default format

protected $_logger;
public function __construct(
    ...
    \Psr\Log\LoggerInterface $logger
    ...
) {
    $this->_logger = $logger;
}

public function logExample() {

    //To print string Output in debug.log
    $this->_logger->addDebug('Your Text Or Variables'); 
    
    // To print array Output in system.log
    $this->_logger->log('600', print_r($yourArray, true));

}

Custom logger

2: This will work with the older version of Magento 2.4.3:

$writer = new \Zend\Log\Writer\Stream(BP . '/var/log/test.log');
$logger = new \Zend\Log\Logger();
$logger->addWriter($writer);
$logger->info('Your text message');
$logger->info('getAllowProducts'.print_r($subject->getAllowProducts(), true));

3: This will work with the newest Magento 2.4.3+:

$writer = new \Zend_Log_Writer_Stream(BP . '/var/log/custom.log');
$logger = new \Zend_Log();
$logger->addWriter($writer);
$logger->info('Your text message');
$logger->info('getAllowProducts'.print_r($subject->getAllowProducts(), true));
0

Place PSR logger code in your constructor:

protected $logger;
public function __construct(\Psr\Log\LoggerInterface $logger)
{
    $this->logger = $logger;
}

then you can use in your function like:

$this->logger->info($message);
0

1 line approach:

\Magento\Framework\App\ObjectManager::getInstance() ->get(\Psr\Log\LoggerInterface::class)->info('yourmessage');

0

Magento 2 ( 2.4.X ) - Magento 2 logs - Magento 2 default logs

$writer = new \Zend_Log_Writer_Stream(BP . '/var/log/testlog-thala-vkk.log');
$logger = new \Zend_Log();
$logger->addWriter($writer);
$logger->info('testt'); // Print string type data
$logger->info('Data::' . print_r($arrData, true)); // Print array type data

Not the answer you're looking for? Browse other questions tagged or ask your own question.