I'm trying to fully understand Magento's error handling.

I noticed that sometimes if a fatal error occurs, a report is created in var/report (and an email is sent - depending on configuration) and on other occasions an error message is logged in var/log/exception.log. This all happens on the same installation, so it can't be a configuration thing.

How does Magento decide where to store an error message?

up vote 9 down vote accepted

So the default behavior for an uncatched error (when developer mode is deactivated) is to create a report. That ultimate catch is handled in the Mage.php:

public static function init($code = '', $type = 'store', $options = array(), $modules = array())
{
    try {
        self::setRoot();
        self::$_app     = new Mage_Core_Model_App();
        self::_setIsInstalled($options);
        self::_setConfigModel($options);

        if (!empty($modules)) {
            self::$_app->initSpecified($code, $type, $options, $modules);
        } else {
            self::$_app->init($code, $type, $options);
        }
    } catch (Mage_Core_Model_Session_Exception $e) {
        header('Location: ' . self::getBaseUrl());
        die;
    } catch (Mage_Core_Model_Store_Exception $e) {
        require_once(self::getBaseDir() . DS . 'errors' . DS . '404.php');
        die;
    } catch (Exception $e) {
        self::printException($e);
        die;
    }
}

If you dig deeper into printException you can see that it decides if dev mode is activated or not. If it's activated it'll just output the exception and in production mode prepare the data and include errors/report.php.

public static function printException(Exception $e, $extra = '')
{
    if (self::$_isDeveloperMode) {
        print '<pre>';

        if (!empty($extra)) {
            print $extra . "\n\n";
        }

        print $e->getMessage() . "\n\n";
        print $e->getTraceAsString();
        print '</pre>';
    } else {

        $reportData = array(
            !empty($extra) ? $extra . "\n\n" : '' . $e->getMessage(),
            $e->getTraceAsString()
        );

        // retrieve server data
        if (isset($_SERVER)) {
            if (isset($_SERVER['REQUEST_URI'])) {
                $reportData['url'] = $_SERVER['REQUEST_URI'];
            }
            if (isset($_SERVER['SCRIPT_NAME'])) {
                $reportData['script_name'] = $_SERVER['SCRIPT_NAME'];
            }
        }

        // attempt to specify store as a skin
        try {
            $storeCode = self::app()->getStore()->getCode();
            $reportData['skin'] = $storeCode;
        }
        catch (Exception $e) {}

        require_once(self::getBaseDir() . DS . 'errors' . DS . 'report.php');
    }

    die();
}

errors/reports.php itself just calls the processor and stores the report:

require_once 'processor.php';

$processor = new Error_Processor();

if (isset($reportData) && is_array($reportData)) {
    $processor->saveReport($reportData);
}

$processor->processReport();

So, but where is the exception.log coming from? That's written when Mage::logException is called:

public static function logException(Exception $e)
{
    if (!self::getConfig()) {
        return;
    }
    $file = self::getStoreConfig('dev/log/exception_file');
    self::log("\n" . $e->__toString(), Zend_Log::ERR, $file);
}

An that static function is manually called in over 100 plcaes over the Magento Core, especially when an exception is catched, should be logged, but not thrown to the top of Mage::init to continue the current process.

  • Thanks so much, especially for the last paragraph. That completely explains what had been confusing me. :) – Louis B. Feb 22 '15 at 19:00

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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