.NET カスタムインスツルメンテーション

.NET トレーサーのセットアップ方法と自動計測を有効にする方法については、.NET Framework セットアップ方法または .NET Core セットアップ方法を参照してください。

このページでは、Datadog APM で可観測性を追加・カスタマイズするための一般的なユースケースを詳しく説明します。サポートされているランタイムの一覧は、.NET Framework 互換性要件または .NET Core 互換性要件を参照してください。

以下の手順を実行するには、1 つまたは複数のライブラリに NuGet パッケージの参照を追加する必要がある場合があります。

  • Datadog.Trace NuGet パッケージ: このライブラリはトレーサーとアクティブスパンに直接アクセスするための API を提供します。注: NuGet パッケージの Datadog.Trace と自動インスツルメンテーションを同時に使用する場合、バージョンを同期させることが重要です。
  • Datadog.Trace.Annotations NuGet パッケージ: このライブラリは、コードに適用して追加の自動インスツルメンテーション機能を有効にすることができる .NET 属性を提供します。

ddtrace ライブラリの機能性を拡張したり、アプリケーションのインスツルメントをより精確に制御するのに役立つ方法がライブラリにあります。

カスタムスパンタグスパンに追加して、Datadog 内の可観測性をカスタマイズします。スパンタグは受信トレースに適用されるため、観測された動作を、マーチャントの階層、チェックアウト金額、ユーザー ID などのコードレベルの情報と関連付けることができます。

カスタムスパンタグを追加する

注: この機能を使用するには、アプリケーションに `Datadog.Trace` NuGet パッケージを追加することが必須です。

customer.id などのアプリケーションコード内の動的な値に対応するカスタムタグをスパンに追加します。

using Datadog.Trace;

public class ShoppingCartController : Controller
{
    private IShoppingCartRepository _shoppingCartRepository;

    [HttpGet]
    public IActionResult Index(int customerId)
    {
        // グローバルトレーサーでアクティブスコープにアクセスする
        // 注: アクティブなスパンが存在しない場合は null を返すことがあります
        var scope = Tracer.Instance.ActiveScope;

        if (scope != null)
        {
            // Datadog の Web UI で使用するためのタグをスパンに追加する
            scope.Span.SetTag("customer.id", customerId.ToString());
        }

        var cart = _shoppingCartRepository.Get(customerId);

        return View(cart);
    }
}

すべてのスパンにグローバルにタグを追加する

DD_TAGS 環境変数を使用して、アプリケーションに対して生成されたすべてのスパンにタグを設定します。これは、アプリケーション、データセンター、地域など、Datadog UI 内で統計データをグループ化するのに役立ちます。

DD_TAGS=datacenter:njc,key2:value2

スパンにエラーを設定する

注: この機能を使用するには、アプリケーションに `Datadog.Trace` NuGet パッケージを追加することが必須です。

コードで発生したエラーをマークするには、Span.SetException(Exception) メソッドを利用します。このメソッドは、スパンをエラーとしてマークし、関連するスパンメタデータを追加して、例外の情報を提供します。

try
{
    // 例外をスローする可能性のある作業を行います
}
catch(Exception e)
{
    span.SetException(e);
}

これで、3 つのタグがスパンに設定されます。 "error.msg":exception.Message, "error.stack":exception.ToString(), and "error.type":exception.GetType().ToString().

タグの追加

.NET Framework または .NET Core に対して対応するフレームワークインスツルメンテーションを使用しない場合や、より深いアプリケーションのトレースをする場合、完全なフレームグラフのため、またはコードの断片の実行時間を測定するために、コードにカスタムインスツルメンテーションを追加できます。

アプリケーションコードの変更が不可能な場合は、環境変数 DD_TRACE_METHODS を使用してこれらのメソッドの詳細を記述します。

既存の [Trace] または同様の属性がある場合、または属性を使用して Datadog 内の不完全なトレースを完了する場合は、トレースアノテーションを使用します。

構成によるインスツルメントメソッド

注: この機能を使用するには、アプリケーションの自動インスツルメンテーションを有効にすることが必須です。

環境変数 DD_TRACE_METHODS を使用すると、アプリケーションコードを変更せずに、サポートされていないフレームワークを視覚化することができます。入力フォーマットに関する完全な詳細については、.NET Framework セットアップ手順または .NET Core セットアップ手順を参照してください。次の例では、インスツルメントしたいメソッドの名前が SaveSession で、そのメソッドが Store.Managers.SessionManager タイプで定義されていると仮定します。

DD_TRACE_METHODS=Store.Managers.SessionManager[SaveSession]

この結果、スパンには operationNametrace.annotation に、resourceNameSaveSession に設定されます。もし、スパンの属性をカスタマイズしたい場合で、ソースコードを変更できるのであれば、代わりに属性によってメソッドをインスツルメントすることができます。

