Protokollierungsfehler in ASP.NET MVC

109

Ich verwende derzeit log4net in meiner ASP.NET MVC-Anwendung, um Ausnahmen zu protokollieren. Ich mache das so, indem ich alle meine Controller von einer BaseController-Klasse erben lasse. Im OnActionExecuting-Ereignis des BaseControllers protokolliere ich alle Ausnahmen, die möglicherweise aufgetreten sind:

protected override void OnActionExecuted(ActionExecutedContext filterContext)
{
    // Log any exceptions
    ILog log = LogManager.GetLogger(filterContext.Controller.GetType());

    if (filterContext.Exception != null)
    {
        log.Error("Unhandled exception: " + filterContext.Exception.Message +
            ". Stack trace: " + filterContext.Exception.StackTrace, 
            filterContext.Exception);
    }
}

Dies funktioniert hervorragend, wenn während einer Controller-Aktion eine nicht behandelte Ausnahme aufgetreten ist.

Für 404-Fehler habe ich einen benutzerdefinierten Fehler in meiner web.config wie folgt eingerichtet:

<customErrors mode="On">
    <error statusCode="404" redirect="~/page-not-found"/>
</customErrors>

Und in der Controller-Aktion, die die URL "Seite nicht gefunden" verarbeitet, protokolliere ich die angeforderte Original-URL:

[AcceptVerbs(HttpVerbs.Get)]
public ActionResult PageNotFound()
{
    log.Warn("404 page not found - " + Utils.SafeString(Request.QueryString["aspxerrorpath"]));

    return View();
}

Und das funktioniert auch.

Das Problem, das ich habe, ist, wie Fehler protokolliert werden, die sich auf den ASPX-Seiten selbst befinden. Angenommen, ich habe einen Kompilierungsfehler auf einer der Seiten oder einen Inline-Code, der eine Ausnahme auslöst:

<% ThisIsNotAValidFunction(); %>
<% throw new Exception("help!"); %>

Es scheint, dass das HandleError-Attribut dies korrekt auf meine Error.aspx-Seite im freigegebenen Ordner umleitet, aber es wird definitiv nicht von der OnActionExecuted-Methode meines BaseControllers abgefangen. Ich dachte, ich könnte den Protokollierungscode vielleicht auf der Error.aspx-Seite selbst platzieren, bin mir aber nicht sicher, wie ich die Fehlerinformationen auf dieser Ebene abrufen soll.

Kevin Pang
quelle
+1 für ELMAH. Hier ist ein ELMAH-Tutorial, das ich geschrieben habe, um Ihnen den Einstieg zu erleichtern . Denken Sie auch daran, das Elmah.MVC- Paket zu verwenden, wenn Sie ASP.NET MVC verwenden, um Probleme mit benutzerdefinierten Fehlerseiten usw. zu vermeiden.
ThomasArdal
Es gibt einige Produkte, die alle in .NET-Apps auftretenden Fehler protokollieren. Sie sind nicht so niedrig wie ELMAH oder log4net, aber Sie sparen eine Menge Zeit, wenn Sie nur versuchen, Fehler zu überwachen und zu diagnostizieren: Bugsnag und AirBrake sind zwei davon, die ich kenne .NET
Don P

Antworten:

103

Ich würde in Betracht ziehen, Ihre Webanwendung durch Einstecken von Elmah zu vereinfachen .

Sie fügen Ihrem Projekt die Elmah-Assembly hinzu und konfigurieren dann Ihre web.config. Anschließend werden Ausnahmen protokolliert, die auf Controller- oder Seitenebene erstellt wurden. Es kann so konfiguriert werden, dass es sich an verschiedenen Orten (wie SQL Server, E-Mail usw.) anmeldet. Es bietet auch ein Web-Frontend, mit dem Sie das Protokoll der Ausnahmen durchsuchen können.

Es ist das erste, was ich zu einer von mir erstellten asp.net mvc-App hinzufüge.

Ich benutze immer noch log4net, aber ich neige dazu, es zum Protokollieren von Debug / Info zu verwenden und überlasse alle Ausnahmen Elmah.

Weitere Informationen finden Sie auch in der Frage Wie protokollieren Sie Fehler (Ausnahmen) in Ihren ASP.NET-Apps? .

