使用 Application Insights 诊断 Web 应用中的异常

注意

以下文档依赖于 Application Insights 经典 API。 Application Insights 的长期计划是使用 OpenTelemetry 收集数据。 有关详细信息,请参阅为 .NET、Node.js、Python 和 Java 应用程序启用 Azure Monitor OpenTelemetry我们的 OpenTelemetry 路线图。 迁移指导适用于 .NETNode.jsPython

Web 应用程序中的异常可以使用 Application Insights 进行报告。 可将失败的请求与客户端和服务器上的异常和其他事件相关联,从而快速诊断原因。 本文介绍如何设置异常报告、显式报告异常、诊断故障等。

设置异常报告

可以设置 Application Insights 以报告服务器或客户端中发生的异常。 根据应用程序所依赖的平台,你将需要添加相应的扩展或 SDK。

服务器端

若要从服务器端应用程序报告异常,请考虑以下方案:

客户端

JavaScript SDK 提供让客户端报告 Web 浏览器中发生的异常的功能。 若要在客户端设置有关报告异常的功能,请参阅用于网页的 Application Insights

应用程序框架

对于某些应用程序框架,需要进行更多配置。 请考虑以下技术:

重要

本文从代码示例的角度着重介绍 .NET Framework 应用。 用于 .NET Framework 的某些方法在 .NET Core SDK 中已过时。 使用 .NET Core 生成应用时,请参阅 .NET Core SDK 文档了解详细信息。

使用 Visual Studio 诊断异常

在 Visual Studio 中打开应用程序解决方案。 使用 F5 在服务器或开发计算机上运行应用。 重新创建异常。

打开 Visual Studio 中的“Application Insights 搜索”遥测窗口。 调试时,选择“Application Insights”下拉框。

该屏幕截图显示如何右键单击项目并选择“Application Insights”。

选择异常报告,显示器堆栈跟踪。 若要打开相关代码文件,请选择堆栈跟踪中的行引用。

如果已启用 CodeLens,你将看到有关异常的数据:

该屏幕截图显示 CodeLens 的异常通知。

使用 Azure 门户诊断失败

Application Insights 随附了特选的应用程序性能管理体验,可帮助你诊断受监视应用程序中发生的故障。 若要开始,请在左侧 Application Insights 资源菜单中的“调查”下,选择“失败”选项。

你将看到请求的失败率趋势、其中失败的请求数,以及受影响的用户数。 “总体”视图显示特定于所选失败操作的一些最有用的分布情况。 你将看到排名前三的响应代码、排名前三的异常类型以及排名前三的失败依赖项类型。

该屏幕截图显示“操作”选项卡上的“故障会审”视图。

若要查看其中每个操作子集的具有代表性的示例,请选择相应链接。 例如,若要诊断异常,可以选择要在“端到端事务详细信息”选项卡中显示的特定异常的计数。

该屏幕截图显示“端到端事务详细信息”选项卡。

或者,可以切换到顶部的“异常”选项卡,从异常的“总体”视图开始,而不是查看特定失败操作的异常。 这里可以看到为所监视的应用收集的所有异常。

自定义跟踪和日志数据

要获取特定于应用的诊断数据,可在插入代码后发送自己的遥测数据。 自定义遥测或日志数据与请求、页面视图和其他自动收集的数据一起显示在诊断搜索中。

可以通过 Microsoft.VisualStudio.ApplicationInsights.TelemetryClient 使用多个 API:

若要查看这些事件,请在左侧菜单中打开“搜索”。 选择下拉菜单“事件类型”,然后选择“自定义事件”、“跟踪”或“异常”。

显示“搜索”屏幕的屏幕截图。

备注

如果应用生成大量遥测数据,自适应采样模块将通过仅发送具有代表性的事件部分来自动减少发送到门户的数据量。 属于同一操作的事件将以组为单位进行选择或取消选择,以便你可以在相关事件之间导航。 有关详细信息,请参阅 Application Insights 中的采样

查看请求 POST 数据

