コンテンツにスキップ

ddtrace-api 使用ガイド


Warning

本ケースは ddtrace 対応バージョンを使用してテストしています

前提条件

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 方式を提供しており、より柔軟にビジネスロジックにインスツルメンテーションを施すことができます。

  1. インスツルメンテーションが必要なメソッドに @Trace アノテーションを追加します
    @Trace
    public String apiTrace(){
        return "apiTrace";
    }
  1. 次に gateway メソッドでこれを呼び出します
...
testService.apiTrace();
...
  1. 再起動して、gateway にアクセスします

image.png

注意: インスツルメンテーションを埋め込むということは、アプリケーション起動時に agent が不要という意味ではありません。agent がない場合、@Trace も無効になります。@Trace アノテーションのデフォルトの操作名は trace.annotation であり、トレース対象のメソッドはデフォルトでリソースを持ちます。

名前を変更することもできます

    @Trace(resourceName = "apiTrace",operationName = "apiTrace")
    public String apiTrace(){
        return "apiTrace";
    }

変更後の効果は次のとおりです:

image.png

Baggage を使用してビジネス上の重要なタグをバックエンドリンクで伝搬する

ddtrace は Baggage 方式を提供しています。正確には、ddtrace が OpenTracing の提供する Baggage 機能を使用して、指定したタグをリンク上で伝搬できるようにします。例えば、ユーザー名や役職などの情報を伝搬させ、ユーザー行動の分析を容易にします。

span.setBaggageItem("username","liurui");

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 内にのみ存在します。

customer_tags = ["username", "job"]

3 リクエストを送信する

2つのヘッダー dd-usernamedd-job を持つ gateway リクエストを送信します。システムは dd で始まるヘッダーパラメータを認識し、現在のすべてのリンク span 間で伝搬します。

効果表示

カスタマイズ

カスタム traceId

ベストプラクティスドキュメントを参照してください: <extract + TextMapAdapter を使用したカスタム traceId の実装>

カスタム span

通常、アプリケーションはビジネスロジックに対して例外処理を行います。関連するリンクはエラーとしてマークされない可能性があり、その結果、アプリケーションのエラートレースが正しく統計されないことがあります。一般的には try-catch またはグローバルな例外キャッチが原因です。

このような場合、リンクにマークを付ける処理が必要です。カスタム span を使用してこれらの span をエラー span としてマークし、catch 箇所でマークするだけで済みます。

  1. 以下の方法で現在の span 情報を取得します
final Span span = GlobalTracer.get().activeSpan();
  1. span をエラーとしてマークします
span.setTag(Tags.ERROR, true);

現在のメソッドが 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();
    }

参考ドキュメント

<デモソースコード>

ddtrace 起動パラメータ

フィードバック

このページは役に立ちましたか?