.NET または .NET Core トレース SDK

Instana でのトレースは自動的に行われますが、カスタムコード、特定のアプリケーション領域、または社内コンポーネントについてさらに詳細な情報を得たい場合は、 Instana の「.NET 」または「.NET Core Tracing SDK」をご利用いただけます。

SDK のインストール

Instana .NET または .NET Core 用の SDK を、 nuget.org の公式フィード上で NuGet パッケージとして提供しています。 Instana.Tracing.Core.Sdk を検索して見つけ、プロジェクトに追加します。

独自のコードのトレース

以下の例は、コードに分散トレース機能を追加する方法を示しています。

注: SDKは現在も開発中ですので、アップデートする際は必ずこのページを確認し、最新のAPIを使用するようにしてください。

単純なスパンの作成

メソッド起動をトレースするには、CustomSpan.Create API を使用するのが最も単純な方法です。

public void MyTracedMethod()
{
    using(var span = CustomSpan.Create())
    {
        // your original code here
    }
}
 

上記のコードは、メソッドとその中で費やされた時間を表す中間スパンを作成します。

中間スパンを使用する代わりにエントリー・スパンまたはエグジット・スパンを作成する場合は、コンビニエンス API (エントリー・スパンの場合は CustomSpan.CreateEntry 、エグジット・スパンの場合は CustomSpan.CreateExit と呼ばれる) を使用することができます。

単純なスパンの作成と例外のキャプチャー

メソッド本体の処理中に発生したエラーを、生成されたスパンに注釈として付加したい場合は、次のように ` CustomSpan.SetErrorAPI ` を使用して手動で行うことができます:

public void MyTracedMethod()
{
    using(var span = CustomSpan.Create())
    {
        try
        {
        // your original code here
        }
        catch(Exception e)
        {
            span.SetError(e.ToString());
        }
    }
}
 

より単純で推奨される方法は、代わりに CustomSpan.WrapAction または CustomSpan.Wrap<T> API を使用することです。

public void MyTracedMethod()
{
    using(var span = CustomSpan.Create())
    {
        // setting the second argument to "false" will prevent exceptions from being thrown. Instead they will be
        // captured in the span and swallowed. Setting it to true will let you handle exceptions yourself.
        span.WrapAction(
            ()=>{
                // your original code here
            }, true);
    }
}
 

ラップしたいコードブロックが、その後の処理に必要な値を返す場合は、代わりに APICustomSpan.Wrap<T> を使用してください。

public void MyTracedMethod()
{
    using(var span = CustomSpan.Create())
    {
        // setting the second argument to "false" will prevent exceptions from being thrown. Instead they will be
        // captured in the span and swallowed. Setting it to true will let you handle exceptions yourself.
        bool result = span.Wrap<bool>(
            ()=>{
                // your original code here
                return myBooleanValue;
            }, true);
    }
}
 

これで、エントリー、出口、および中間の作成方法が分かりました。 また、 SetError または WrapAction (または Wrap<T>) のいずれかの API を使用して例外をキャプチャーする方法についても学習しました。

スパンへのデータの追加

スパン自体は、単にタイミング、呼び出しスタック、および名前で構成されます。 ほとんどのシナリオではあまり役に立ちません。 そのため、スパンにデータを追加する必要があります。 スパンには、 CustomSpan クラスが単純な API を提供する Data および Tagsを含めることができます。

public void MyTracedMethod(string userName, string someSuperRelevantData)
{
    using(var span = CustomSpan.Create())
    {
        span.SetData("username", userName);
        span.SetData("relevant", someSuperRelevantData);
        span.WrapAction(
            ()=>{
                // your original code here
            }, true);
    }
}
 

データは Instana のバックエンドに転送されており、 Instana のUIからトレースをダウンロードすることで取得できます。 ただし、ここに表示されているデータは、 Instana のUIには表示されません。

スパンへのタグの追加

SetDataを使用する代わりに、 SetTagを使用することもできます。これは、ストリングの配列をキーとして取り、スパンに渡すデータを階層として構造化するために使用できます。

