Galat pencatatan di ASP.NET MVC

109

Saat ini saya menggunakan log4net di aplikasi ASP.NET MVC saya untuk mencatat pengecualian. Cara saya melakukan ini adalah dengan membuat semua pengontrol saya mewarisi dari kelas BaseController. Dalam acara OnActionExecuting BaseController, saya mencatat setiap pengecualian yang mungkin terjadi:

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

Ini berfungsi dengan baik jika pengecualian yang tidak tertangani terjadi selama tindakan pengontrol.

Adapun kesalahan 404, saya memiliki kesalahan khusus yang diatur di web.config saya seperti ini:

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

Dan dalam tindakan pengontrol yang menangani url "halaman-tidak-ditemukan", saya mencatat url asli yang diminta:

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

    return View();
}

Dan ini juga berhasil.

Masalah yang saya alami adalah bagaimana mencatat kesalahan yang ada di halaman .aspx itu sendiri. Katakanlah saya mengalami kesalahan kompilasi pada salah satu halaman atau beberapa kode sebaris yang akan memunculkan pengecualian:

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

Tampaknya atribut HandleError mengubah rute ini dengan benar ke halaman Error.aspx saya di folder Bersama, tetapi jelas tidak tertangkap oleh metode OnActionExecuted BaseController saya. Saya berpikir saya mungkin bisa meletakkan kode logging di halaman Error.aspx itu sendiri, tapi saya tidak yakin bagaimana cara mengambil informasi kesalahan di level itu.

Kevin Pang
sumber
1 untuk ELMAH. Berikut adalah Tutorial ELMAH yang saya tulis untuk membantu Anda memulai. Ingat juga untuk menggunakan paket Elmah.MVC saat menggunakan ASP.NET MVC, untuk menghindari masalah dengan halaman kesalahan kustom dll.
ThomasArdal
Ada beberapa produk di luar sana yang akan mencatat semua kesalahan yang terjadi di aplikasi .NET. Mereka tidak serendah ELMAH atau log4net, tetapi menghemat banyak waktu jika Anda hanya mencoba memantau & mendiagnosis kesalahan: Bugsnag dan AirBrake adalah dua di antaranya yang saya tahu .NET
Don P

Jawaban:

103

Saya akan mempertimbangkan untuk menyederhanakan aplikasi web Anda dengan menghubungkannya ke Elmah .

Anda menambahkan perakitan Elmah ke proyek Anda dan kemudian mengkonfigurasi web.config Anda. Kemudian akan mencatat pengecualian yang dibuat pada pengontrol atau tingkat halaman. Ini dapat dikonfigurasi untuk masuk ke berbagai tempat berbeda (seperti SQL Server, Email, dll). Ini juga menyediakan antarmuka web, sehingga Anda dapat menelusuri log pengecualian.

Ini adalah hal pertama yang saya tambahkan ke aplikasi MVC asp.net yang saya buat.

Saya masih menggunakan log4net, tetapi saya cenderung menggunakannya untuk mencatat debug / info, dan menyerahkan semua pengecualian ke Elmah.

Anda juga dapat menemukan informasi lebih lanjut di pertanyaan Bagaimana Anda mencatat kesalahan (Pengecualian) di aplikasi ASP.NET Anda? .

Andrew Rimmer
sumber
3
Saya mulai menggunakan Elmah baru-baru ini dan ini adalah salah satu penebang pengecualian paling licin dan paling sederhana yang pernah saya gunakan. Saya membaca posting yang mengatakan bahwa MS harus memasukkannya ke dalam ASP.net dan saya setuju.
dtc
14
Mengapa saya membutuhkan ELMAH dan log4net untuk aplikasi. penebangan? Mengapa tidak ada solusi tunggal?
VJAI
Akankah ini berfungsi bahkan jika saya memiliki arsitektur n-tier? Pengontrol - layanan - repositori?
a.farkas2508
2
ELMAH dinilai terlalu tinggi.
Ronnie Overby
Apakah ELMAH gratis?
Dallas
38

Anda dapat mengikuti acara OnError di Global.asax.

Sesuatu seperti ini:

/// <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
sumber
3
Ini harus menangkap semua pengecualian. Saya menganggap ini praktik terbaik.
Andrei Rînea
4
Menurut analisis nilai ReSharper, Serverakan selalu bukan nol.
Drew Noakes
6
Mengabaikan 404 tidak berhasil bagi saya seperti yang Anda tulis. Saya menulisif (ex is HttpException && ((HttpException)ex).GetHttpCode() == 404) return;
pauloya
21

MVC3
Buat Atribut yang mewarisi dari HandleErrorInfoAttribute dan menyertakan pilihan logging Anda

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

Tempatkan atribut di Global.asax RegisterGlobalFilters

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

Pernahkah Anda berpikir untuk memperluas atribut HandleError? Selain itu, Scott memiliki entri blog yang bagus tentang interseptor filter pada pengontrol / tindakan di sini .

Kieron
sumber
1

Tampilan Error.aspx didefinisikan seperti ini:

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

HandleErrorInfo memiliki tiga properti: string ActionName string ControllerName Exception Exception

Anda harus bisa mengakses HandleErrorInfo dan juga Exception dalam tampilan.

Praveen Angyan
sumber
0

Anda dapat mencoba memeriksa HttpContext.Error, tetapi saya tidak yakin akan hal ini.

Mike Chaliy
sumber