2009-02-20 4 views
97

Ich verwende derzeit log4net in meiner ASP.NET MVC-Anwendung, um Ausnahmen zu protokollieren. Die Art, wie ich das mache, besteht darin, dass alle meine Controller von einer BaseController-Klasse erben. In der OnActionExecuting Veranstaltung Base, log ich alle Ausnahmen, die aufgetreten sind:Protokollierungsfehler in ASP.NET MVC

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 gut, wenn eine nicht behandelte Ausnahme während einer Controller-Aktion aufgetreten.

Wie für 404-Fehler, ich habe einen benutzerdefinierten Fehler wie so in meinem web.config einrichten:

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

Und in der Controller-Aktion, die den "Seite-not-found" url Griffe, ich lüge Die ursprüngliche URL wird angefordert:

[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 auf den ASPX-Seiten selbst sind. Lassen Sie uns sagen, dass ich einen Kompilierungsfehler haben auf einer der Seiten oder einem Inline-Code, der eine Ausnahme werfen:

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

Es das richtig das Handle Attribut erscheint, wird Umleiten diese auf meine Error.aspx Seite im freigegebenen Ordner, aber es wird definitiv nicht von der OnActionExecuted-Methode meines BaseControllers abgefangen. Ich dachte, ich könnte vielleicht den Logging-Code auf der Error.aspx-Seite selbst setzen, aber ich bin mir nicht sicher, wie die Fehlerinformationen auf dieser Ebene abgerufen werden.

+0

+1 für ELMAH. Hier ist ein [ELMAH Tutorial] (http://blog.elmah.io/elmah-tutorial/), das ich geschrieben habe, um Ihnen den Einstieg zu erleichtern. Denken Sie auch daran, das Paket [Elmah.MVC] (https://www.nuget.org/packages/Elmah.MVC/) zu verwenden, wenn Sie ASP.NET MVC verwenden, um Probleme mit benutzerdefinierten Fehlerseiten usw. zu vermeiden. – ThomasArdal

+0

Theres ein paar Produkte Dort werden alle Fehler protokolliert, die in .NET-Anwendungen auftreten. Sie sind nicht so niedrig wie ELMAH oder log4net, aber sparen Sie eine Menge Zeit, wenn Sie nur versuchen, Fehler zu überwachen und zu diagnostizieren: [Bugsnag] (https://docs.bugsnag.com/platforms/dotnet/ asp-net /) und [AirBrake] (https://airbrake.io/languages/net_bug_tracker) sind zwei von denen, die ich weiß. NET –

Antwort

96

Ich würde Ihre Webanwendung vereinfachen, indem Sie Elmah einstecken.

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

Es ist das erste, was ich zu jedem asp.net mvc app ich erstelle hinzufügen.

Ich benutze immer noch log4net, aber ich neige dazu, es für die Protokollierung Debug/Info zu verwenden, und lassen Sie alle Ausnahmen zu Elmah. Weitere Informationen finden Sie auch in der Frage How do you log errors (Exceptions) in your ASP.NET apps?.

+3

Ich begann Elmah vor kurzem zu verwenden, und es ist einer der glattesten und einfachsten Ausnahme-Logger, die ich habe jemals benutzt. Ich habe einen Beitrag gelesen, der besagt, dass MS es in ASP.net aufnehmen sollte und ich stimme zu. – dtc

+13

Warum brauche ich ELMAH und log4net für App. protokollieren? Warum nicht eine einzige Lösung? – VJAI

+0

Funktioniert das auch, wenn ich eine n-Tier-Architektur habe? Controller - Dienstleistungen - Repositories? –

1

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

2

Haben Sie darüber nachgedacht, das Attribut HandleError zu erweitern? Außerdem hat Scott einen guten Blogbeitrag über Filterabfangeinrichtungen auf Controllern/Aktionen here.

1

Das ist Error.aspx Ansicht wie folgt definiert:

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

Die HandleErrorInfo hat drei Eigenschaften: Zeichenfolge Action Zeichenfolge controller Exception Exception

Sie sollten die für den Zugriff auf HandleErrorInfo und daher in der Lage sein, Ausnahme in der Ansicht.

35

Sie können das Ereignis OnError im Global.asax einbinden.

Etwas wie folgt aus:

/// <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); 
     } 

    } 


} 
+2

Dies sollte alle Ausnahmen abfangen. Ich halte dies für die beste Vorgehensweise. –

+4

Gemäß der Wertanalyse von ReSharper wird 'Server' immer nicht Null sein. –

+6

Das Ignorieren von 404 funktionierte für mich nicht so wie du es geschrieben hast. Ich schrieb 'if (ex ist HttpException && ((HttpException) ex) .GetHttpCode() == 404) return;' – pauloya

19

MVC3
Attribut erstellen, die von HandleErrorInfoAttribute erbt und schließt Ihre Wahl der Protokollierung

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(); 
     } 
    } 

Platz Attribut in Global.asax RegisterGlobalFilters

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