Jak używać ELMAH do ręcznego rejestrowania błędów

259

Czy można wykonać następujące czynności przy użyciu ELMAH?

logger.Log(" something");

Robię coś takiego:

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

Ten wyjątek nie zostanie automatycznie zarejestrowany przez ELMAH, ponieważ został obsłużony.

Omu
źródło
1
Na przyszłość napisałem post na ten temat: Programowe rejestrowanie błędów . Mój samouczek ELMAH również zawiera pewne informacje na ten temat.
ThomasArdal

Odpowiedzi:

412

Metoda bezpośredniego zapisu dziennika, działająca od ELMAH 1.0:

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

ELMAH 1.2 wprowadza bardziej elastyczny interfejs API:

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

Istnieje różnica między tymi dwoma rozwiązaniami:

  • RaiseMetoda stosuje reguły filtrowania ELMAH do wyjątku. Logmetoda nie.
  • Raise jest oparty na subskrypcji i może zalogować jeden wyjątek do kilku rejestratorów.
Andrey Kamaev
źródło
1
jaka jest różnica między twoją metodą a innymi?
Omu
3
Rejestrują one błąd w Elmah bez powodowania, że ​​aplikacja przestanie działać. Pozwala wychwycić typowe wyjątki, odpowiednio je obsłużyć, ale nadal móc je rejestrować.
PCasagrande,
7
Odkryłem, że Elmah.ErrorSignal nie logował się, gdy powrót POST zawiera niebezpieczny HTML dla Mvc4 .Net 4.5, w moim przykładzie powrót POST z Windows Access Control Services z SignInResponseMessage. Elmah.ErrorLog.GetDefault działał w tym scenariuszu
Adam
1
Miałem ten sam problem z niebezpiecznym HTML-em. ErrorLog.GetDefault załatwił sprawę
hgirish,
4
Jedno duże zastrzeżenie podczas używania Elmah.ErrorLog.Log(): rzuca na wypadek, gdyby samo wywołanie dziennika nie powiodło się, prawdopodobnie powodując uszkodzenie całej aplikacji internetowej. Raise()zawodzi cicho. Na przykład: jeśli wystąpi problem z błędną konfiguracją po stronie serwera (np. Elmah jest skonfigurowany do zapisywania błędów na dysku, ale nie ma prawidłowego dostępu do folderu logów), .Log()metoda wyrzuci. (Jest to przydatne do debugowania, np. Dlaczego nic nie .Raise()loguje?)
Cristian Diaconescu,
91

Poleciłbym zawinięcie połączenia do Elmah w swoją własną prostą klasę opakowania.

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

Następnie wystarczy zadzwonić, gdy trzeba zarejestrować błąd.

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

Ma to następujące zalety:

  • Nie musisz pamiętać tej nieco archaicznej składni wywołania Elmah
  • Jeśli masz wiele bibliotek DLL, nie musisz odwoływać się do Elmah Core z każdego z nich - po prostu umieść to we własnej bibliotece DLL systemu.
  • Jeśli kiedykolwiek potrzebujesz specjalnej obsługi lub po prostu chcesz ustawić punkt przerwania w celu debugowania błędów, masz wszystko w jednym miejscu.
  • Jeśli kiedykolwiek odejdziesz od Elmah, możesz po prostu zmienić jedno miejsce.
  • Jeśli masz starsze rejestrowanie błędów, które chcesz zachować (akurat mam prosty mechanizm rejestrowania błędów związany z niektórymi interfejsami użytkownika, których natychmiast nie mam czasu).

Uwaga: Dodałem właściwość „contextualMessage” dla informacji kontekstowych. Możesz to pominąć, jeśli wolisz, ale uważam to za bardzo przydatne. Elmah automatycznie rozpakowuje wyjątki, więc bazowy wyjątek będzie nadal zgłaszany w dzienniku, ale komunikat kontekstowy będzie widoczny po kliknięciu.

Simon_Weaver
źródło
1
Świetna odpowiedź. Może ELMAH powinien wdrożyć coś podobnego po wyjęciu z pudełka. Czasami naprawdę trudno jest debugować błąd bez kontekstu.
ra00l
2
Lubię połykać wszelkie wtórne błędy za pomocą // uh oh! just keep going. Jeśli moja obsługa błędów kończy się niepowodzeniem, chcę wiedzieć. Chcę, żeby trochę hałasowało.
Jeremy Cook
3
@JeremyCook Zgadzam się, ale z zastrzeżeniem, że jeśli nie jesteś ostrożny, nieudane procedury obsługi błędów zwykle kończą się dzwonieniem, a następnie wysadzaniem w powietrze (och, a ja w rzeczywistości dzwoniłem tutaj do interfejsu API innej firmy, aby zarejestrować błąd). Prawdopodobnie nie powinienem był zostawiać tego w tej odpowiedzi, ale miałem złe doświadczenia z tym, że coś takiego się wydarzyło wcześniej
Simon_Weaver,
1
Byłoby to jeszcze lepsze imho jako metoda rozszerzenia.
Stephen Kennedy,
1
Być może zastanawiasz się: nie, ile błędów ręcznych mógłbym spróbować zarejestrować? Myślałem o tym około rok temu. Krótko mówiąc: użyj tego opakowania!
nmit026
29