请求详细信息不包含在 POST 调用中发送到应用的数据。 若要报告此数据:

  • 在应用程序中安装 SDK
  • 在应用程序中插入代码以调用 Microsoft.ApplicationInsights.TrackTrace()。 在消息参数中发送 POST 数据。 允许的大小有限制,因此,应该尝试仅发送必要数据。
  • 调查失败的请求时,查找关联的跟踪。

捕获异常和相关的诊断数据

首先,不会在门户中看到在应用中导致失败的所有异常。 如果在网页中使用 JavaScript SDK,你将会看到所有浏览器异常。 但大多数服务器异常由 IIS 导致,必须编写几行代码才能看到它们。

方法:

  • 通过在异常处理程序中插入代码来显式记录异常,从而报告这些异常。
  • 通过配置 ASP.NET 框架自动捕获异常。 框架类型不同,必要的附加内容也不同。

显式报告异常

最简单的报告方法是在异常处理程序中插入对 trackException() 的调用。

try
{
    // ...
}
catch (ex)
{
    appInsights.trackException(ex, "handler loc",
    {
        Game: currentGame.Name,
        State: currentGame.State.ToString()
    });
}
var telemetry = new TelemetryClient();

try
{
    // ...
}
catch (Exception ex)
{
    var properties = new Dictionary<string, string>
    {
        ["Game"] = currentGame.Name
    };

    var measurements = new Dictionary<string, double>
    {
        ["Users"] = currentGame.Users.Count
    };

    // Send the exception telemetry:
    telemetry.TrackException(ex, properties, measurements);
}
Dim telemetry = New TelemetryClient

Try
    ' ...
Catch ex as Exception
    ' Set up some properties:
    Dim properties = New Dictionary (Of String, String)
    properties.Add("Game", currentGame.Name)

    Dim measurements = New Dictionary (Of String, Double)
    measurements.Add("Users", currentGame.Users.Count)

    ' Send the exception telemetry:
    telemetry.TrackException(ex, properties, measurements)
End Try

属性和测量参数是可选的,但对筛选和添加额外信息很有用。 例如,如果有一个可运行多个游戏的应用,可查找与特定游戏相关的所有异常报表。 可向每个字典添加任意数量的项。

浏览器异常

报告大多数浏览器异常。

如果网页包括来自内容分发网络或其他域的脚本文件,请确保脚本标记具有属性 crossorigin="anonymous",并且服务器可发送 CORS 头。 此行为允许从这些资源中获取有关未处理的 JavaScript 异常的堆栈跟踪和详细信息。

重用遥测客户端

注意

建议实例化 TelemetryClient 一次,并在应用程序的整个生命周期内重复使用它。

借助 .NET 中的依赖项注入 (DI)、适当的 .NET SDK,并为 DI 正确配置 Application Insights,可以要求将 TelemetryClient 作为构造函数参数。

public class ExampleController : ApiController
{
    private readonly TelemetryClient _telemetryClient;

    public ExampleController(TelemetryClient telemetryClient)
    {
        _telemetryClient = telemetryClient;
    }
}

在前面的示例中,已将 TelemetryClient 注入到 ExampleController 类中。

Web 窗体

在 Web 窗体中,当不存在通过 CustomErrors 配置的重定向时,HTTP 模块能够收集异常。 但是,如果有活动重定向,在 Global.asax.cs 中将以下行添加到 Application_Error 函数。

void Application_Error(object sender, EventArgs e)
{
    if (HttpContext.Current.IsCustomErrorEnabled &&
        Server.GetLastError () != null)
    {
        _telemetryClient.TrackException(Server.GetLastError());
    }
}

在前面的示例中,_telemetryClient 是类型 TelemetryClient 的类范围内变量。

MVC

从 Application Insights Web SDK 2.6 版(beta3 及更高版本)开始,Application Insights 会自动收集 MVC 5+ 控制器方法中引发的未经处理异常。 如果之前已添加自定义处理程序以跟踪此类异常,可将其删除以避免对异常进行双重跟踪。

在某些情况下,当引发异常时,异常筛选器无法正确处理错误:

  • 从控制器构造函数引发异常时
  • 从消息处理程序引发异常时
  • 在路由期间引发异常时
  • 在响应内容序列化期间引发异常时
  • 在应用程序启动期间引发异常时
  • 在后台任务中引发异常时

