ddtrace-api 使用ガイド¶
Warning
本ケースは ddtrace 対応バージョンを使用してテストしています
前提条件¶
-
DataKit ddtrace コレクター を有効にする
-
Shell を準備
java -javaagent:dd-java-agent-v1.34.0-guance.jar \
-Ddd.service.name=ddtrace-server \
-Ddd.agent.port=9529 \
-jar springboot-ddtrace-server.jar
インストールとデプロイ¶
Maven の pom 依存関係を追加¶
<dependency>
<groupId>com.datadoghq</groupId>
<artifactId>dd-trace-api</artifactId>
<version>1.34.0</version>
</dependency>
<dependency>
<groupId>io.opentracing</groupId>
<artifactId>opentracing-api</artifactId>
<version>0.33.0</version>
</dependency>
<dependency>
<groupId>io.opentracing</groupId>
<artifactId>opentracing-mock</artifactId>
<version>0.33.0</version>
</dependency>
<dependency>
<groupId>io.opentracing</groupId>
<artifactId>opentracing-util</artifactId>
<version>0.33.0</version>
</dependency>
Tracer の取得¶
GlobalTracer を使用して Tracer オブジェクトを取得します
Tracer tracer = GlobalTracer.get();
Tracer を使用して現在の span 情報を取得できます
Span span = tracer.activeSpan();
// tracer オブジェクトを取得
Tracer tracer = GlobalTracer.get();
// 現在の span オブジェクトを取得
Span span = tracer.activeSpan();
if (span!=null) {
// traceId を取得
String traceId = span.context().toTraceId();
// spanId を取得
String spanId = span.context().toSpanId();
}
関数レベルでのインスツルメンテーション¶
dd.trace.methods 方式でメソッドに能動的にインスツルメンテーションを施す以外にも、ddtrace は API 方式を提供しており、より柔軟にビジネスロジックにインスツルメンテーションを施すことができます。
- インスツルメンテーションが必要なメソッドに
@Traceアノテーションを追加します
- 次に
gatewayメソッドでこれを呼び出します
- 再起動して、gateway にアクセスします
注意: インスツルメンテーションを埋め込むということは、アプリケーション起動時に agent が不要という意味ではありません。agent がない場合、
@Traceも無効になります。@Traceアノテーションのデフォルトの操作名はtrace.annotationであり、トレース対象のメソッドはデフォルトでリソースを持ちます。
名前を変更することもできます
@Trace(resourceName = "apiTrace",operationName = "apiTrace")
public String apiTrace(){
return "apiTrace";
}
変更後の効果は次のとおりです:
Baggage を使用してビジネス上の重要なタグをバックエンドリンクで伝搬する¶
ddtrace は Baggage 方式を提供しています。正確には、ddtrace が OpenTracing の提供する Baggage 機能を使用して、指定したタグをリンク上で伝搬できるようにします。例えば、ユーザー名や役職などの情報を伝搬させ、ユーザー行動の分析を容易にします。
1 TraceBaggageFilter の作成¶
TraceBaggageFilter 方式でリクエストをインターセプトし、request header の関連パラメータを Baggage 方式で伝搬します。
package com.zy.observable.ddtrace;
import io.opentracing.Span;
import io.opentracing.util.GlobalTracer;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Enumeration;
/**
* Baggage を使用すると、タグをリンク間で伝搬できます。現在のリクエストヘッダーを取得し、
* 指定されたプレフィックスを持つヘッダーを Baggage として設定します。
* @author liurui
* @date 2022/7/19 14:59
*/
@Component
public class TraceBaggageFilter implements Filter {
/**
* 指定されたプレフィックスを持つヘッダーをリンク間で伝搬します
*/
private static final String PREFIX = "dd-";
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
final Span span = GlobalTracer.get().activeSpan();
if (span != null) {
HttpServletRequest request = (HttpServletRequest)servletRequest;
Enumeration<String> headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()) {
final String header = headerNames.nextElement();
String value = request.getHeader(header);
if (StringUtils.startsWith(header,PREFIX) && StringUtils.isNotBlank(value)){
// Baggage はリンク間で伝搬できますが、通常のタグではできません
span.setBaggageItem(header.replace(PREFIX,""),value);
}
}
}
filterChain.doFilter(servletRequest,servletResponse);
}
}
2 DataKit の設定¶
ここでは DataKit の ddtrace コレクター設定と組み合わせて使用する必要があります。customer_tags 方式でカスタムタグを追加する必要があります。そうしないと、このデータは meta 内にのみ存在します。
3 リクエストを送信する¶
2つのヘッダー dd-username と dd-job を持つ gateway リクエストを送信します。システムは dd で始まるヘッダーパラメータを認識し、現在のすべてのリンク span 間で伝搬します。
効果表示¶
カスタマイズ¶
カスタム traceId¶
ベストプラクティスドキュメントを参照してください: <extract + TextMapAdapter を使用したカスタム traceId の実装>
カスタム span¶
通常、アプリケーションはビジネスロジックに対して例外処理を行います。関連するリンクはエラーとしてマークされない可能性があり、その結果、アプリケーションのエラートレースが正しく統計されないことがあります。一般的には try-catch またはグローバルな例外キャッチが原因です。
このような場合、リンクにマークを付ける処理が必要です。カスタム span を使用してこれらの span をエラー span としてマークし、catch 箇所でマークするだけで済みます。
- 以下の方法で現在の span 情報を取得します
- span をエラーとしてマークします
現在のメソッドが catch ブロック内にある場合、トレース情報も span に出力できます。
エラー span の処理ロジックを共通関数としてグローバルに使用できるようにします。コードは次のとおりです:
private void buildErrorTrace(Exception ex) {
final Span span = GlobalTracer.get().activeSpan();
if (span != null) {
span.setTag(Tags.ERROR, true);
span.log(Collections.singletonMap(Fields.ERROR_OBJECT, ex));
span.setTag(DDTags.ERROR_MSG, ex.getMessage());
span.setTag(DDTags.ERROR_TYPE, ex.getClass().getName());
final StringWriter errorString = new StringWriter();
ex.printStackTrace(new PrintWriter(errorString));
span.setTag(DDTags.ERROR_STACK, errorString.toString());
}
}
呼び出し元のコード
@GetMapping("/gateway")
@ResponseBody
public String gateway(String tag) {
......
try {
if (client) {
httpTemplate.getForEntity("http://" + extraHost + ":8081/client", String.class).getBody();
}
} catch (Exception e) {
buildErrorTrace(e);
}
return httpTemplate.getForEntity(apiUrl + "/billing?tag=" + tag, String.class).getBody();
}
参考ドキュメント¶
<デモソースコード>



