チュートリアル: Instana トレースSDKを使用した、カスタム Java HTTP フレームワークへのトレース機能の組み込み
Instana エージェントは多くの Java HTTP フレームワークをサポートしており、ほとんどの場合、Java エージェントを実行すると、すぐに使用可能なトレースがサポートされます。
ただし、サポート対象外の自社開発の HTTP サーバーをご利用の場合は、 Java Trace SDK を使用して、お使いのフレームワークにトレーシング機能を追加することができます。
このチュートリアルでは、その方法を説明します。
サンプル・コード
この custom-http-sample チュートリアルのサンプルコードは、 github.com でご覧いただけます。 これは以下のシナリオを実装します。

この例を実行して http://localhost:8080を開くと、 Hello, Stan!という応答が表示されます。 ただし、Instana で呼び出しを分析すると、トレースが破損していることが分かります。
トレース1: 
トレース2: 
発信要求は、Instana の自動トレースでサポートされる Apache HTTP クライアントを使用して実装されます。 欠けているのは、カスタム HTTP サーバーへの着信( GET
/greeting インバウンドコール)です。
カスタム HTTP サーバーのトレースの有効化
サポート対象のフレームワークの場合、Instana エージェントは Java アプリケーションを自動的にインスツルメントします。 カスタム HTTP サーバーの場合は、いくつかの注釈を追加して、新規スパンを開始するメソッド呼び出しを Instana エージェントに指示する必要があります。
最初に mvn 依存関係を追加します。
<dependency>
<groupId>com.instana</groupId>
<artifactId>instana-java-sdk</artifactId>
<version>1.2.0</version>
</dependency>
次に、カスタム HTTP サーバーで HTTP 要求を処理するメソッドに @Span 注釈を追加します。
@Span(type = Span.Type.ENTRY, value = "my-custom-http-server")
public String apply(Map<String, String> headers) {
// ...
}
この注釈は、 Java エージェントに対して、 ENTRY span(別名 サーバー・スパン) を使用します。
3 番目に、Instana エージェントの configuration.yaml ファイルに以下を追加して、パッケージ com.instana.sample.* 内の Java クラスをスキャンして @Span 注釈を探す必要があることを指示します。
com.instana.plugin.javatrace:
instrumentation:
sdk:
packages:
- 'com.instana.sample'
これで、カスタム・サーバーがインスツルメントされ、/greeting への着信呼び出しから /name への発信呼び出しがトリガーされることが分かります。

ただし、着信コールと発信コールの間でトレース ID の受け渡しが行われないため、トレースはまだ破損したままです。
着信トレース・ヘッダーの処理
Instana は、以下の HTTP ヘッダーを使用して、サービスから次のサービスにトレース情報を渡します。
X-INSTANA-T: トレース IDX-INSTANA-S: 親スパン IDX-INSTANA-L: レベル0は、トレースを抑止する必要があることを意味します。これは、ヘルス・チェックに役立つ場合があります。
カスタマー HTTP サーバーでトレース・コンパクトを相関付けるには、以下のメソッドを GreetingHandler に追加する必要があります。
private void correlateTracing(Map<String, String> request) {
String level = request.remove(SpanSupport.LEVEL);
String traceId = request.remove(SpanSupport.TRACE_ID);
String parentSpanId = request.remove(SpanSupport.SPAN_ID);
if (SpanSupport.SUPPRESS.equals(level)) {
SpanSupport.suppressNext();
} else if (traceId != null && parentSpanId != null) {
SpanSupport.inheritNext(traceId, parentSpanId);
}
}
ヘッダーは評価後に削除され、元のヘッダーのみが残されて、Instana のトレースなしで送信されることになることに注意してください。
ただし、 apply()で correlateTracing() を呼び出すことはできません。これは、 @Span アノテーションを持つメソッドが呼び出される前にヘッダーを評価する必要があるためです。 回避策として、 apply() メソッドの名前を doApply() に変更し、以下のようにステップを追加することができます。
@Override
public String apply(Map<String, String> headers) {
correlateTracing(headers);
return doApply(headers);
}
@Span(type = Span.Type.ENTRY, value = "my-custom-http-server")
private String doApply(Map<String, String> headers) {
// ...
}
これで、curl http://localhost:8080 を実行すると、Instana で完全なトレースが表示されます。

タグの追加
ここまでのところ、my-custom-http-server スパンは、追加の注釈なしの汎用 ENTRY スパンにすぎません。 詳細を見ると、まったく空のように見えます。

アクティブな @Span コンテキスト内で SDK の SpanSupport.annotate() メソッドを呼び出して、現在のスパンに注釈を追加できます。 Instana Java Trace SDKのドキュメントに記載されている OpenTracing's のセマンティック規約の一部をサポートしています。 HTTP の注釈を追加するには、メソッド doApply() の先頭に以下の行を追加してください:
@Span(type = Span.Type.ENTRY, value = SPAN_NAME)
private String doApply(Map<String, String> headers) {
SpanSupport.annotate(Span.Type.ENTRY, SPAN_NAME,"tags.http.url", "http://localhost:8080/greeting");
SpanSupport.annotate(Span.Type.ENTRY, SPAN_NAME,"tags.http.method", "GET");
SpanSupport.annotate(Span.Type.ENTRY, SPAN_NAME,"tags.http.status_code", "200");
// ...
}
これで、カスタム HTTP サーバーの ENTRY スパンの詳細に、指定された HTTP メタデータが表示されます。

クライアントでは Instana の自動トレースでサポートされる Apache HTTP クライアントが使用されるため、Jetty からカスタム HTTP サーバーへの対応する EXIT スパンには、既に HTTP メタデータが含まれています。
スパンへのエラーのマーク付け
いずれかのポイントで、呼び出しにエラーのマークを付けることが必要になる場合があります。 これは、 OpenTracing's のセマンティック規約で指定されているように、タグ error を追加するだけで簡単に実現できます。
SpanSupport.annotate(Span.Type.ENTRY, SPAN_NAME,"tags.error", "true");
この情報を追加することで、Instana で呼び出しがエラーとして視覚化されます。

サマリーと展望
このチュートリアルでは、Instana の分散トレースを使用してカスタム HTTP フレームワークをインスツルメントするために必要な最も重要な API について説明しました。
SDK の詳細については、SDK の JavaDocを参照してください。 例えば、@SpanParam 注釈および @SpanReturn 注釈を使用すると、パラメーターをキャプチャーしたりスパンの追加情報として値を戻したりすることが非常に簡単になります。これは、シナリオによっては SpanSupport.annotate() を明示的に呼び出すよりはるかに便利な場合があります。