属性によるインスツルメントメソッド

注: この機能を使用するには、`Datadog.Trace.Annotations` NuGet パッケージを追加し、アプリケーションの自動インスツルメンテーションを有効にすることが必須です。

Datadog が自動インスツルメンテーションを行う際に、メソッドに [Trace] を追加し、トレースするようにします。自動インスツルメンテーションが有効でない場合、この属性はアプリケーションに何の影響も及ぼしません。

[Trace] 属性はデフォルトのオペレーション名 trace.annotation とトレースされるメソッドのリソース名を持っています。これらは [Trace] 属性の名前付き引数として設定することで、インスツルメンテーションされる内容をより良く反映させることができます。[Trace] 属性に設定できる引数は、オペレーション名とリソース名のみです。

using Datadog.Trace.Annotations;

namespace Store.Managers
{
    public class SessionManager
    {
        [Trace(OperationName = "database.persist", ResourceName = "SessionManager.SaveSession")]
        public static void SaveSession()
        {
            // ここにメソッドの実装
        }
    }
}

新しいスパンを手動で作成する

注: この機能を使用するには、アプリケーションに `Datadog.Trace` NuGet パッケージを追加することが必須です。

自動インスツルメンテーション、[Trace] 属性、DD_TRACE_METHODS コンフィギュレーションに加えて、プログラムでコードのブロックの周囲にスパンを作成することで、可観測性をカスタマイズできます。この方法で作成されたスパンは、他のトレースメカニズムと自動的に統合されます。つまり、トレースがすでに開始されている場合、手動スパンはその親スパンとして呼び出し元を持ちます。同様に、コードのラップされたブロックから呼び出されたトレースメソッドは、その親として手動スパンを持ちます。

using (var parentScope =
       Tracer.Instance.StartActive("manual.sortorders"))
{
    parentScope.Span.ResourceName = "<RESOURCE NAME>";
    using (var childScope =
           Tracer.Instance.StartActive("manual.sortorders.child"))
    {
        // トレースするコードの周囲にあるステートメントを使用してネストします
        childScope.Span.ResourceName = "<RESOURCE NAME>";
        SortOrders();
    }
}

トレースクライアントと Agent コンフィギュレーション

ヘッダーの抽出と挿入

Datadog APM トレーサーは、分散型トレーシングのための B3W3C のヘッダー抽出と注入をサポートしています。詳細については、セットアップドキュメントを参照してください。

ほとんどの場合、ヘッダーの抽出と注入は透過的に行われます。しかし、分散トレースが切断される可能性があるケースも知られています。例えば、分散キューからメッセージを読み込むとき、ライブラリによってはスパンコンテキストを失うことがあります。そのような場合、以下のコードを使ってカスタムトレースを追加することができます。

var spanContextExtractor = new SpanContextExtractor();
var parentContext = spanContextExtractor.Extract(headers, (headers, key) => GetHeaderValues(headers, key));
var spanCreationSettings = new SpanCreationSettings() { Parent = parentContext };
using var scope = Tracer.Instance.StartActive("operation", spanCreationSettings);

GetHeaderValues メソッドを提供します。このメソッドの実装方法は、SpanContext を保持する構造に依存します。

以下はその例です。

// Confluent.Kafka
IEnumerable<string> GetHeaderValues(Headers headers, string name)
{
    if (headers.TryGetLastBytes(name, out var bytes))
    {
        try
        {
            return new[] { Encoding.UTF8.GetString(bytes) };
        }
        catch (Exception)
        {
            // 無視
        }
    }

    return Enumerable.Empty<string>();
}

// RabbitMQ
IEnumerable<string> GetHeaderValues(IDictionary<string, object> headers, string name)
{
    if (headers.TryGetValue(name, out object value) && value is byte[] bytes)
    {
        return new[] { Encoding.UTF8.GetString(bytes) };
    }

    return Enumerable.Empty<string>();
}

Kafka コンシューマースパンをトレースするために SpanContextExtractor API を使用する場合、DD_TRACE_KAFKA_CREATE_CONSUMER_SCOPE_ENABLEDfalse に設定します。これにより、メッセージがトピックから消費された直後にコンシューマースパンが正しく閉じられ、メタデータ (partitionoffset など) が正しく記録されることが保証されます。SpanContextExtractor API を使用して Kafka メッセージから作成されたスパンは、プロデューサーのスパンの子であり、コンシューマーのスパンの兄弟になります。

リソースのフィルター

リソース名に基づいてトレースを除外することで、ヘルスチェックなどの Synthetic トラフィックを削除することができます。セキュリティや追加構成については、データセキュリティのための Datadog Agent またはトレーサーの構成を参照してください。