Objectif
Que celui qui n’a pas perdu son temps à comprendre et reproduire un problème survenu sur une application en production me jette la première pierre !
Dans le contexte d’une application MVC basée sur le Zend Framework (architecture identique à celle du Quickstart de la version 1.9.4), voyons comment configurer son contrôleur d’erreurs pour journaliser les erreurs applicatives dans un fichier de log.
Environnement applicatif et configuration Apache
Il est de bon ton de définir dans le .htaccess de /monprojet/public ou dans le virtual host Apache (quand on a la main dessus), la constante de l’environnement de l’application :
SetEnv APPLICATION_ENV development ...
Ceci permet de changer simplement la configuration selon l’environnement d’exécution (ici seulement développement et production).
Cette constante est ensuite récupérée dans /monprojet/public/index.php :
defined('APPLICATION_ENV') || define('APPLICATION_ENV', (getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV') : 'production'));
Configurer le logger
Définir les options de journalisation dans le fichier /monprojet/application/configs/application.ini :
[production] ... logging.enabled = 1 logging.level = 3 logging.filename = /tmp/exploit.log [development : production] ... logging.level = 7
Les niveaux de log par défaut sont les suivants, ici nous journaliserons donc les informations de niveau ERR, CRIT, ALERT, EMERG sur la production, et tous les niveaux sur l’environnement de dev :
EMERG = 0; // Emergency: system is unusable ALERT = 1; // Alert: action must be taken immediately CRIT = 2; // Critical: critical conditions ERR = 3; // Error: error conditions WARN = 4; // Warning: warning conditions NOTICE = 5; // Notice: normal but significant condition INFO = 6; // Informational: informational messages DEBUG = 7; // Debug: debug messages
Reste à configurer le logger dans le bootstrap (/monprojet/application/Bootstrap.php) pour qu’il prenne en compte les options :
protected function _initLogging() { $logger = new Zend_Log(); // récupérer et filtrer sur le niveau de log $optionLevel = (int) $this->_options["logging"]["level"]; $filter = new Zend_Log_Filter_Priority($optionLevel); $logger->addFilter($filter); // ajouter un rédacteur qui écrit dans le fichier défini $optionPath = $this->_options["logging"]["filename"]; $writer = new Zend_Log_Writer_Stream($optionPath); $logger->addWriter($writer); Zend_Registry::set("logger", $logger); }
Personnaliser notre ErrorController
On complète juste l’action du QuickStart :
public function errorAction() { $this->_helper->layout->setLayout('layouts/site'); $errors = $this->_getParam('error_handler'); switch ($errors->type) { case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_CONTROLLER: case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ACTION: // 404 error -- controller or action not found $this->getResponse()->setHttpResponseCode(404); $this->view->message = 'Page not found'; break; default: // application error $this->getResponse()->setHttpResponseCode(500); $this->view->message = 'Application error'; // logging $logger = Zend_Registry::get("logger"); // logger le type d'exception et sa trace $logger->err($errors->exception->getMessage()); $logger->err($errors->exception->getTraceAsString()); // rediriger la sortie var_dump dans le fichier de log ob_start(); var_export($errors->request->getParams()); $formatedParams = ob_get_contents(); ob_end_clean(); $logger->err($formatedParams); break; } $this->view->exception = $errors->exception; $this->view->request = $errors->request; }
Provoquer une erreur pour tester
Pour se faire, il suffit de lever une exception dans l’action index du contrôleur index, puis afficher l’accueil de l’application :
public function indexAction() { // ... throw new Exception('Division by zero.'); }
Le fichier de /tmp/exploit.log contient désormais des informations permettant de reproduire l’anomalie que l’utilisateur aura rencontré :
2009-12-03T22:37:38+01:00 ERR (3): Division by zero.
2009-12-03T22:37:38+01:00 ERR (3): #0 /usr/share/php/Zend/Controller/Action.php(513): IndexController->indexAction()
#1 /usr/share/php/Zend/Controller/Dispatcher/Standard.php(289): Zend_Controller_Action->dispatch('indexAction')
#2 /usr/share/php/Zend/Controller/Front.php(946): Zend_Controller_Dispatcher_Standard->dispatch(Object(Zend_Controller_Request_Http), Object(Zend_Controller_Response_Http))
#3 /usr/share/php/Zend/Application/Bootstrap/Bootstrap.php(77): Zend_Controller_Front->dispatch()
#4 /usr/share/php/Zend/Application.php(358): Zend_Application_Bootstrap_Bootstrap->run()
#5 /var/www/monprojet/public/index.php(26): Zend_Application->run()
#6 {main}
2009-12-03T22:37:38+01:00 ERR (3): array (
'controller' => 'index',
'action' => 'index',
'module' => 'default',
)Conclusion
Malgré un développement soigné et des tonnes de tests unitaires et fonctionnels, l’utilisateur final se débrouillera toujours pour tomber, loi de Murphy oblige, sur un nouveau bug.
L’exploitation des logs permet de s’en rendre compte et de prendre les mesures qui s’imposent.
Il est également possible d’écrire ses logs en base de données et pourquoi pas de créer un petit module pour pouvoir les consulter et les classer par fréquence.
L’envoi par e-mail des erreurs critiques est aussi une bonne alternative, difficile de faire abstraction de ce genre de spam.
Magento
Joomla!
Zend Fr.
Ubuntu



![Validate my RSS feed [Valid RSS]](/wp-content/themes/libre-a-vous/images/rss-valid.png)