OpenTracing
Datadog の調査レポート: サーバーレスの状態 レポート: サーバーレスの状態

OpenTracing

OpenTracing は、アプリケーションをトレースするためのベンダーに依存しない、言語間の標準です。Datadog は、多くの APM トレーサーに OpenTracing 実装を提供しています。詳細については、opentracing.io を参照してください。

OpenTracing API と Datadog Tracer (dd-trace-ot) ライブラリを使用して、特定のコードの実行時間を測定します。これにより、Java Agent だけでできるよりも正確にアプリケーションをトレースできます。

セットアップ

Maven の場合、これを pom.xml に追加します。

<!-- OpenTracing API -->
<dependency>
    <groupId>io.opentracing</groupId>
    <artifactId>opentracing-api</artifactId>
    <version>0.31.0</version>
</dependency>

<!-- OpenTracing Util -->
<dependency>
    <groupId>io.opentracing</groupId>
    <artifactId>opentracing-util</artifactId>
    <version>0.31.0</version>
</dependency>

<!-- Datadog Tracer(dd-java-agent を使用しない場合にのみ必要) -->
<dependency>
    <groupId>com.datadoghq</groupId>
    <artifactId>dd-trace-ot</artifactId>
    <version>${dd-trace-java.version}</version>
</dependency>

Gradle の場合は、次を追加します:

compile group: 'io.opentracing', name: 'opentracing-api', version: "0.31.0"
compile group: 'io.opentracing', name: 'opentracing-util', version: "0.31.0"
compile group: 'com.datadoghq', name: 'dd-trace-ot', version: "${dd-trace-java.version}"

構成セクションで説明されているように、環境変数またはシステムプロパティを使用してアプリケーションを構成します。

OpenTracing による手動インスツルメンテーション

自動インスツルメンテーションでは十分な深さや詳細が得られない場合は、これらの組み合わせを使用します。

try-finally の使用

import datadog.trace.api.DDTags;

import io.opentracing.Scope;
import io.opentracing.Tracer;
import io.opentracing.util.GlobalTracer;

class InstrumentedClass {

    void method0() {
        /*
         * 1. 環境変数またはシステムプロパティを使用してアプリケーションを構成します
         * 2. dd-java-agent (-javaagent:/path/to/dd-java-agent.jar) を使用すると、
         *    GlobalTracer が自動的にインスタンス化されます。
         */
        Tracer tracer = GlobalTracer.get();

        Scope scope = tracer.buildSpan("<オペレーション名>").startActive(true);
        try {
            scope.span().setTag(DDTags.サービス名, "<サービス名>");

            // トレースしているコード
            Thread.sleep(1000);

        // close() を呼び出さないと、スパンデータは Datadog に到達しません!
        } finally {
            scope.close();
        }
    }
}

または、try-with-resources ステートメントでトレースするコードをラップします。

import datadog.trace.api.DDTags;

import io.opentracing.Scope;
import io.opentracing.Tracer;
import io.opentracing.util.GlobalTracer;

class InstrumentedClass {

    void method0() {
        Tracer tracer = GlobalTracer.get();

        try (Scope scope = tracer.buildSpan("<オペレーション名>").startActive(true)) {
            scope.span().setTag(DDTags.サービス名, "<サービス名>");
            Thread.sleep(1000);
        }
    }
}

この場合、scope.close() を呼び出す必要はありません。

dd-java-agent.jar を使用していない場合は、構成済みのトレーサーを GlobalTracer に登録する必要があります。そのためには、アプリケーションの起動の早い段階(例: メインメソッド)で GlobalTracer.register(new DDTracer()) を呼び出します。

import datadog.opentracing.DDTracer;
import io.opentracing.Tracer;
import io.opentracing.util.GlobalTracer;
import datadog.trace.common.sampling.AllSampler;
import datadog.trace.common.writer.DDAgentWriter;

//API の例の場合
import datadog.trace.common.writer.Writer;
import datadog.trace.common.sampling.Sampler;

public class Application {

    public static void main(String[] args) {

        // 環境変数またはシステムプロパティからトレーサーを初期化します
        DDTracer tracer = new DDTracer();
        GlobalTracer.register(tracer);
        // 同じトレーサーを Datadog API に登録します
        datadog.trace.api.GlobalTracer.registerIfAbsent(tracer);

        // または API から
        Writer writer = new DDAgentWriter();
        Sampler sampler = new AllSampler();
        String service = "Service Name";
        Tracer tracer = new DDTracer(service,writer, sampler);
        GlobalTracer.register(tracer);

        // ...
    }
}

非同期トレースの手動インスツルメンテーション

OpenTracing API を使用して、手動インスツルメンテーションで非同期トレースを作成します。

