是否可以配置在应用程序崩溃时存储在Windows事件日志中的信息?

时间:2015-12-07 17:59:35

标签: c# asp.net .net stack-overflow event-log

有时,错误会触发导致整个ASP.NET MVC应用程序崩溃的不可恢复的异常之一(例如StackOverflowException)。发生这种情况时,Windows事件日志通常包含有关错误的一些信息,尽管它很小。例如,目前,我们认为在反射调用中抛出了StackOverflowException。在这种情况下,事件日志包含有关外部TargetInvocationException的一些基本信息,并且没有任何内容可以让我们查明问题。我的问题是,是否可以在.NET / IIS / Windows中配置某些内容以在发生这种情况时记录更多信息?例如,如果我们可以获得完整异常的前N个字符(包括堆栈跟踪和内部异常),我们可以轻松地调试并解决问题。

1 个答案:

答案 0 :(得分:0)

您无法控制其他类写入日志的内容,但您可以捕获global.asax文件中的异常并执行自己的日志记录。我倾向于使用数据库日志记录和电子邮件通知的组合。

- global.asax中

    void Application_Error(object sender, EventArgs e)
    {
        // Code that runs when an unhandled error occurs
        Exception exSvr = Server.GetLastError();

        if (exSvr == null)
            return;

        if (exSvr.Message == "The client disconnected.")
        {
            // I don't want to be notified everytime someone closes
            //   the browser mid-request.
            return;
        }

        if (exSvr is System.Threading.ThreadAbortException || exSvr.InnerException is System.Threading.ThreadAbortException || exSvr.Message.StartsWith("Thread was being aborted") || (exSvr.InnerException != null && exSvr.InnerException.Message.StartsWith("Thread was being aborted")))
        {
            // So we don't get notified everytime .NET kills a thread.
            // NOTE:  This error is how .NET kills a thread, and will happen every time we call Response.Redirect("", true)
            return;
        }

        ErrorHandler.SendServerErrMsg("Application Error", exSvr, HttpContext.Current);
    }

- 的ErrorHandler

    public static void SendServerErrMsg(string codeSection, Exception exSvr, HttpContext context, SeverityLevel lvl = SeverityLevel.Warning)
    {
        if (_config == null || !_config.EnableEmailAlerts)
            return;

        if (context != null && context.Request != null && context.Request.Url != null && context.Request.Url.IsLoopback && !_config.SendAlertsInDebugMode)
            return;

        if (context != null && context.IsDebuggingEnabled && !_config.SendAlertsInDebugMode)
            return;

        // Attempt to get the currently logged in user.
        System.Web.Security.MembershipUser curUsr = null;
        try
        { curUsr = System.Web.Security.Membership.GetUser(); }
        catch { } // If it fails, don't worry about it.

        // Set the message's subject line.
        string subject = _config.ApplicationName + " Exception - " + HttpUtility.HtmlEncode(codeSection);

        // Build the page body in a StringBuilder object.
        System.Text.StringBuilder sb = new System.Text.StringBuilder();
        if (context != null && context.Request != null)
            sb.AppendLine(string.Format("<h2>{0}</h2>", HttpUtility.HtmlEncode(context.Request.ApplicationPath)));
        sb.AppendLine("<p>The following exception has occurred:</p>");
        sb.AppendLine("<ul>");
        Exception innerEx = exSvr;
        while (innerEx != null)
        {
            sb.AppendLine(string.Format("<li>{0}</li>", HttpUtility.HtmlEncode(innerEx.Message)));
            innerEx = innerEx.InnerException;
        }
        sb.AppendLine("</ul>");
        sb.AppendLine("<p/>");
        if (exSvr.TargetSite != null)
            sb.AppendLine(string.Format("<p>Target Site: {0} {1} (in {2})</p>", exSvr.TargetSite.MemberType, exSvr.TargetSite.Name, exSvr.TargetSite.DeclaringType));
        else
            sb.AppendLine("<p>Target Site: N/A</p>");
        sb.AppendLine("<p/>");
        sb.AppendLine("<hr />");
        if (context != null && context.Request != null)
        {
            HttpRequest req = context.Request;
            sb.AppendLine("<p>");
            sb.AppendLine(string.Format("<div>Request URL: {0}</div>", HttpUtility.HtmlEncode(req.Url.ToString())));
            sb.AppendLine(string.Format("<div>Request Path: {0}</div>", HttpUtility.HtmlEncode(req.FilePath)));
            sb.AppendLine(string.Format("<div>User: {0}</div>", (curUsr != null) ? HttpUtility.HtmlEncode(curUsr.UserName) : "Unknown"));
            sb.AppendLine(string.Format("<div>User Host Address: {0}</div>", HttpUtility.HtmlEncode(req.UserHostAddress)));
            // We're going to try a reverse DNS search on the IP address.  Failover,
            //   just uses the UserHostName value from the HttpContext object.
            string hostName = null;
            try { hostName = System.Net.Dns.GetHostEntry(req.UserHostAddress).HostName; }
            catch { hostName = null; }
            if (hostName == null) hostName = req.UserHostName;
            sb.AppendLine(string.Format("<div>User Host Name: {0}</div>", HttpUtility.HtmlEncode(hostName)));
            sb.AppendLine(string.Format("<div>User Agent: {0}</div>", HttpUtility.HtmlEncode(req.UserAgent)));
            sb.AppendLine(string.Format("<div>Server Name: {0}</div>", (context.Server != null ? HttpUtility.HtmlEncode(context.Server.MachineName) : "Unknown")));
            sb.AppendLine(string.Format("<div>Request Identity: {0}</div>", (req.LogonUserIdentity != null ? HttpUtility.HtmlEncode(req.LogonUserIdentity.Name) : "Unknown")));

            sb.AppendLine("</p>");
            sb.AppendLine("<hr />");
        }
        sb.AppendLine("<p>Stack trace follows:</p>");
        Exception ex = exSvr;
        while (ex != null)
        {
            sb.AppendLine("<p>");
            sb.AppendLine(string.Format("<b>&gt;&gt;&nbsp;{0}:</b> {1} in {2}<br/>", ex.GetType().Name, HttpUtility.HtmlEncode(ex.Message), HttpUtility.HtmlEncode(ex.Source)));
            sb.AppendLine(HttpUtility.HtmlEncode(ex.StackTrace));
            sb.AppendLine("</p>");
            ex = ex.InnerException;
        }
        if (context!=null && context.Trace.IsEnabled)
        {
            sb.AppendLine("<hr />");
            sb.AppendLine("<p>Web Trace:</p>");
            sb.AppendLine(string.Format("<p>{0}</p>", HttpUtility.HtmlEncode(context.Trace.ToString())));
        }

        EmailHelper.SendEmail(GetAlertContacts(), subject.Trim(), sb.ToString().Trim(), true);
    }