Verwendung von ELMAH zum manuellen Protokollieren von Fehlern

259

Ist es möglich, mit ELMAH Folgendes zu tun?

logger.Log(" something");

Ich mache so etwas:

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

Diese Ausnahme wird von ELMAH nicht automatisch protokolliert, da sie behandelt wurde.

Omu
quelle
1
Zum späteren Nachschlagen habe ich einen Beitrag darüber geschrieben: Fehler programmgesteuert protokollieren . Mein ELMAH-Tutorial enthält auch einige Informationen dazu.
ThomasArdal

Antworten:

412

Direkte Protokollschreibmethode, die seit ELMAH 1.0 funktioniert:

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

ELMAH 1.2 führt eine flexiblere API ein:

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

Es gibt einen Unterschied zwischen den beiden Lösungen:

  • RaiseDie Methode wendet ELMAH-Filterregeln auf die Ausnahme an. LogMethode nicht.
  • Raise ist abonnementbasiert und kann eine Ausnahme bei mehreren Loggern protokollieren.
Andrey Kamaev
quelle
1
Was ist der Unterschied zwischen Ihrer Methode und den anderen?
Omu
3
Diese protokollieren den Fehler in Elmah, ohne dass die Anwendung nicht mehr funktioniert. Sie können damit häufig auftretende Ausnahmen abfangen, sie ordnungsgemäß behandeln und dennoch protokollieren.
PCasagrande
7
Ich habe festgestellt, dass Elmah.ErrorSignal nicht protokolliert wurde, als POST zurück unsicheres HTML für Mvc4 .Net 4.5 enthielt, in meinem Beispiel ein POST zurück von Windows Access Control Services mit einer SignInResponseMessage. Elmah.ErrorLog.GetDefault hat in diesem Szenario funktioniert
Adam
1
Ich hatte das gleiche Problem mit unsicherem HTML. ErrorLog.GetDefault hat den Trick gemacht
hgirish
4
Eine große Einschränkung bei der Verwendung Elmah.ErrorLog.Log(): Wird ausgelöst, falls der Protokollaufruf selbst fehlschlägt, wodurch möglicherweise die gesamte Web-App heruntergefahren wird. Raise()scheitert lautlos. Beispiel: Wenn auf der Serverseite ein Problem mit der Fehlkonfiguration auftritt (z. B. Elmah ist so konfiguriert, dass die Fehler auf der Festplatte gespeichert werden, hat jedoch nicht den richtigen Zugriff auf den Protokollordner), wird die .Log()Methode ausgelöst. (Dies ist jedoch gut zum Debuggen, z. B. warum wird nichts .Raise()protokolliert?)
Cristian Diaconescu
91

Ich würde empfehlen, den Anruf an Elmah in eine eigene einfache Wrapper-Klasse zu packen.

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
        }
    }
}

Rufen Sie es dann einfach auf, wenn Sie einen Fehler protokollieren müssen.

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

Dies hat folgende Vorteile:

  • Sie müssen sich nicht an diese leicht archaische Syntax des Elmah-Aufrufs erinnern
  • Wenn Sie viele DLLs haben, müssen Sie nicht von jeder einzelnen auf Elmah Core verweisen - und dies einfach in Ihre eigene 'System'-DLL einfügen.
  • Wenn Sie jemals eine spezielle Behandlung durchführen müssen oder nur einen Haltepunkt zum Debuggen von Fehlern einfügen möchten, haben Sie alles an einem Ort.
  • Wenn Sie jemals von Elmah wegziehen, können Sie nur einen Ort wechseln.
  • Wenn Sie eine ältere Fehlerprotokollierung haben, die Sie beibehalten möchten (ich habe zufällig einen einfachen Fehlerprotokollierungsmechanismus, der mit einigen Benutzeroberflächen verknüpft ist, für deren Entfernung ich keine sofortige Zeit habe).

Hinweis: Ich habe eine 'contextualMessage'-Eigenschaft für Kontextinformationen hinzugefügt. Sie können dies weglassen, wenn Sie es vorziehen, aber ich finde es sehr nützlich. Elmah packt Ausnahmen automatisch aus, sodass die zugrunde liegende Ausnahme weiterhin im Protokoll gemeldet wird, die Kontextnachricht jedoch angezeigt wird, wenn Sie darauf klicken.

