Application Insights を使用した Web アプリの例外の診断

Web アプリケーションの例外は、Application Insights でレポートすることができます。 要求の失敗をクライアントとサーバーの両方の例外またはその他のイベントに相互に関連付けることで、原因をすばやく診断できます。 この記事では、例外のレポート処理を設定したり、例外を明示的にレポートしたり、障害を診断したりする方法について説明します。

例外のレポートを設定する

サーバーまたはクライアントで発生した例外をレポートするように Application Insights を設定できます。 アプリケーションが依存しているプラットフォームによっては、適切な拡張機能または SDK が必要になります。

サーバー側

サーバー側のアプリケーションから例外をレポートさせるには、次のシナリオを考慮してください。

クライアント側

Web ブラウザーで発生した例外をクライアント側でレポートする機能は、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] ドロップダウン ボックスを選択します。

Screenshot that shows right-clicking the project and choosing Application Insights.

例外レポートを選択してスタック トレースを表示します。 関連コード ファイルを開くには、スタック トレース内の明細行参照をクリックします。

CodeLens が有効になっている場合、例外に関するデータが表示されます。

Screenshot that shows CodeLens notification of exceptions.

Azure portal を使用して障害を診断する

Application Insights には、監視対象アプリケーションの障害を診断するのに役立つ、キュレーションされたアプリケーション パフォーマンス管理エクスペリエンスが用意されています。 開始するには、左側の Application Insights リソース メニューの [調査][失敗] オプションを選択します。

要求の失敗率の傾向、失敗の数、影響を受けたユーザーの数が表示されます。 [全体] ビューには、選択した失敗操作に固有の最も有用な分布がいくつか表示されます。 上位 3 件の応答コード、上位 3 件の例外の種類、上位 3 件の失敗した依存関係の種類が表示されます。

Screenshot that shows a failures triage view on the Operations tab.

これらの操作のサブセットごとに代表的なサンプルを確認するには、対応するリンクを選択します。 たとえば、例外を診断するには、特定の例外の数を選択します。すると、それが [エンドツーエンド トランザクションの詳細] タブに表示されます。

Screenshot that shows the End-to-end transaction details tab.

または、特定の失敗した操作の例外を調べる代わりに、上部で [例外] タブに切り替えて例外の [全体] ビューから開始できます。 ここでは、監視対象のアプリケーションに関して収集されたすべての例外が表示されます。

カスタムのトレースとログ データ

アプリに固有の診断データを取得するには、独自のテレメトリ データを送信するコードを挿入します。 カスタムのテレメトリまたはログ データは、要求、ページ ビュー、およびその他の自動収集されたデータと共に、診断検索に表示されます。

Microsoft.VisualStudio.ApplicationInsights.TelemetryClient を使用すると、いくつかの API が利用できます。

  • TelemetryClient.TrackEvent は通常、使用パターンを監視するために使用されますが、送信されるデータは診断検索のカスタム イベントの下にも表示されます。 イベントには名前が付けられるほか、文字列プロパティや数値メトリックが付与され、それらを元に診断検索をフィルター処理できます。
  • TelemetryClient.TrackTrace は、POST 情報などの長いデータを送信できます。
  • TelemetryClient.TrackException は、Application Insights に例外の詳細 (スタック トレースなど) を送信します。

これらのイベントを表示するには、左側のメニューで [検索] を開きます。 [イベントの種類] ドロップダウン メニューを選択し、[カスタム イベント][トレース]、または [例外] を選択します。

Screenshot that shows the Search screen.

Note

アプリから大量のテレメトリが生成されると、アダプティブ サンプリング モジュールからイベントの代表的な部分のみが送信され、ポータルに送信されるデータ量が自動的に削減されます。 同じ操作に含まれるイベントはグループ単位で選択または選択解除されるので、関連するイベントごとに操作できます。 詳細については、「Application Insights におけるサンプリング」を参照してください。

要求の POST データを表示する

要求詳細では、POST 呼び出しでアプリに送信されたデータは含まれません。 このデータを報告するには:

  • アプリケーション プロジェクトに SDK をインストールします
  • アプリケーションにコードを挿入し、Microsoft.ApplicationInsights.TrackTrace() を呼び出します。 メッセージ パラメーターで POST データを送信します。 許可されるサイズには制限があります。そのため、必要不可欠なデータだけを送信するように努めてください。
  • 失敗した要求を調査するときは、関連付けられているトレースを検索します。

