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.