Simon_Weaver
quelle
1
Gute Antwort. Vielleicht sollte ELMAH etwas Ähnliches sofort implementieren. Manchmal ist es wirklich schwierig, einen Fehler ohne Kontext zu debuggen.
ra00l
2
Ich mag alles andere als das Schlucken von sekundären Fehlern mit dem // uh oh! just keep going. Wenn meine Fehlerbehandlung fehlschlägt, möchte ich wissen. Ich möchte, dass es etwas Lärm macht.
Jeremy Cook
3
@JeremyCook Ich stimme zu, aber mit der Einschränkung, dass, wenn Sie nicht vorsichtig sind, fehlgeschlagene Fehlerbehandlungsroutinen dazu neigen, sich selbst aufzurufen und dann in die Luft zu jagen (oh, und ich habe hier auch eine Drittanbieter-API aufgerufen, um den Fehler zu protokollieren). Ich hätte das wahrscheinlich nicht für diese Antwort belassen sollen, aber ich hatte vorher schlechte Erfahrungen mit so etwas gemacht
Simon_Weaver
1
Als Erweiterungsmethode wäre es imho sogar noch besser.
Stephen Kennedy
1
Sie denken vielleicht: Nein, wie viele manuelle Fehler könnte ich möglicherweise versuchen, zu protokollieren? Das dachte ich vor ungefähr einem Jahr. Lange Rede, kurzer Sinn: Verwenden Sie diesen Wrapper!
nmit026
29

Sie können die Elmah.ErrorSignal () -Methode verwenden, um ein Problem zu protokollieren, ohne eine Ausnahme auszulösen.

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

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

Ja, es ist möglich. ELMAH wurde entwickelt, um unbehandelte Ausnahmen abzufangen. Sie können ELMAH jedoch über die ErrorSignal-Klasse eine Ausnahme signalisieren. Diese Ausnahmen werden nicht ausgelöst (sprudeln nicht), sondern nur an ELMAH (und an Abonnenten des Raise-Ereignisses der ErrorSignal-Klasse) gesendet.

Ein kleines Beispiel:

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

Ich wollte dasselbe in einem Thread tun, in dem ich begonnen hatte, E-Mails aus meiner MVC4-Anwendung in die Warteschlange zu stellen. Daher war der HttpContext nicht verfügbar, als eine Ausnahme ausgelöst wurde. Um dies zu tun, habe ich basierend auf dieser Frage und einer anderen Antwort, die hier zu finden ist, Folgendes erhalten: elmah: Ausnahmen ohne HttpContext?

In der Konfigurationsdatei habe ich einen Anwendungsnamen angegeben:

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

Dann können Sie im Code (wie die oben angegebene Antwort, jedoch ohne den HttpContext) anstelle eines HttpContext null übergeben:

ThreadPool.QueueUserWorkItem(t => {
     try {
         ...
         mySmtpClient.Send(message);
     } catch (SomeException e) {
         Elmah.ErrorLog.GetDefault(null).Log(new Elmah.Error(e));
     }
 });
Matthew
quelle
Ich mag deine Lösung; Ich kann "Elmah" jedoch nicht auflösen. in meinem Projekt. Ich habe versucht, "mit Elmah" hinzuzufügen. in meinem Code, aber es existiert nicht in meinem aktuellen Kontext.
Taersious
@Taersious Wie siehst du packages.configaus? Sehen Sie so etwas wie : <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" />'? Haben Sie mit NuGET installiert?
Matthew
Ich möchte ja sagen, aber mein Projekt ist derzeit in der Quellcodeverwaltung gesperrt. Ich habe elmah manuell aus der Beispielkonfigurationsdatei im Projekt implementiert.
Taersious
@Taersious Wenn Sie dies manuell tun, haben Sie den Elmah-Verweis zum Projekt hinzugefügt, bevor Sie die Verwendung aufrufen ... Ich würde erwarten, dass es in beide Richtungen funktioniert, aber ich weiß, dass die obigen Zeilen beim Hinzufügen von nuget zupackages.config
Matthew
3

Manchmal ist es CurrentHttpContextmöglicherweise nicht verfügbar.

Definieren

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 { }
    }
}

Verwenden

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
quelle
2

Ich bin auf ASP.NET Core und verwende ElmahCore .

Um Fehler manuell mit HttpContext (im Controller) zu protokollieren, schreiben Sie einfach:

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

In einem anderen Teil Ihrer Anwendung ohne HttpContext :

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

Ich habe versucht, benutzerdefinierte Nachrichten mit Signal.FromCurrentContext () in elmah-Protokolle zu schreiben. Raise (ex); und festgestellt, dass diese Ausnahmen in die Luft gesprudelt sind, z.

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

Außerdem sehe ich nicht, wie elmah verschiedene Protokollierungsstufen unterstützt - ist es möglich, die ausführliche Protokollierung über eine web.config-Einstellung auszuschalten?

Valery Gavrilov
quelle
1
Wenn Sie eine Ausnahme abfangen und nicht erneut auslösen, treten keine Ausnahmen auf. Vielleicht verstehe ich falsch? ELMAH unterstützt keine unterschiedlichen Protokollierungsstufen. Es ist nur für Fehler.
ThomasArdal
Danke, Thomas. Genau das wollte ich bestätigen
Valery Gavrilov
0

Benutzte diese Linie und es funktioniert einwandfrei.

 try{
            //Code which may throw an error
    }
    catch(Exception ex){
            ErrorLog.GetDefault(HttpContext.Current).Log(new Elmah.Error(ex));
    }
Prajakta Grünkohl
quelle