例外と関連する診断データをキャプチャする

最初、ポータルにはアプリの障害の原因となる例外の一部しか表示されません。 Web ページで JavaScript SDK を使用している場合は、ブラウザーの例外はすべて表示されます。 ただし、ほとんどのサーバー例外は IIS によりキャッチされます。それを確認するには、簡単なコードを記述する必要があります。

次のようにすることができます。

  • 例外を明示的に記録します
  • 例外を自動的にキャプチャします 。 追加しなければならないものはフレームワークの種類によって異なります。

例外を明示的にレポートする

最も簡単なレポート方法は、例外ハンドラーに 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

プロパティと測定値のパラメーターは省略可能ですが、フィルター処理と、特別な情報を追加するのに便利です。 たとえば、複数のゲームを実行できるアプリケーションを使用している場合、1 つのゲームに関連する例外レポートをすべて検索できます。 必要な数だけ項目を各辞書に追加できます。

ブラウザーの例外

ほとんどのブラウザー例外が報告されます。

Web ページにコンテンツ配信ネットワークまたは他のドメインのスクリプト ファイルが含まれている場合は、スクリプト タグに crossorigin="anonymous" 属性があり、サーバーが CORS ヘッダーを送信することを確認します。 この動作により、これらのリソースから、未処理の JavaScript 例外のスタック トレースと詳細を取得できます。

テレメトリ クライアントを再利用する

Note

TelemetryClient を 1 回インスタンス化し、アプリケーションの有効期間中はそれを再利用することをお勧めします。

.NET の依存関係の挿入 (DI) と適切な .NET SDK があって、さらに Application Insights を DI 用に正しく構成すれば、コンストラクターのパラメーターとして TelemetryClient を要求することができます。

public class ExampleController : ApiController
{
    private readonly TelemetryClient _telemetryClient;

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

前の例では、TelemetryClientExampleController クラスに挿入されます。

Web フォーム

Web フォームの場合、HTTP モジュールは、CustomErrors で構成されたリダイレクトがないとき、例外を回収できます。 ただし、アクティブなリダイレクトがある場合、次の行を Global.asax.csApplication_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.csAiHandleErrorAttribute をグローバル フィルターとして登録します。

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

サンプル

MVC 4、MVC 5

FilterConfig.csAiHandleErrorAttribute をグローバル フィルターとして登録します。

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 では、Web API 2+ についてコントローラーのメソッドでスローされたハンドルされない例外を自動的に収集します。 そのような例外 (次の例を参照) を追跡するためにカスタム ハンドラーを以前に追加した場合は、例外の二重追跡を防止するためにそれを削除できます。

例外フィルターで処理できないケースがいくつかあります。 次に例を示します。

  • コントローラー コンストラクターからスローされる例外。
  • メッセージ ハンドラーからスローされる例外。
  • ルーティング中にスローされる例外。
  • 応答コンテンツのシリアル化中にスローされる例外。
  • アプリケーションの起動中にスローされる例外。
  • バックグラウンド タスクでスローされる例外。

アプリケーションによって "処理される" すべての例外も手動で追跡する必要があります。 コントローラーで発生したハンドルされない例外では、通常、500 "内部サーバー エラー" 応答が返されます。 このような応答が、処理された例外 (または例外なし) の結果として手動で作成された場合は、ResultCode 500 を使用して対応する要求テレメトリで追跡されます。 ただし、Application Insights SDK では対応する例外を追跡できません。

以前のバージョンのサポート

Application Insights Web SDK 2.5 (およびそれ以前) の Web API 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 フレームワークでは、ある特定の時間間隔の例外数をカウントし、それを時間間隔の長さで除算してレートを算出します。

この数は、TrackException レポートをカウントする Application Insights ポータルで算出される例外数とは異なります。 サンプリングの時間間隔が異なります。さらに、SDK では、すべての処理済みの例外と未処理の例外について TrackException レポートを送信するわけではありません。

次のステップ