Lỗi ghi nhật ký trong ASP.NET MVC


109

Tôi hiện đang sử dụng log4net trong ứng dụng ASP.NET MVC của mình để ghi các ngoại lệ. Cách tôi đang làm điều này là để tất cả các bộ điều khiển của tôi kế thừa từ một lớp BaseController. Trong sự kiện OnActionExecuting của BaseController, tôi ghi lại bất kỳ ngoại lệ nào có thể đã xảy ra:

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

Điều này hoạt động tốt nếu một ngoại lệ chưa được xử lý xảy ra trong một hành động của bộ điều khiển.

Đối với lỗi 404, tôi có một lỗi tùy chỉnh được thiết lập trong web.config của mình như sau:

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

Và trong hành động trình điều khiển xử lý url "không tìm thấy trang", tôi ghi lại url ban đầu được yêu cầu:

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

    return View();
}

Và điều này cũng hoạt động.

Vấn đề mà tôi gặp phải là làm thế nào để ghi lại các lỗi trên chính các trang .aspx. Giả sử tôi gặp lỗi biên dịch trên một trong các trang hoặc một số mã nội tuyến sẽ tạo ra một ngoại lệ:

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

Có vẻ như thuộc tính HandleError đang định tuyến lại chính xác trang này đến trang Error.aspx của tôi trong thư mục Chia sẻ, nhưng nó chắc chắn không bị phương thức OnActionExecuted của BaseController bắt giữ. Tôi đã nghĩ rằng mình có thể đặt mã ghi nhật ký trên chính trang Error.aspx, nhưng tôi không chắc về cách truy xuất thông tin lỗi ở cấp đó.


+1 cho ELMAH. Đây là Hướng dẫn ELMAH tôi đã viết để giúp bạn bắt đầu. Cũng nên nhớ để sử dụng Elmah.MVC gói khi sử dụng ASP.NET MVC, các vấn đề tránh với các trang lỗi tùy chỉnh, vv
ThomasArdal

Có một số sản phẩm sẽ ghi lại tất cả các lỗi xảy ra trong ứng dụng .NET. Chúng không ở cấp độ thấp như ELMAH hoặc log4net, nhưng giúp bạn tiết kiệm rất nhiều thời gian nếu bạn chỉ đang cố gắng theo dõi và chẩn đoán lỗi: BugsnagAirBrake là hai trong số đó tôi biết .NET
Don P

Câu trả lời:


103

Tôi sẽ xem xét việc đơn giản hóa ứng dụng web của bạn bằng cách cắm Elmah .

Bạn thêm hội đồng Elmah vào dự án của mình và sau đó định cấu hình web.config của bạn. Sau đó, nó sẽ ghi lại các ngoại lệ được tạo ở cấp bộ điều khiển hoặc cấp trang. Nó có thể được cấu hình để đăng nhập vào nhiều nơi khác nhau (như SQL Server, Email, v.v.). Nó cũng cung cấp một giao diện người dùng web để bạn có thể duyệt qua nhật ký các trường hợp ngoại lệ.

Đó là điều đầu tiên tôi thêm vào bất kỳ ứng dụng mvc asp.net nào mà tôi tạo.

Tôi vẫn sử dụng log4net, nhưng tôi có xu hướng sử dụng nó để ghi nhật ký gỡ lỗi / thông tin và để lại tất cả các ngoại lệ cho Elmah.

Bạn cũng có thể tìm thêm thông tin trong câu hỏi Làm cách nào để ghi lại lỗi (Ngoại lệ) trong ứng dụng ASP.NET của bạn? .


3
Tôi đã bắt đầu sử dụng Elmah gần đây và nó là một trong những trình ghi ngoại lệ trơn tru và đơn giản nhất mà tôi từng sử dụng. Tôi đọc một bài đăng nói rằng MS nên đưa nó vào ASP.net và tôi đồng ý.
dtc

14
Tại sao tôi cần cả ELMAH và log4net cho ứng dụng. khai thác gỗ? Tại sao không phải là một giải pháp duy nhất?
VJAI

Điều này sẽ hoạt động ngay cả khi tôi có kiến ​​trúc n-tier? Bộ điều khiển - dịch vụ - kho lưu trữ?
a.farkas2508

2
ELMAH được đánh giá quá cao.
Ronnie Overby

ELMAH có miễn phí không?
Dallas

38

Bạn có thể kết nối vào sự kiện OnError trong Global.asax.

Một cái gì đó như thế này:

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

    }


}

3
Điều này sẽ bắt tất cả các trường hợp ngoại lệ. Tôi coi đây là cách tốt nhất.
Andrei Rînea

4
Theo phân tích giá trị của ReSharper, Serversẽ luôn không rỗng.
Drew Noakes

6
Bỏ qua 404 không phù hợp với tôi như cách bạn đã viết. Tôi đã viếtif (ex is HttpException && ((HttpException)ex).GetHttpCode() == 404) return;
pauloya

21

MVC3
Tạo thuộc tính kế thừa từ HandleErrorInfoAttribute và bao gồm lựa chọn ghi nhật ký của bạn

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

Đặt thuộc tính trong Global.asax RegisterGlobalFilters

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

1

Bạn đã nghĩ đến việc mở rộng thuộc tính HandleError chưa? Ngoài ra, Scott có một bài đăng blog hay về bộ lọc chặn trên bộ điều khiển / hành động ở đây .


1

Chế độ xem Error.aspx được định nghĩa như thế này:

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

HandleErrorInfo có ba thuộc tính: string ActionName string ControllerName Exception Exception

Bạn sẽ có thể truy cập HandleErrorInfo và do đó là Exception trong dạng xem.


0

Bạn có thể thử kiểm tra HttpContext.Error, nhưng tôi không chắc về điều này.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.