Andrew Rimmer
quelle
3
Ich habe vor kurzem angefangen, Elmah zu verwenden, und es ist einer der einfachsten und einfachsten Ausnahmeprotokollierer, die ich je verwendet habe. Ich habe einen Beitrag gelesen, der besagt, dass MS ihn in ASP.net aufnehmen sollte, und ich stimme zu.
dtc
14
Warum ich sowohl ELMAH als auch log4net für die App brauche. Protokollierung? Warum nicht eine einzige Lösung?
VJAI
Funktioniert dies auch, wenn ich eine n-Tier-Architektur habe? Controller - Services - Repositories?
a.farkas2508
2
ELMAH ist überbewertet.
Ronnie Overby
Ist ELMAH kostenlos?
Dallas
38

Sie können sich in das OnError-Ereignis in Global.asax einbinden.

Etwas wie das:

/// <summary>
/// Handles the Error event of the Application control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
protected void Application_Error(object sender, EventArgs e)
{
    if (Server != null)
    {
        Exception ex = Server.GetLastError();

        if (Response.StatusCode != 404 )
        {
            Logging.Error("Caught in Global.asax", ex);
        }

    }


}
Chuck Conway
quelle
3
Dies sollte alle Ausnahmen erfassen. Ich halte dies für die beste Vorgehensweise.
Andrei Rînea
4
Laut der Wertanalyse von ReSharper Serverwird immer ungleich Null sein.
Drew Noakes
6
Das Ignorieren von 404 hat bei mir nicht so funktioniert, wie Sie es geschrieben haben. Ich schriebif (ex is HttpException && ((HttpException)ex).GetHttpCode() == 404) return;
Pauloya
21

MVC3-
Attribut erstellen, das von HandleErrorInfoAttribute erbt und die Protokollierung Ihrer Wahl enthält

public class ErrorLoggerAttribute : HandleErrorAttribute 
{
    public override void OnException(ExceptionContext filterContext)
    {
        LogError(filterContext);
        base.OnException(filterContext);
    }

    public void LogError(ExceptionContext filterContext)
    {
       // You could use any logging approach here

        StringBuilder builder = new StringBuilder();
        builder
            .AppendLine("----------")
            .AppendLine(DateTime.Now.ToString())
            .AppendFormat("Source:\t{0}", filterContext.Exception.Source)
            .AppendLine()
            .AppendFormat("Target:\t{0}", filterContext.Exception.TargetSite)
            .AppendLine()
            .AppendFormat("Type:\t{0}", filterContext.Exception.GetType().Name)
            .AppendLine()
            .AppendFormat("Message:\t{0}", filterContext.Exception.Message)
            .AppendLine()
            .AppendFormat("Stack:\t{0}", filterContext.Exception.StackTrace)
            .AppendLine();

        string filePath = filterContext.HttpContext.Server.MapPath("~/App_Data/Error.log");

        using(StreamWriter writer = File.AppendText(filePath))
        {
            writer.Write(builder.ToString());
            writer.Flush();
        }
    }

Platzieren Sie das Attribut in Global.asax RegisterGlobalFilters

    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
       // filters.Add(new HandleErrorAttribute());
        filters.Add(new ErrorLoggerAttribute());
    }
Kennzeichen
quelle
1

Haben Sie darüber nachgedacht, das HandleError-Attribut zu erweitern? Auch Scott hat eine gute Blog - Post über Filter Abfangjäger auf Controller / Aktionen hier .

Kieron
quelle
1

Die Ansicht Error.aspx ist wie folgt definiert:

namespace MvcApplication1.Views.Shared
{
    public partial class Error : ViewPage<HandleErrorInfo>
    {
    }
}

Die HandleErrorInfo verfügt über drei Eigenschaften: Zeichenfolge ActionName Zeichenfolge ControllerName Exception Exception

Sie sollten in der Ansicht auf HandleErrorInfo und damit auf die Ausnahme zugreifen können.

Praveen Angyan
quelle
0

Sie können versuchen, HttpContext.Error zu untersuchen, aber ich bin mir nicht sicher.

Mike Chaliy
quelle