Comment utiliser ELMAH pour enregistrer manuellement les erreurs

259

Est-il possible de faire ce qui suit en utilisant ELMAH?

logger.Log(" something");

Je fais quelque chose comme ça:

try 
{
    // Code that might throw an exception 
}
catch(Exception ex)
{
    // I need to log error here...
}

Cette exception ne sera pas enregistrée automatiquement par ELMAH, car elle a été gérée.

Omu
la source
1
Pour référence future, j'ai écrit un article à ce sujet: Journalisation des erreurs par programme . Mon tutoriel ELMAH contient également des informations à ce sujet.
ThomasArdal

Réponses:

412

Méthode d'écriture directe des journaux, fonctionnant depuis ELMAH 1.0:

try 
{
    some code 
}
catch(Exception ex)
{
    Elmah.ErrorLog.GetDefault(HttpContext.Current).Log(new Elmah.Error(ex));
}

ELMAH 1.2 introduit une API plus flexible:

try 
{
    some code 
}
catch(Exception ex)
{
    Elmah.ErrorSignal.FromCurrentContext().Raise(ex);
}

Il y a une différence entre les deux solutions:

  • RaiseLa méthode applique les règles de filtrage ELMAH à l'exception. Logpas.
  • Raise est basé sur un abonnement et peut enregistrer une exception dans les différents enregistreurs.
