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.