// ステップ 1: ワーク送信スレッドでスコープ/スパンを開始します
try (Scope scope = tracer.buildSpan("ServiceHandlerSpan").startActive(false)) {
    final Span span = scope.span();
    doAsyncWork(new Runnable() {
        @Override
        public void run() {
            // ステップ 2: ワーカースレッドでスパンを再アクティブ化します
            try (Scope scope = tracer.scopeManager().activate(span, false)) {
              // ワーカースレッドの実装...
            }
        }
    });
    // 送信スレッドの実装...
}

OpenTracing の手動インスツルメンテーションを使用して分散トレースを作成する

// ステップ 1: クライアントコードに Datadog ヘッダーを挿入します
try (Scope scope = tracer.buildSpan("httpClientSpan").startActive(true)) {
    final Span span = scope.span();
    HttpRequest request = /* ここにあなたのコード */;

    tracer.inject(span.context(),
                  Format.Builtin.HTTP_HEADERS,
                  new MyHttpHeadersInjectAdapter(request));

    // HTTP リクエストの実装...
}

public static class MyHttpHeadersInjectAdapter implements TextMap {
  private final HttpRequest httpRequest;

  public HttpHeadersInjectAdapter(final HttpRequest httpRequest) {
    this.httpRequest = httpRequest;
  }

  @Override
  public void put(final String key, final String value) {
    httpRequest.addHeader(key, value);
  }

  @Override
  public Iterator<Map.Entry<String, String>> iterator() {
    throw new UnsupportedOperationException("このクラスは、tracer#inject() でのみ使用する必要があります");
  }
}

// ステップ 2: サーバーコードで Datadog ヘッダーを抽出します
HttpRequest request = /* ここにあなたのコード */;

final SpanContext extractedContext =
  GlobalTracer.get().extract(Format.Builtin.HTTP_HEADERS,
                             new MyHttpRequestExtractAdapter(request));

try (Scope scope = tracer.buildSpan("httpServerSpan").asChildOf(extractedContext).startActive(true)) {
    final Span span = scope.span(); // ステップ 1 の HTTP クライアントスパンの子
    // HTTP サーバーの実装...
}

public class MyHttpRequestExtractAdapter implements TextMap {
  private final HttpRequest request;

  public HttpRequestExtractAdapter(final HttpRequest request) {
    this.request = request;
  }

  @Override
  public Iterator<Map.Entry<String, String>> iterator() {
    return request.headers().iterator();
  }

  @Override
  public void put(final String key, final String value) {
    throw new UnsupportedOperationException("このクラスは、Tracer.extract()! でのみ使用する必要があります");
  }
}

上記の例では OpenTracing クラスのみを使用していることに注意してください。詳細については、OpenTracing API を確認してください。

エラーを設定する

スパンの 1 つに関連するエラーをカスタマイズするには、 io.opentracing.Spanio.opentracing.tag.Tags、および io.opentracing.util.GlobalTracer ライブラリをエラーが発生するメソッドにインポートします。

import io.opentracing.Span;
import io.opentracing.tag.Tags;
import io.opentracing.util.GlobalTracer;

次に、エラーを true に設定し、少なくとも error.msgerror.typeerror.stack タグをスパンに追加します。

    final Span span = GlobalTracer.get().activeSpan();
    if (span != null) {
      Tags.ERROR.set(span, true);
      span.log(Collections.singletonMap(Fields.ERROR_OBJECT, ex));
    }

: トレースビューのドキュメントで説明されている関連エラーメタデータも追加できます。 現在のスパンがルートスパンではない場合、dd-trace-api ライブラリを使用してエラーとしてマークし、MutableSpan でルートスパンを取得してから、setError(true) を使用します。詳細については、ソースコードを参照してください。

セットアップ:

OpenTracing のサポートは ddtrace パッケージに含まれています。pip を使用して、必要な opentracing パッケージをインストールします。

$ pip install ddtrace[opentracing]

使用方法:

トレーサーを初期化するための OpenTracing の規則は、新しいトレーサーを構成、インスタンス化し、グローバルな opentracing.tracer 参照を上書きする初期化メソッドを定義することです。

import time
import opentracing
from ddtrace.opentracer import Tracer, set_global_tracer

def init_tracer(service_name):
    config = {
      'agent_hostname': 'localhost',
      'agent_port': 8126,
    }
    tracer = Tracer(service_name, config=config)
    set_global_tracer(tracer)
    return tracer

def my_operation():
  span = opentracing.tracer.start_span('<オペレーション名>')
  span.set_tag('<タグキー>', '<タグ値>')
  time.sleep(0.05)
  span.finish()

init_tracer('<サービス名>')
my_operation()

より高度な使用法と構成情報については、Datadog Python Opentracing API ドキュメントおよび Python OpenTracing リポジトリを参照してください。

OpenTracing で Datadog をセットアップするには、詳細について Ruby OpenTracing のクイックスタートを参照してください。

Datadog トレーサー設定の構成

基底の Datadog トレーサーは、グローバルトレーサーを構成するときにオプション( Datadog::Tracer と一致)を渡すことで構成できます。