Andrey Kamaev
la source
1
quelle est la différence entre votre méthode et les autres?
Omu
3
Ceux-ci enregistrent l'erreur dans Elmah sans provoquer l'arrêt de l'application. Il vous permet de détecter les exceptions courantes, de les gérer correctement, mais de pouvoir les enregistrer.
PCasagrande
7
J'ai trouvé qu'Elmah.ErrorSignal ne se connectait pas lorsque le retour POST contient du code HTML non sécurisé pour Mvc4 .Net 4.5, dans mon exemple un retour POST des services de contrôle d'accès Windows avec un SignInResponseMessage. Elmah.ErrorLog.GetDefault a fonctionné dans ce scénario
Adam
1
J'ai eu le même problème avec Html dangereux. ErrorLog.GetDefault a fait l'affaire
hgirish
4
Une grosse mise en garde lors de l'utilisation Elmah.ErrorLog.Log(): elle lève en cas d'échec de l'appel de journal, ce qui peut éventuellement entraîner la fermeture de l'ensemble de l'application Web. Raise()échoue silencieusement. Par exemple: s'il y a un problème de mauvaise configuration côté serveur (par exemple, Elmah est configuré pour enregistrer les erreurs sur le disque, mais n'a pas l'accès correct au dossier logs), la .Log()méthode lancera. (C'est bien pour le débogage, par exemple, pourquoi ne .Raise()consigne-t-il rien?)
Cristian Diaconescu
91

Je recommanderais d'encapsuler l'appel à Elmah dans une simple classe wrapper.

using Elmah;

public static class ErrorLog
{
    /// <summary>
    /// Log error to Elmah
    /// </summary>
    public static void LogError(Exception ex, string contextualMessage=null)
    {
        try
        {
            // log error to Elmah
            if (contextualMessage != null) 
            {
                // log exception with contextual information that's visible when 
                // clicking on the error in the Elmah log
                var annotatedException = new Exception(contextualMessage, ex); 
                ErrorSignal.FromCurrentContext().Raise(annotatedException, HttpContext.Current);
            }
            else 
            {
                ErrorSignal.FromCurrentContext().Raise(ex, HttpContext.Current);
            }

            // send errors to ErrorWS (my own legacy service)
            // using (ErrorWSSoapClient client = new ErrorWSSoapClient())
            // {
            //    client.LogErrors(...);
            // }
        }
        catch (Exception)
        {
            // uh oh! just keep going
        }
    }
}

Il suffit ensuite de l'appeler chaque fois que vous devez enregistrer une erreur.

try {
   ...
} 
catch (Exception ex) 
{
    // log this and continue
    ErrorLog.LogError(ex, "Error sending email for order " + orderID);
}

Cela présente les avantages suivants:

  • Vous n'avez pas besoin de vous souvenir de cette syntaxe légèrement archaïque de l'appel Elmah
  • Si vous avez de nombreuses DLL, vous n'avez pas besoin de référencer Elmah Core à partir de chacune d'entre elles - et placez-les simplement dans votre propre DLL «Système».
  • Si jamais vous avez besoin de faire une manipulation spéciale ou si vous voulez simplement mettre un point d'arrêt pour déboguer les erreurs, vous avez tout à un endroit.
  • Si jamais vous vous éloignez d'Elmah, vous ne pouvez changer qu'un seul endroit.
  • Si vous avez une journalisation des erreurs héritée que vous souhaitez conserver (il se trouve que j'ai un mécanisme de journalisation des erreurs simple qui est lié à certaines interfaces utilisateur que je n'ai pas immédiatement le temps de supprimer).

Remarque: J'ai ajouté une propriété «contextualMessage» pour les informations contextuelles. Vous pouvez omettre cela si vous préférez mais je le trouve très utile. Elmah déballe automatiquement les exceptions afin que l'exception sous-jacente soit toujours signalée dans le journal mais le contextualMessage sera visible lorsque vous cliquez dessus.

Simon_Weaver
la source
1
Très bonne réponse. ELMAH devrait peut-être implémenter quelque chose de similaire dès le départ. Il est parfois très difficile de déboguer une erreur sans contexte.
ra00l
2
J'aime tout sauf avaler les erreurs secondaires avec le // uh oh! just keep going. Si ma gestion des erreurs échoue, je veux savoir. Je veux que ça fasse du bruit.
Jeremy Cook
3
@JeremyCook Je suis d'accord, mais avec la mise en garde que si vous n'êtes pas prudent, les routines de gestion des erreurs ont tendance à finir par s'appeler puis exploser (oh et j'appelais également une API tierce ici pour enregistrer l'erreur). Je n'aurais probablement pas dû laisser cela dans cette réponse, mais j'avais eu de mauvaises expériences avec une telle chose avant
Simon_Weaver
1
Ce serait encore mieux à mon humble avis comme méthode d'extension.
Stephen Kennedy
1
Vous pensez peut-être: non, combien d'erreurs manuelles puis-je essayer de consigner? Je pensais cela, il y a environ un an. Pour faire court: utilisez cet emballage!
nmit026
29

Vous pouvez utiliser la méthode Elmah.ErrorSignal () pour consigner un problème sans déclencher une exception.

try
{
    // Some code
}
catch(Exception ex)
{
    // Log error
    Elmah.ErrorSignal.FromCurrentContext().Raise(ex);

    // Continue
}
bigtv
la source
19
catch(Exception ex)
{
    Elmah.ErrorSignal.FromCurrentContext().Raise(ex);
}
Darin Dimitrov
la source
14

Oui c'est possible. ELMAH a été conçu pour intercepter les exceptions non gérées. Cependant, vous pouvez signaler une exception à ELMAH via la classe ErrorSignal. Ces exceptions ne sont pas levées (ne bouillonnent pas), mais sont uniquement envoyées à ELMAH (et aux abonnés de l'événement Raise de la classe ErrorSignal).

Un petit exemple:

protected void ThrowExceptionAndSignalElmah()
{
    ErrorSignal.FromCurrentContext().Raise(new NotSupportedException());
}
Christophe Geers
la source
13

Je cherchais à faire la même chose dans un thread que j'avais commencé à mettre en file d'attente du courrier à partir de mon application MVC4, en tant que tel, je n'avais pas le HttpContext disponible lorsqu'une exception était levée. Pour ce faire, je me suis retrouvé avec ce qui suit sur la base de cette question et une autre réponse trouvée ici: elmah: exceptions sans HttpContext?

Dans le fichier de configuration, j'ai spécifié un nom d'application:

<elmah>
    <security allowRemoteAccess="false" />
    <errorLog type="Elmah.SqlErrorLog, Elmah" connectionStringName="ELMAH" applicationName="myApplication"/>   
</elmah>

