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

本文关键字:日志 事件 存储 信息 Windows 配置 崩溃 应用程序 是否 | 更新日期: 2023-09-27 18:26:10

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

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

您无法控制其他类向日志中写入的内容,但您可以在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);
    }

--错误处理程序

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