public void MyTracedMethod(string userName, string someSuperRelevantData)
{
    using(var span = CustomSpan.Create())
    {
        span.SetTag("username", userName);
        span.SetTag("relevant", someSuperRelevantData);
        span.WrapAction(
            ()=>{
                // your original code here
            }, true);
    }
}
 

タグは、「通話の詳細」ビューに直接表示され、「無制限」分析で検索することもできます。

サービスへのカスタム・スパンのマッピング

通常、カスタムスパンを Instana のアプリケーション・パースペクティブ内の論理サービスに関連付けることになりますが、これは APISetServicename を呼び出すだけで簡単に実現できます(引数には文字列を指定するだけです)。 SDKを使用して実装されたエンドポイントを区別するために、 API SetEndpointName を使用して、より詳細なマッピングを行うためのエンドポイントを指定することもできます。

public void MyTracedMethod(string userName, string someSuperRelevantData)
{
    using(var span = CustomSpan.Create())
    {
        span.SetServiceName("AwesomeSDKService");
        span.SetEndpointName("TracingEndpoint");
        .
        .
        .
    }
}
 

すべてのスパンでサービスとエンドポイントを設定できますが、これらの設定は INTERMEDIATE スパンで破棄されます (これらの設定は、直前の ENTRYから継承されます)。

スパン結果をキャプチャする

例えば、計測するメソッドが値を返すとします。 トレースにこの値を指定すると、トラブルシューティングに役立つと想定できます。 SetResult API を入力してください。

public bool MyTracedMethod(string userName, string someSuperRelevantData)
{
    using(var span = CustomSpan.Create())
    {
        bool result = span.Wrap<bool>(
            ()=>{
                // your original code here
                return resultingBoolean;
            }, true);

        span.SetResult(result.ToString());
        return result;
    }
}
 

スパンのネスト

スパンのネストは、あるメソッドを別のメソッドから呼び出すだけで簡単です。 例えば、1 つのメソッドがエントリーとして機能し、その子スパンが中間であると想定できます。

public bool MyTracedEntryMethod(string userName, string someSuperRelevantData)
{
    using(var span = CustomSpan.CreateEntry())
    {
        bool result = span.Wrap<bool>(
            ()=>{
                List<string> data = this.GetSomeDataFromSomewhere();
                // do some heavy processing
                return theResultICameUpWith;
            }, true);

        span.SetResult(result.ToString());
        return result;
    }
}


private List<string> GetSomeDataFromSomewhere()
{
    using(var span = CustomSpan.Create())
    {
        List<string> result = span.WrapAction(
            ()=>{
                // read data from somewhere...
                return theListICameUpWith;
            }, true);

        span.SetResult(result.ToString());
        return result;
    }
}
 

このスパンの結果は、中間スパンを子とするエントリー・スパンです。 技術的には、ネストの深さに制限はありませんが、深い再帰でスパンを作成してはなりません。

分散トレースの distributed の検討

これまで議論されたすべてのスパンは、1 つのサービスに限定されていました。 他のコンポーネントに到達することはなく、他のコンポーネントもそのアクティビティーをトレースしました。 サービス境界を超えて真の分散トレースを実現するには、相関を適用する必要があります。

トレースにおける相関では、出口呼び出しで相関データを設定する方法、およびこのデータを取得して他のコンポーネントの入り口でこのコンテキストを継続する方法について説明します。

この相関を実現するために、 CustomSpan には CustomSpan.CreateExit メソッドと CustomSpan.CreateEntry メソッドの多重定義があります。

CustomSpan.CreateExit メソッドは Action<string, string> を引数として使用できますが、 CustomSpan.CreateEntryFunc<DistributedTraceInformation>を取ります。

たとえば、ある Message クラスがあり、それを呼び出すリモートサービスに渡すとします。

    public class Message
    {
        public Message()
        {
            this.Tags = new Dictionary<string, string>();
        }
        public Dictionary<string, string> Tags { get; private set; }
        public int Payload { get; set; }

        public void AddTag(string tagName, string tagValue)
        {
            this.Tags.Add(tagName, tagValue);
        }
    }
 

