ELMAH: Fallback ErrorLog

Ce court article présente une extension à ELMAH pour le support d’ErrorLogs composites.


Pour une introduction sur ELMAH, c’est par ici.

Dans sa version actuelle (1.2.2), ELMAH permet de définir un seul ErrorLog. À ma connaissance, il n’existait pas d’extension pour traiter ce cas jusqu’à présent. Celui-ci me paraît pourtant intéressant, en particulier quand on utilise SqlErrorLog comme principal handler: en cas de problème de connexion avec la base de données (défaillance réseau, problème serveur, etc.), il est souhaitable d’enregistrer les erreurs dans un autre emplacement, disons XmlFileErrorLog. Et quand bien même l’écriture sur fichier échouerait, on souhaiterait logiquement enregistrer les erreurs dans MemoryErrorLog en dernier recours… L’échec d’écriture sur fichier paraît improbable, mais ce n’est pas si improbable selon la configuration du serveur (écriture en dehors du répertoire du site web, problème d’écriture sur un partage réseau, problème d’espace disque, etc.). Le fait d’enregistrer les erreurs dans MemoryErrorLog en dernier recours permet de se laisser une chance pour retrouver facilement une erreur récente (en cas de recyclage, ces traces sont perdues).

J’ai lu plusieurs pages sur Internet qui faisaient mention de la fonctionnalité de reporting par SMTP d’ELMAH (via la section de configuration errorMail) comme alternative à une réelle fonctionnalité de fallback. D’expérience, je considère que la dépendance directe d’un site web à un client SMTP est tout sauf fiable.

Exemple pratique

Voici un exemple de configuration typique pour ELMAH:


<configuration>
  <configSections>
    <sectionGroup name="elmah">
      <section name="security" requirePermission="false" type="Elmah.SecuritySectionHandler, Elmah" />
      <section name="errorLog" requirePermission="false" type="Elmah.ErrorLogSectionHandler, Elmah" />
      <section name="errorMail" requirePermission="false" type="Elmah.ErrorMailSectionHandler, Elmah" />
      <section name="errorFilter" requirePermission="false" type="Elmah.ErrorFilterSectionHandler, Elmah" />
    </sectionGroup>
  </configSections>
  <elmah>
    <errorLog type="Elmah.SqlErrorLog, Elmah" connectionStringName="DB_ELMAH"  applicationName="Blog" >
  </elmah>
</configuration>

Voici un nouvel exemple qui utilise l’extension Elmah.FallbackErrorLog:


<configuration>
  <configSections>
    <sectionGroup name="elmah">
      <section name="security" requirePermission="false" type="Elmah.SecuritySectionHandler, Elmah" />
      <section name="errorLog" requirePermission="false" type="Elmah.FallbackErrorLogSectionHandler, Elmah.FallbackErrorLog" />
      <section name="errorMail" requirePermission="false" type="Elmah.ErrorMailSectionHandler, Elmah" />
      <section name="errorFilter" requirePermission="false" type="Elmah.ErrorFilterSectionHandler, Elmah" />
    </sectionGroup>
  </configSections>
  <elmah>
    <errorLog type="Elmah.FallbackErrorLog, Elmah.FallbackErrorLog" >
        <add type="Elmah.SqlErrorLog, Elmah" connectionStringName="DB_ELMAH"  applicationName="Blog" />
        <add type="Elmah.XmlFileErrorLog, Elmah" logPath="~/App_Data/Logs" />
        <add type="Elmah.MemoryErrorLog, Elmah" size="30" />
    </errorLog>
  </elmah>
</configuration>

Pour utiliser cette configuration, il suffit d’installer le package Elmah.FallbackErrorLog.

Détails d’implémentation

L’extension contient principalement deux classes:

  • FallbackErrorLogSectionHandler
  • et FallbackErrorLog.

La première prend en charge les noeuds enfants dans la section de configuration errorLog. La seconde implémente la logique de fallback à partir d’une liste de traceurs.

FallbackErrorLogSectionHandler

La section errorLog peut contenir des noeuds enfants (limités au tag add). Noter que cette classe est compatible avec une section errorLog sans enfant (ce qui n’a pas vraiment d’intérêt me semble-t-il, mais c’est gratuit 🙂 ).

La chose éventuellement intéressante est que l’on n’est pas limité à l’usage de la classe FallbackErrorLog puisque celle-ci est référencée par son type dans la section errorLog. S’il y a un intérêt à implémenter un nouveau traceur composite, il suffit d’étendre cette classe (ou pas) et de référencer le nouveau type.

Dernière remarque: les éléments add ne peuvent pas avoir d’enfants.

FallbackErrorLog

Il s’agit d’une implémentation très simple de la classe abstraite ErrorLog. Son constructeur accepte un argument IDictionary un peu particulier contenant d’autres IDictionary (les paramètres de chaque ErrorLog sous-jacent).
La seule partie un peu subtile est dans la méthode GetErrors qui doit fusionner les traces de plusieurs fournisseurs en fonction de leur date d’enregistrement.

Le code source est sur Github.