Symfony : envoyer un mail en cas d'erreur

Publié le par greg

Bonjour à tous,

Petite bafouille ce soir, une plus longue viendra, il me faut le temps de l'écrire. Aujourd'hui le sujet est une question qu'on m'a posée il n'y a pas longtemps lors de l'une des mes formations symfony : est il possible d'envoyer un mail lorsqu'une erreur 500 se produit sur le site de production ?

La réponse est non mais oui ... en partie. Je m'explique : il est possible d'attraper les exceptions crées dans symfony et d'envoyer un mail. Mais en aucun cas les erreurs PHP ne peuvent être attrapées ... on ne peut rien faire dans ce cas.

Comment attraper les exceptions dans symfony ?

Très facile, le framework symfony 1.0 est composé de couches appelées filtres. Lors de l'exécution, chacune des requêtes passe au travers des filtres et une fois la réponse calculée, repasse dans l'autre sens. Pour plus de précisions sur ce système de filtres, je vous propose la lecture du livre à ce sujet.

 Il est évidemment possible d'ajouter un filtre dans la pile, comme par exemple un filtre qui attraperait les erreurs des filtres «en dessous» c'est à dire là ou vous auriez placé le code de vos actions et templates, utilisé votre modèle et vos bibliothèques.

Le code du filtre est très simple, il suffit de faire un try catch sur l'exécution de la pile de filtres du «dessous». En cas d'exception, envoyer un mail et propager l'exception pour que symfony s'en occupe. Dans le répertoire lib de votre application, placer un fichier catchErrorFilter.class.php qui contient le code suivant (mis à jour suite à la pertinente remarque  de Niko dans les commentaires ):

<?php

class catchErrorFilter extends sfFilter
{
  public function 
execute ($filterChain)
  {
      
// Execute next filter in the chain
    
try
    {
      
$filterChain->execute();
    }
    
// Si l'exception est due a un redirect
    // ne pas envoyer de notification
    
catch (sfStopException $e)
    {
      throw 
$e
# propager l'exception
    
}
    
// Toute autre exception est reportee
    
catch (Exception $e)
    {
      
// envoyer un mail ici

      
throw $e# propager l'
exception
    }
  }
}


Reste à configurer symfony pour enregistrer votre nouveau filtre et le placer dans la pile des filtres. Le fichier filters.yml dans le répertoire de configuration de votre application est fait pour cela, il devrait ressembler à cela :

rendering: ~
security:  ~

# insert your own filters here

catch_error:
  class: catchErrorFilter
  param:
    condition: %APP_CATCH_ERRORS%

cache:     ~
common:    ~
execution: ~


On enregistre le filtre et on demande à symfony de ne l'exécuter qu'à condition de que la variable de configuration «APP_CATCH_ERROR» soit vraie. Cela va nous permettre de n'utiliser ce filtre qu'en environnement de production et éviter ainsi de recevoir des mails lors des erreurs (plus fréquentes) sur les environnements de développement. Il convient dons de placer cette directive dans le fichier de conf app.yml :

all:
  catch_errors: off

prod:
  catch_errors: on


Voila, le tour est joué ...

Publicité

Publié dans symfony

Pour être informé des derniers articles, inscrivez vous :
Commenter cet article
B
<br /> Super astuce !<br /> Petite correction : La condition doit être un booléen, donc il faut mettre :<br /> <br /> all:<br />   catch_errors: false<br /> <br /> prod:<br />   catch_errors: true<br /> <br /> <br />
Répondre
G
<br /> Ah ... on voit les utilisateurs de sf 1.4 ;)<br /> <br /> <br />
J
<br /> Pour l'envoie de mail je propose cette methode à votre classe (faite à partir du tuto jobeet) :<br /> <br />   public function sendMail(Exception $e)<br />   {<br />         ProjectConfiguration::registerZend();<br />         $mail = new Zend_Mail('UTF-8');<br />         $mail->setSubject('Exception : '.$e->getMessage());<br />         $mail->setBodyText($e);<br />         $mail->setFrom('contact@yoursite.com', 'Your site');<br />         $mail->addTo('you@mail.com');<br />         $mail->send();<br />   }<br /> <br /> De sorte à avoir quelques infos pour résoudre le bug à défaut d'avoir la page complette dans le mail avec les éléments dépliable (c'est possible ?)<br /> <br /> Ca récupère bien les exeptions sauf celles du genre<br /> <br /> Action "module/action" does not exist.<br /> <br /> Merci.<br /> <br /> <br />
Répondre
S
Merci beaucoup.Je le teste dès que possible. Des possibilités de traitement autres que le mail sont surement possibles. Je m'en vais tester tout ca.Je suppose que c'est toujours valable sur Symfony 1.2 ?
Répondre
G
<br /> Oui, il est possible de faire mieux avec sf1.2 en utilisant le système d'évènements.<br /> Quoiqu'il en soit, attention au flood, implémentez un algo du genre seau à jetons pour éviter d'écrouler votre serveur mail ou de base de données en cas de gros plantage...<br /> <br /> <br />
N
Quick fix:<br /> try{  $filterChain->execute();}catch (sfStopException $e){  throw $e;}catch (Exception $e){  // Send mail here  throw $e;  }<br />
Répondre
G
<br /> adjugé !<br /> <br /> <br />
N
Attention parceque là tu catches TOUTES les exceptions, y compris les sfStopException qui sont utilisées à chaque redirect... Tu risques de te faire spammer :)
Répondre
G
<br /> yeay ... il faut tester un is_a('sfStopException'), la question est : les sfStopException ne sont elles pas utilisées ailleurs que pour les redirect ?<br /> <br /> Je m'en va tester cela tient ...<br /> <br /> <br />