Ensuite, dans le code (comme la réponse fournie ci-dessus, mais sans HttpContext), vous pouvez passer null au lieu d'un HttpContext:

ThreadPool.QueueUserWorkItem(t => {
     try {
         ...
         mySmtpClient.Send(message);
     } catch (SomeException e) {
         Elmah.ErrorLog.GetDefault(null).Log(new Elmah.Error(e));
     }
 });
Matthieu
la source
J'aime votre solution; cependant, je suis incapable de résoudre "Elmah". dans mon projet. J'ai essayé d'ajouter "en utilisant Elmah;" dans mon code, mais il n'existe pas dans mon contexte actuel.
Taersious
@Taersious À quoi ressemble votre packages.configapparence? Voyez-vous quelque chose comme <package id="elmah" version="1.2.2" targetFramework="net45" /> <package id="elmah.corelibrary" version="1.2.2" targetFramework="net45" /> <package id="elmah.sqlserver" version="1.2" targetFramework="net45" />':? Avez-vous installé avec NuGET?
Matthew
Je voudrais dire oui, mais mon projet est actuellement verrouillé en contrôle de source. J'ai implémenté elmah manuellement à partir d'un exemple de fichier de configuration dans le projet.
Taersious
@Taersious Si vous le faites manuellement, avez-vous ajouté la référence Elmah au projet avant d'invoquer l'utilisation ... Je m'attendrais à ce que cela fonctionne dans les deux sens, mais je sais que lorsque Nuget l'ajoute, les lignes ci-dessus s'ajoutent aupackages.config
Matthew
3

Parfois, ils CurrentHttpContextpeuvent ne pas être disponibles.

Définir

public class ElmahLogger : ILogger
{
    public void LogError(Exception ex, string contextualMessage = null, bool withinHttpContext = true)
    {
        try
        {
            var exc = contextualMessage == null 
                      ? ex 
                      : new ContextualElmahException(contextualMessage, ex);
            if (withinHttpContext)
                ErrorSignal.FromCurrentContext().Raise(exc);
            else
                ErrorLog.GetDefault(null).Log(new Error(exc));
        }
        catch { }
    }
}

Utilisation

public class MyClass
{
    readonly ILogger _logger;

    public MyClass(ILogger logger)
    {
        _logger = logger;
    }

    public void MethodOne()
    {
        try
        {

        }
        catch (Exception ex)
        {
            _logger.LogError(ex, withinHttpContext: false);
        }
    }
}
tchelidze
la source
2

Je suis sur le noyau ASP.NET et j'utilise ElmahCore .

Pour enregistrer manuellement les erreurs avec HttpContext (dans le contrôleur), écrivez simplement:

using ElmahCore;
...
HttpContext.RiseError(new Exception("Your Exception"));

Dans une autre partie de votre application sans HttpContext :

using ElmahCore;
...
ElmahExtensions.RiseError(new Exception("Your Exception"));
A. Morel
la source
0

J'essayais d'écrire des messages personnalisés dans les journaux Elmah en utilisant Signal.FromCurrentContext (). Raise (ex); et a constaté que ces exceptions se multiplient, par exemple:

try
{
    ...
}
catch (Exception ex)
{
    Elmah.ErrorSignal.FromCurrentContext().Raise(ex);
    // this will write to the log AND throw the exception
}

De plus, je ne vois pas comment elmah prend en charge différents niveaux de journalisation - est-il possible de désactiver la journalisation détaillée par un paramètre web.config?

Valery Gavrilov
la source
1
Si vous attrapez une exception et ne la relancez pas, les exceptions ne bouillonnent pas. Peut-être que je me méprends? ELMAH ne prend pas en charge différents niveaux de journalisation. C'est uniquement pour les erreurs.
ThomasArdal
Merci, Thomas. C'est exactement ce que j'essayais de confirmer
Valery Gavrilov
0

Utilisé cette ligne et cela fonctionne parfaitement bien.

 try{
            //Code which may throw an error
    }
    catch(Exception ex){
            ErrorLog.GetDefault(HttpContext.Current).Log(new Elmah.Error(ex));
    }
Prajakta Kale
la source