# `options` は Datadog::Tracer に提供されるオプションのハッシュです
OpenTracing.global_tracer = Datadog::OpenTracer::Tracer.new(options)

Ruby トレーサー設定セクションで説明されているように、Datadog.configure を使用して構成することもできます。

インテグレーションのアクティブ化と構成

デフォルトでは、Datadog で OpenTracing を構成しても、Datadog が提供する追加のインスツルメンテーションは自動的にアクティブになりません。アプリケーションにある OpenTracing インスツルメンテーションからのみスパントレースを受け取ります。

ただし、Datadog が提供する追加のインスツルメンテーションは、Datadog.configure を使用して OpenTracing とともにアクティブ化できます。これは、トレースをさらに強化するために使用できます。これを有効にするには、Ruby インテグレーションインスツルメンテーションで詳細をご覧ください。

サポートされているシリアル化形式

種類サポート追加情報
OpenTracing::FORMAT_TEXT_MAPはい
OpenTracing::FORMAT_RACKはいRack 形式では解決が失われるため、大文字または - のいずれかを含む名前のバゲージアイテムは、往復でそれぞれ小文字と _ に変換されることに注意してください。Datadog は、これらの文字を避けるか、受信側でそれに応じて対応することをお勧めします。
OpenTracing::FORMAT_BINARYいいえ

opentracer パッケージをインポートして、Datadog トレーサーを OpenTracing 互換トレーサーとして公開します。

:

基本的な使用例

package main

import (
    "github.com/opentracing/opentracing-go"

    "gopkg.in/DataDog/dd-trace-go.v1/ddtrace/opentracer"
    "gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer"
)

func main() {
    // 通常のトレーサーを起動し、opentracing.Tracer インターフェイスとして返します。
    // Datadog トレーサーで通常使用するのと同じオプションのセットを使用できます。
    t := opentracer.New(tracer.WithServiceName("<サービス名>"))

    // トレーサーパッケージの通常の Stop 呼び出しを使用して停止します。
    defer tracer.Stop()

    // グローバル OpenTracing トレーサーを設定します。
    opentracing.SetGlobalTracer(t)

    // 通常どおり OpenTracing API を使用します。
}

: OpenTracing API を通常の API または Datadog インテグレーションと並行して使用することは完全にサポートされています。内部的には、それらはすべて同じトレーサーを使用します。その他の例と詳細については、API ドキュメントを参照してください。

このライブラリは OpenTracing に準拠しています。(OpenTracing API と Datadog Tracer(dd-trace)ライブラリを使用して、特定のコードの実行時間を測定します。次の例では、Datadog Tracer が初期化され、グローバルトレーサーとして使用されます。

// server.js

const tracer = require('dd-trace').init()
const opentracing = require('opentracing')

opentracing.initGlobalTracer(tracer)

const app = require('./app.js')

// app.js

const tracer = opentracing.globalTracer()

以下のタグを使用して、Datadog 固有のオプションをオーバーライドできます。

  • service.name: このスパンに使用されるサービス名。これを指定しなかった場合、トレーサーからのサービス名が使用されます。
  • resource.name: このスパンに使用されるリソース名。これを指定しなかった場合、オペレーション名が使用されます。
  • span.type: このスパンに使用されるスパンタイプ。指定しなかった場合、スパンタイプは custom にフォールバックします。

OpenTracing をサポートするには、Datadog.Trace.OpenTracing NuGet パッケージをアプリケーションに追加します。アプリケーションの起動時に、OpenTracing ライブラリを初期化します。

using Datadog.Trace.OpenTracing;

public void ConfigureServices(IServiceCollection services)
{
    // デフォルト設定で OpenTracing ITracer を作成します
    OpenTracing.ITracer tracer = OpenTracingTracerFactory.CreateTracer();

    // ASP.NET Core 依存関係の挿入でトレーサーを使用するには
    services.AddSingleton<ITracer>(tracer);

    // OpenTracing.GlobalTracer.Instance でトレーサーを使用するには
    GlobalTracer.Register(tracer);
}

PHP トレーサーは、Composer と共にインストールされる opentracing/opentracing ライブラリを介して OpenTracing をサポートします。

$ composer require opentracing/opentracing:1.0.0-beta5

自動インスツルメンテーションが有効になっている場合、OpenTracing 互換のトレーサーがグローバルトレーサーとして利用可能になります。

<?php
  $otTracer = \OpenTracing\GlobalTracer::get();
  $span = $otTracer->startActiveSpan('web.request')->getSpan();
  $span->setTag('span.type', 'web');
  $span->setTag('http.method', $_SERVER['REQUEST_METHOD']);
  // ...期待どおりに OpenTracing を使用します
?>

Datadog C++ トレーサーは、OpenTracing API を介してのみ使用できます。このドキュメントの使用手順はすべて、一般的な OpenTracing 機能について説明しています。

その他の参考資料