仍需要手动跟踪应用程序处理的所有异常。 源自控制器的未经处理异常通常会导致 500“内部服务器错误”响应。 如果此类响应是由于已处理的异常或根本没有任何异常而手动构造的,则它是通过 ResultCode 500 在相应请求遥测数据中进行跟踪的。 但是,Application Insights SDK 无法跟踪相应异常。

以前版本支持

如果使用 Application Insights Web SDK 2.5(及更低版本)的 MVC 4(及更低版本),请参照以下示例跟踪异常。

如果 CustomErrors 配置为 Off,异常将可供 HTTP 模块收集。 但是,如果它是 RemoteOnly(默认值)或 On,异常将被清除,并且 Application Insights 无法自动收集它。 可通过重写 System.Web.Mvc.HandleErrorAttribute 类并应用这个已重写的类来修复该行为,如下面适用于不同 MVC 版本的代码所示(请参阅 GitHub 源):

using System;
using System.Web.Mvc;
using Microsoft.ApplicationInsights;

namespace MVC2App.Controllers
{
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
    public class AiHandleErrorAttribute : HandleErrorAttribute
    {
        public override void OnException(ExceptionContext filterContext)
        {
            if (filterContext != null && filterContext.HttpContext != null && filterContext.Exception != null)
            {
                //The attribute should track exceptions only when CustomErrors setting is On
                //if CustomErrors is Off, exceptions will be caught by AI HTTP Module
                if (filterContext.HttpContext.IsCustomErrorEnabled)
                {   //Or reuse instance (recommended!). See note above.
                    var ai = new TelemetryClient();
                    ai.TrackException(filterContext.Exception);
                }
            }
            base.OnException(filterContext);
        }
    }
}

MVC 2

将 HandleError 属性替换为控制器中的新属性:

    namespace MVC2App.Controllers
    {
        [AiHandleError]
        public class HomeController : Controller
        {
            // Omitted for brevity
        }
    }

示例

MVC 3

在 Global.asax.cs 中将 AiHandleErrorAttribute 注册为全局筛选器:

public class MyMvcApplication : System.Web.HttpApplication
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new AiHandleErrorAttribute());
    }
}

示例

MVC 4、MVC 5

在 FilterConfig.cs 中将 AiHandleErrorAttribute 注册为全局筛选器:

public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        // Default replaced with the override to track unhandled exceptions
        filters.Add(new AiHandleErrorAttribute());
    }
}

示例

Web API

从 Application Insights Web SDK 2.6 版(beta3 及更高版本)开始,Application Insights 会自动收集 WebAPI 2+ 控制器方法中引发的未经处理异常。 如果之前已添加自定义处理程序以跟踪此类异常(如下面的示例中所述),则可以删除该处理程序以避免对异常进行双重跟踪。

存在一些无法处理异常筛选器的情况。 例如:

  • 从控制器构造函数引发的异常。
  • 从消息处理程序引发的异常。
  • 在路由过程中引发的异常。
  • 在响应内容序列化期间引发的异常。
  • 在应用程序启动过程中引发的异常。
  • 在后台任务中引发的异常。

仍需要手动跟踪应用程序处理的所有异常。 源自控制器的未经处理异常通常会导致 500“内部服务器错误”响应。 如果此类响应是由于已处理的异常或根本没有任何异常而手动构造的,则它是通过 ResultCode 500 在相应请求遥测数据中进行跟踪的。 但是,Application Insights SDK 无法跟踪相应异常。

以前版本支持

如果使用 Application Insights Web SDK 2.5(及更低版本)的 WebAPI 1(及更低版本),请参照以下示例跟踪异常。

Web API 1.x

替代 System.Web.Http.Filters.ExceptionFilterAttribute

using System.Web.Http.Filters;
using Microsoft.ApplicationInsights;

namespace WebAPI.App_Start
{
    public class AiExceptionFilterAttribute : ExceptionFilterAttribute
    {
    public override void OnException(HttpActionExecutedContext actionExecutedContext)
    {
        if (actionExecutedContext != null && actionExecutedContext.Exception != null)
        {  //Or reuse instance (recommended!). See note above.
            var ai = new TelemetryClient();
            ai.TrackException(actionExecutedContext.Exception);
        }
        base.OnException(actionExecutedContext);
    }
    }
}