Za pomocą metody Elmah.ErrorSignal () można zarejestrować problem bez zgłaszania wyjątku.

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

    // Continue
}
bigtv
źródło
19
catch(Exception ex)
{
    Elmah.ErrorSignal.FromCurrentContext().Raise(ex);
}
Darin Dimitrov
źródło
14

Tak to mozliwe. ELMAH został zaprojektowany do przechwytywania nieobsługiwanych wyjątków. Możesz jednak zasygnalizować wyjątek ELMAH za pośrednictwem klasy ErrorSignal. Te wyjątki nie są zgłaszane (nie wygasają), ale są wysyłane tylko do ELMAH (i do subskrybentów zdarzenia Raise klasy ErrorSignal).

Mały przykład:

protected void ThrowExceptionAndSignalElmah()
{
    ErrorSignal.FromCurrentContext().Raise(new NotSupportedException());
}
Christophe Geers
źródło
13

Chciałem zrobić to samo w wątku, w którym zacząłem umieszczać w kolejce pocztę z poziomu aplikacji MVC4, ponieważ nie miałem dostępnego HttpContext po zgłoszeniu wyjątku. Aby to zrobić, skończyłem z następującymi na podstawie tego pytania i kolejnej odpowiedzi tutaj: elmah: wyjątki bez HttpContext?

W pliku konfiguracyjnym podałem nazwę aplikacji:

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

Następnie w kodzie (jak odpowiedź podana powyżej, ale bez HttpContext) możesz podać null zamiast HttpContext:

ThreadPool.QueueUserWorkItem(t => {
     try {
         ...
         mySmtpClient.Send(message);
     } catch (SomeException e) {
         Elmah.ErrorLog.GetDefault(null).Log(new Elmah.Error(e));
     }
 });
Mateusz
źródło
Podoba mi się twoje rozwiązanie; nie jestem jednak w stanie rozwiązać „Elmah”. w moim projekcie. Próbowałem dodać „za pomocą Elmah;” w moim kodzie, ale nie istnieje w moim bieżącym kontekście.
Taersious
@Taersious Jak packages.configwyglądasz? Czy widzisz coś takiego <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" />':? Czy zainstalowałeś z NuGET?
Matthew
Chciałbym powiedzieć tak, ale mój projekt jest obecnie zablokowany w kontroli źródła. Zaimplementowałem elmah ręcznie z przykładowego pliku konfiguracyjnego w projekcie.
Taersious
@Taersious Jeśli robisz to ręcznie, czy dodałeś odwołanie do Elmah do projektu przed wywołaniem use ... Spodziewałbym się, że zadziała tak czy inaczej, ale wiem, że kiedy nuget doda to, powyższe linie zostaną dodane dopackages.config
Matthew
3

Czasami CurrentHttpContext może nie być dostępna.

Definiować

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

Posługiwać się

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
źródło
2

Jestem na rdzeniu ASP.NET i używam ElmahCore .

Aby ręcznie rejestrować błędy za pomocą HttpContext (w kontrolerze), po prostu napisz:

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

W innej części aplikacji bez HttpContext :

using ElmahCore;
...
ElmahExtensions.RiseError(new Exception("Your Exception"));
A. Morel
źródło
0

Próbowałem zapisywać niestandardowe komunikaty w dziennikach elmah za pomocą Signal.FromCurrentContext (). Raise (ex); i stwierdził, że te wyjątki są propagowane, np .:

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

Poza tym nie widzę, jak elmah obsługuje różne poziomy rejestrowania - czy można wyłączyć pełne rejestrowanie za pomocą ustawienia web.config?

Valery Gavrilov
źródło
1
Jeśli złapiesz wyjątek i nie wyrzucisz go ponownie, wyjątki nie wybuchną. Może źle zrozumiałem? ELMAH nie obsługuje różnych poziomów rejestrowania. To tylko dla błędów.
ThomasArdal,
Dzięki, Thomas. Właśnie to starałem się potwierdzić
Valery Gavrilov
0

Użyłem tej linii i działa idealnie dobrze.

 try{
            //Code which may throw an error
    }
    catch(Exception ex){
            ErrorLog.GetDefault(HttpContext.Current).Log(new Elmah.Error(ex));
    }
Prajakta Kale
źródło