例外の報告

OpenTelemetry .NET トレースで例外を報告する方法を学ぶ

このガイドでは、手動でアクティビティ(スパン)を作成する際に、OpenTelemetry トレーシングに例外を報告する方法について説明します。 計装ライブラリを使用している場合、これらの機能は自動的に提供されることがあります。

トレースにおける例外処理の理解

OpenTelemetry では、アプリケーションで発生するエラーに関するコンテキストを提供するために、トレースに例外を報告することが重要です。 基本的なステータス報告から完全な例外の詳細まで、これを処理する方法はいくつかあります。

ユーザーが処理する例外

ユーザーが処理する例外とは、アプリケーションによってキャッチされ処理される例外です。

try
{
    Func();
}
catch (SomeException ex)
{
    DoSomething();
}
catch (Exception ex)
{
    DoSomethingElse();
    throw;
}

OpenTelemetry .NET は、これらの例外をトレースに報告するためのいくつかのオプションを提供しています。

オプション 1:Activity のステータスを手動で設定する

もっとも基本的なオプションは、例外が発生したことを示すために Activity のステータスを Error に設定することです。

using (var activity = MyActivitySource.StartActivity("Foo"))
{
    try
    {
        Func();
    }
    catch (SomeException ex)
    {
        activity?.SetStatus(ActivityStatusCode.Error);
        DoSomething();
    }
    catch (Exception ex)
    {
        activity?.SetStatus(ActivityStatusCode.Error);
        throw;
    }
}

オプション 2:SetErrorStatusOnException 機能を使用する

深くネストされたアクティビティやサードパーティライブラリで作成されたアクティビティがある場合、手動でステータスを設定するのは困難になることがあります。 かわりに、例外を自動的に検出してアクティビティのステータスを設定するよう SDK を構成できます。

Sdk.CreateTracerProviderBuilder()
    .SetErrorStatusOnException()
    // その他の設定...
    .Build();

この構成により、アクティビティがアクティブな間に発生した例外は、自動的にそのアクティビティのステータスを Error に設定します。

オプション 3:エラーの説明を含める

より多くのコンテキストを提供するために、例外メッセージをステータスの説明として含めることができます。

using (var activity = MyActivitySource.StartActivity("Foo"))
{
    try
    {
        Func();
    }
    catch (SomeException ex)
    {
        activity?.SetStatus(ActivityStatusCode.Error, ex.Message);
    }
}

オプション 4:完全な例外を記録する

もっとも詳細なデバッグ体験を得るために、Activity.RecordException() を使用して例外をイベントとしてアクティビティに保存します。

using (var activity = MyActivitySource.StartActivity("Foo"))
{
    try
    {
        Func();
    }
    catch (SomeException ex)
    {
        activity?.SetStatus(ActivityStatusCode.Error, ex.Message);
        activity?.RecordException(ex);
    }
}

これにより、例外の型、メッセージ、スタックトレースがアクティビティにキャプチャされ、トレーシングバックエンドで利用可能になります。

未処理の例外

未処理の例外とは、アプリケーションによってキャッチおよび処理されない例外です。 通常、プロセスのクラッシュやスレッドの終了を引き起こします。

AppDomain.UnhandledException イベントハンドラーを使用することで、未処理の例外をキャプチャし、アクティブなアクティビティに記録できます。

using System;
using System.Diagnostics;
using OpenTelemetry;
using OpenTelemetry.Trace;

public class Program
{
    private static readonly ActivitySource MyActivitySource = new ActivitySource("MyCompany.MyProduct.MyLibrary");

    public static void Main()
    {
        AppDomain.CurrentDomain.UnhandledException += UnhandledExceptionHandler;

        using var tracerProvider = Sdk.CreateTracerProviderBuilder()
            .AddSource("MyCompany.MyProduct.MyLibrary")
            .SetSampler(new AlwaysOnSampler())
            .SetErrorStatusOnException()
            .AddConsoleExporter()
            .Build();

        using (MyActivitySource.StartActivity("Foo"))
        {
            using (MyActivitySource.StartActivity("Bar"))
            {
                throw new Exception("Oops!");
            }
        }
    }

    private static void UnhandledExceptionHandler(object source, UnhandledExceptionEventArgs args)
    {
        var ex = (Exception)args.ExceptionObject;

        var activity = Activity.Current;

        while (activity != null)
        {
            activity.RecordException(ex);
            activity.Dispose();
            activity = activity.Parent;
        }
    }
}

ベストプラクティス

OpenTelemetry トレースで例外を報告する際のベストプラクティスは以下のとおりです。

  1. 常にステータスを Error に設定する:最低限、例外が発生した場合はアクティビティのステータスを Error に設定してください。

  2. 例外の詳細を含める:可能な場合は RecordException() を使用して、完全な例外情報をキャプチャしてください。

  3. 未処理の例外を処理する:未処理の例外がトレースにキャプチャされるよう、グローバルハンドラーの設定を検討してください。

  4. 自動化を検討する:例外のステータス設定を自動化するために、SDK の SetErrorStatusOnException() オプションを使用してください。

  5. カーディナリティに注意する:変動性の高い例外メッセージをステータスの説明に直接含めると、スパンのカーディナリティが増加する可能性があるため注意してください。

さらに学ぶ