可将此替换属性添加到特定控制器,或者将其添加到 WebApiConfig 类中的全局筛选器配置:

using System.Web.Http;
using WebApi1.x.App_Start;

namespace WebApi1.x
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional });
    
            // ...
            config.EnableSystemDiagnosticsTracing();
    
            // Capture exceptions for Application Insights:
            config.Filters.Add(new AiExceptionFilterAttribute());
        }
    }
}

示例

Web API 2.x

添加 IExceptionLogger 的实现:

using System.Web.Http.ExceptionHandling;
using Microsoft.ApplicationInsights;

namespace ProductsAppPureWebAPI.App_Start
{
    public class AiExceptionLogger : ExceptionLogger
    {
        public override void Log(ExceptionLoggerContext context)
        {
            if (context != null && context.Exception != null)
            {
                //or reuse instance (recommended!). see note above
                var ai = new TelemetryClient();
                ai.TrackException(context.Exception);
            }
            base.Log(context);
        }
    }
}

将此代码片段添加到服务的 WebApiConfig 中:

using System.Web.Http;
using System.Web.Http.ExceptionHandling;
using ProductsAppPureWebAPI.App_Start;

namespace WebApi2WithMVC
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            // Web API configuration and services
    
            // Web API routes
            config.MapHttpAttributeRoutes();
    
            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional });

            config.Services.Add(typeof(IExceptionLogger), new AiExceptionLogger());
        }
    }
}

示例

作为替代项,可以:

  • 仅将 ExceptionHandler 实例替换为 IExceptionHandler 的自定义实现。 此异常处理程序仅在框架仍能够选择要发送哪个响应消息时(而不是在终止了连接等情况下)调用。
  • 使用异常筛选器(如上述有关 Web API 1.x 控制器的部分中所述),这些筛选器并非在所有情况下都调用。

WCF

添加一个用来扩展 Attribute 并实现 IErrorHandlerIServiceBehavior 的类。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.ServiceModel.Description;
    using System.ServiceModel.Dispatcher;
    using System.Web;
    using Microsoft.ApplicationInsights;

    namespace WcfService4.ErrorHandling
    {
      public class AiLogExceptionAttribute : Attribute, IErrorHandler, IServiceBehavior
      {
        public void AddBindingParameters(ServiceDescription serviceDescription,
            System.ServiceModel.ServiceHostBase serviceHostBase,
            System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints,
            System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
        {
        }

        public void ApplyDispatchBehavior(ServiceDescription serviceDescription,
            System.ServiceModel.ServiceHostBase serviceHostBase)
        {
            foreach (ChannelDispatcher disp in serviceHostBase.ChannelDispatchers)
            {
                disp.ErrorHandlers.Add(this);
            }
        }

        public void Validate(ServiceDescription serviceDescription,
            System.ServiceModel.ServiceHostBase serviceHostBase)
        {
        }

        bool IErrorHandler.HandleError(Exception error)
        {//or reuse instance (recommended!). see note above
            var ai = new TelemetryClient();

            ai.TrackException(error);
            return false;
        }

        void IErrorHandler.ProvideFault(Exception error,
            System.ServiceModel.Channels.MessageVersion version,
            ref System.ServiceModel.Channels.Message fault)
        {
        }
      }
    }

将属性添加到服务实现:

namespace WcfService4
{
    [AiLogException]
    public class Service1 : IService1
    {
        // Omitted for brevity
    }
}

示例

异常性能计数器

如果在服务器上安装了 Azure Monitor Application Insights 代理,可以获取通过 .NET 测量的异常率的图表。 已经处理和未经处理的 .NET 异常均会包括在内。

打开指标资源管理器选项卡,添加新图表。 在“性能计数器”下,选择“异常率”。

.NET Framework 通过对间隔中的异常数进行计数并除以间隔长度计算异常率。

此计数与 Application Insights 门户通过对 TrackException 报告计数计算得出的“异常”计数不同。 采样间隔不同,并且 SDK 不会为所有已经处理和未经处理的异常发送 TrackException 报告。

后续步骤