132

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

18 Answers 18

155
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
  • 12
    +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.
    – Alan Storm
    Dec 3 '15 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 '15 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 '17 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
    – Omer Sabic
    Nov 15 '17 at 9:45
  • Does it correspond to Magento 2.3 also? thanks in advance May 18 '20 at 12:03
178

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));
12
  • 7
    +1 Useful -- do you know if Zend logger will automatically format PHP arrays/objects etc?
    – Alan Storm
    Dec 3 '15 at 7:21
  • 3
    @AlanStorm - Yes you can, check my updated answer.! Dec 3 '15 at 11:05
  • 2
    @Manashvibirla : PHP objects are not printing... Mar 1 '16 at 6: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 '17 at 16:17
  • 16
    It's king of embaressing how often I come here to copy and use this... <3
    – Lez
    Oct 4 '19 at 19:15
79
\Magento\Framework\App\ObjectManager::getInstance()
    ->get(\Psr\Log\LoggerInterface::class)->debug('message');
8
  • 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.
    – Alan Storm
    Dec 3 '15 at 7:21
  • 1
    That's the correct answer.
    – medina
    May 23 '16 at 5:14
  • 5
    I would not advice to use the ObjectManager directly. Use DI instead
    – 7ochem
    Nov 4 '16 at 12:18
  • 15
    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 '17 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 '17 at 16:06
50

Read about QUICK WAY to print Log in any PHP file

Read More at: blog.mageprince.com

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));
2
  • 1
    Thanks man. I always search for it and use it whenever needed.
    – Avesh Naik
    Sep 11 '20 at 14:26
  • @AveshNaik It would better if you create a common function for logs. Check my article for more details: mageprince.com/blog/… Sep 12 '20 at 11:56
12

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"?
    – Alan Storm
    Dec 3 '15 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 '15 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 '15 at 3:47
10

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?
    – Alan Storm
    Dec 3 '15 at 7:22
5

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
  • 4
    Is this code implementing PSI? (Political Statements Injection) :P
    – 7ochem
    May 12 '17 at 14:56
  • 1
    @7ochem Oh yes, it is :v May 14 '17 at 6:23
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 '16 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');
2

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 '18 at 3:47
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

1 line approach:

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

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

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