143

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

21 Answers 21

170
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. Commented 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
    Commented 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. Commented 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
    Commented Nov 15, 2017 at 9:45
  • Does it correspond to Magento 2.3 also? thanks in advance Commented May 18, 2020 at 12:03
187

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.! Commented Dec 3, 2015 at 11:05
  • 2
    @Manashvibirla : PHP objects are not printing... Commented 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 Commented 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. Commented Jul 6, 2017 at 16:17
  • 19
    It's king of embaressing how often I come here to copy and use this... <3
    – Lez
    Commented Oct 4, 2019 at 19:15
89
\Magento\Framework\App\ObjectManager::getInstance()
    ->get(\Psr\Log\LoggerInterface::class)->debug('message');
7
  • 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. Commented Dec 3, 2015 at 7:21
  • 1
    That's the correct answer.
    – medina
    Commented May 23, 2016 at 5:14
  • 5
    I would not advice to use the ObjectManager directly. Use DI instead
    – 7ochem
    Commented Nov 4, 2016 at 12:18
  • 17
    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. Commented 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. Commented Jul 6, 2017 at 16:06
56

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
    Commented Sep 11, 2020 at 14:26
15

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
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..

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"? Commented 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. Commented 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
    Commented 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));
7

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
    Commented May 12, 2017 at 14:56
  • 3
    @7ochem Oh yes, it is :v Commented May 14, 2017 at 6:23
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? Commented Dec 3, 2015 at 7:22
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. Commented 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');
3

You can use several formats.

Default logger

1: In Magento default format

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

public function logExample() {

    //To print string Output in debug.log
    $this->_logger->debug('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));
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
    Commented 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.

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

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