メッセージ内の関連する部分は、2 つのストリングを取る AddTag メソッドです。 このメソッドは、 CustomSpan.CreateExitに提供する必要があるシグニチャーです。

CreateExitを呼び出すときにこのメソッドを使用して、 Messageのインスタンスに相関データを書き込みます。

public void MyLocalEntryMethod()
{
    // this methd will create an entry span and then call our method
    // that communicates with the remote-service (and thus create our exit span)
    using(var span = CustomSpan.CreateEntry())
    {
        span.WrapAction(()=>{
            CallRemoteService();
        })
    }
}

public void CallRemoteService()
{
    Message message = new Message();
    using(var exitSpan = CustomSpan.CreateExit(this, message.AddTag))
    {
        exitSpan.WrapAction( ()=>{
            var service = new RemoteService();
            service.ValidateRequest(message);
        }
    }
}
 

そのため、メッセージが service.ValidateRequest(message)への呼び出しでローカル・コンポーネントのスコープを離れると、そのメッセージのタグのリストに相関データが含まれます。 これらのタグが呼び出し先サイトでどのように抽出されるかを確認できます。

public void ValidateRequest(Message message)
{
    using(var span = CustomSpan.CreateEntry(this, ()=>ExtractCorrelationData(message))
    {
        // do whatever this method is supposed to do, we only care for extraction
        // if the correlation-data anyway :-)
    }
}

private DistributedTraceInformation ExtractCorrelationData(Message message)
{
    var dti = new DistributedTraceInformation();
    dti.ParentSpanId = Convert.ToInt64(message.Tags[TracingConstants.ExternalParentSpanIdHeader], 16);
    dti.TraceId = Convert.ToInt64(message.Tags[TracingConstants.ExternalTraceIdHeader], 16);
    return dti;
}
 

メッセージ内の関連する部分は ExtractCorrelationDataです。 出口の作成時に Message.AddTag メソッドを使用したため、SDK は、メッセージをサービスに送信する前に、関連する ID (parent-span-id および trace-id) をメッセージのタグ・リストに書き込みます。

これで、サービスは、タグを読み取ることによって、これらの値を再度抽出できるようになります (前のコードでキーとして使用されている定数によって、これらの値を識別できます)。 作成した DistributedTraceInformationのインスタンスは、新たに作成した出口を既存のトレースに付加するために SDK によって使用されます。 したがって、作成するエントリー・スパンは、ローカル・サービス上の出口に対応するものになります。

トレースの分割

自動化トレースの実行量が多すぎる例や、作成されるトレースが長すぎて理解できない例があります。 例えば、このようなインスタンスは、長期実行バックグラウンド・タスクの進行状況に関するコールバックを介してサーバーがクライアントに更新をプッシュするときに、長二重 WCF 通信で発生する可能性があります。 このような通信により、長いトレースが生成され、 Instana のUIに表示するには長すぎる可能性があります。

このような場合は、トレースを複数のトレースに分割することができます。 具体的には、クライアントへの各コールバックを別個のトレースに分割することができます。 このオプションを使用するには、 CustomSpanCreateEntryForNewTrace を使用して現在のトレースを停止し、その時点から新しいトレースを作成します。 これは、クライアントへの呼び出しの直前に、サーバー・サイドで行うことができます。

var callbackChanell = OperationContext.Current.GetCallbackChannel<IMathResult>();
if (callbackChanell != null)
{
    using (var span = CustomSpan.CreateEntryForNewTrace(this))
    {
        callbackChanell.SendStatusUpdate(new MathArguments() { InParam = args.InParam, Progress = (float)i / args.InParam, Result = generator.Next(1000, 9999) });
    }
}
 

.NET の属性を使用した宣言型SDK

Instana Declarative SDK は、属性ベースのアプローチを通じて、.NET Core アプリケーションにおける自動分散トレーシングを実現します。 `trace` [InstanaTrace] 属性を使用してメソッドを装飾することで、明示的なトレースコードを記述することなくトレースを生成できます。

このSDKは、以下の機能をサポートしています:

  • 設定可能なスパンタイプ(ENTRY、INTERMEDIATE、EXIT)
  • カスタムスパン名
  • メソッドの引数と戻り値の自動取得
  • カスタム・タグ
  • 機密データの自動マスキング機能

インストルメンテーションは、リライトを通じて実行時に透過的に適用されるため、INSTANA_NET_ATTR_SDK_TRACING 環境変数を有効にするだけで済みます。 この宣言型のアプローチにより、煩雑なコーディング作業を省きつつ、トレース動作をきめ細かく制御できるため、高度なトレースの専門知識がなくても、分散システムの可観測性を実現できます。

仕組み

以下の手順では、Declarative SDK の動作について説明します:

  1. 属性を追加する - メソッドに を付与 [InstanaTrace] し、トレースオプションを設定します。
  2. 自動検出 - Instana プロファイラは、実行時にこの属性を検出します。
  3. バイトコードの挿入 - メソッドの周囲にトレースコードが自動的に挿入されます。
  4. spanの生成 - Instana は、spanの生成、データの取得、およびコンテキストの伝播を自動的に処理します。

設定ファイルや手動での設定は一切必要ありません。 属性を追加すると、トレースが機能します。

注: 属性ベースのトレースを有効にするには、環境変数を設定してください INSTANA_NET_ATTR_SDK_TRACING=true

以下の例は、コード内で属性を使用してEntryおよびExitスパンを生成する方法を示しています。

基本エントリのスパン

[InstanaTrace(SpanKind = SpanKind.ENTRY, SpanName = "ProcessOrder")]
public string ProcessOrder(int orderId)
{
    return "Order processed";
}
 

このメソッドに対して、以下のスパンが生成されます:

{
    "sdk.type": "ENTRY",
    "sdk.name": "ProcessOrder",
    "custom.args.orderId": "12345",
    "custom.result": "Order processed"
}
 

サービス情報を表示する出口区間

Exitは、外部サービス、データベース、またはAPIへの発信コールを処理します。 これらはサービス情報を収集し、システム境界を越えた分散トレーシングを可能にします。

[InstanaTrace(
    SpanKind = SpanKind.EXIT,
    ServiceName = "UserService",
    EndpointName = "/api/users/fetch")]
public User GetUser(string userId)
{
    return new User { Id = userId };
}
 

機密データの保護

このSDKは、セキュリティに関連する一般的なキーワードを含むメソッドのパラメータや戻り値を自動的に伏せることで、機密データを保護します。 , secret, token apikey, api_key,, または credentialspassword大文字小文字を区別しない)と一致する名前のパラメータは、キャプチャされたスパンデータ内で自動的に ***REDACTED*** に置き換えられます。 これにより、トレース内の機密情報が誤って公開されるのを防ぎます。

[InstanaTrace]
public bool Authenticate(string username, string password)
{
    return true;
}
 
{
    "custom.args.username": "john_doe",
    "custom.args.password": "[REDACTED]"
}
 

トラブルシューティング

Declarative SDK で問題が発生した場合は、以下の項目を確認してください:

  1. 環境変数が INSTANA_NET_ATTR_SDK_TRACING に設定されている trueことを確認してください。
  2. Instana プロファイラがアプリケーションに正しく接続されていることを確認してください。
  3. プロジェクトでSDKとプロファイラ/リライターのパッケージの両方が参照されていることを確認してください。

スパンが取得されていない場合は、以下の確認を行ってください:

  1. アプリケーションの実行中に、インスツルメンテーションされたメソッドが呼び出されていることを確認してください。
  2. プロファイラのログを確認し、書き換えが正常に行われていることを確認してください。
  3. トレースデータが Instana バックエンドに正しく書き込まれていることを確認してください。

.NET または.NET Core SDKについてご質問がある場合は、 IBM サポートまでお問い合わせください。