スパンタグを追加し、アプリケーションのパフォーマンスをフィルタリングし、グループ化する

所要時間 7 分

Datadog APM を使用すると、トレースをカスタマイズして、継続的に観察する必要がある追加情報を含めることができます。特定の企業カスタマーのスループットにおけるスパイクや、最も高いレイテンシーの影響を受けているユーザーの確認、または最も多くエラーを生成している共有データベースの特定などが可能になります。

上記の例では、カスタマー ID をトレースに追加し、パフォーマンスが最も遅いカスタマーを特定しています。トレースのカスタマイズは、APM を Datadog の他の機能とシームレスに統合するタグをベースに使用して、スパンに追加されたメタデータの key:value ペアの形式で記述します。

カスタムスパンタグでコードをインスツルメントする

  1. 例に従いコードをインスツルメントします

使用しているプログラミング言語によって、タグを設定してスパンに追加する方法が異なります。

: 作業中のサービスとリソース名をメモしておくと、後で便利です。上記の例では、サービスは Ruby サーバーの web-store、リソース (エンドポイント) は ShoppingCartController#checkout です。

Datadog の UI では、タグを使用してスパンレベルのメタデータを設定します。グローバルトレーサーからアクティブスパンを取得して setTag メソッドでタグを設定することで、自動インスツルメンテーションにカスタムタグを設定できます。

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

@WebServlet
class ShoppingCartServlet extends AbstractHttpServlet {
  @Override
  void doGet(HttpServletRequest req, HttpServletResponse resp) {
    // アクティブスパンを取得
    final Span span = GlobalTracer.get().activeSpan();
    if (span != null) {
      // customer_id -> 254889
      span.setTag("customer.id", customer_id);
    }

    // [...]
  }
}

Datadog の UI は、タグを使用してスパンレベルのメタデータを設定します。グローバルトレーサーからアクティブスパンを取得して set_tag メソッドでタグを設定することで、自動インスツルメンテーションにカスタムタグを設定できます。

from ddtrace import tracer

@app.route('/shopping_cart/<int:customer_id>')
@login_required
def shopping_cart(customer_id):
    # アクティブスパンを取得
    current_span = tracer.current_span()
    if current_span:
        # customer_id -> 254889
        current_span.set_tag('customer.id', customer_id)

    # [...]

Datadog の UI は、タグを使用してスパンレベルのメタデータを設定します。グローバルトレーサーからアクティブスパンを取得して set_tag メソッドでタグを設定することで、自動インスツルメンテーションにカスタムタグを設定できます。

require 'ddtrace'

# get '/shopping_cart/:customer_id', to: 'shopping_cart#index'
class ShoppingCartController < ApplicationController
  # GET /shopping_cart
  def index
    #アクティブスパンを取得し、customer_id -> 254889 を設定します
    Datadog::Tracing.active_span&.set_tag('customer.id', params.permit([:customer_id]))

    # [...]
  end

  # POST /shopping_cart
  def create
    # [...]
  end
end

Datadog の UI は、タグを使用してスパンレベルのメタデータを設定します。グローバルトレーサーからアクティブスパンを取得して SetTag メソッドでタグを設定することで、自動インスツルメンテーションにカスタムタグを設定できます。

package main

import (
    muxtrace "gopkg.in/DataDog/dd-trace-go.v1/contrib/gorilla/mux"

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

func handler(w http.ResponseWriter, r *http.Request) {
    vars := mux.Vars(r)
    // Go Context からアクティブスパンを取得
    if span, ok := tracer.SpanFromContext(r.Context()); ok {
      // customer_id -> 254889
      span.SetTag("customer.id", vars["customerID"])
    }

    // [...]
}

func main() {
    tracer.Start(tracer.WithServiceName("web-store"))
    defer tracer.Stop()
    // 自動インスツルメンテーションを使用
    mux := muxtrace.NewRouter()
    mux.HandleFunc("/shopping_cart/{customerID}", handler)
    http.ListenAndServe(":8080", mux)
}

Datadog の UI では、タグを使用してスパンレベルのメタデータを設定します。グローバルトレーサーからアクティブスパンを取得して setTag メソッドでタグを設定することで、自動インスツルメンテーションにカスタムタグを設定できます。

app.get('/shopping_cart/:customer_id', (req, res) => {
  // アクティブスパンを取得
  const span = tracer.scope().active()
  if (span !== null) {
    // customer_id -> 254889
    span.setTag('customer.id', req.params.customer_id)
  }

  // [...]
})

Span.SetTag() を呼び出すことで、Datadog.Trace.Span オブジェクトにタグを直接追加します。下記に例を示します。

public class ShoppingCartController : Controller
{
    private IShoppingCartRepository _shoppingCartRepository;

    [HttpGet]
    public IActionResult Index(int customerId)
    {
        // グローバルトレーサーからアクティブスパンを取得 (null を返す)
        var scope = Tracer.Instance.ActiveScope;

        if (scope != null)
        {
            // タグをスパンに追加して Datadog ウェブ UI で使用
            scope.Span.SetTag("customer.id", customerId.ToString());
        }

        var cart = _shoppingCartRepository.Get(customerId);

        return View(cart);
    }
}

: アクティブスパンがない場合、Datadog.Trace.Tracer.Instance.ActiveScopenull を返します。

Datadog の UI は、タグを使用してスパンレベルのメタデータを設定します。グローバルトレーサーからアクティブスパンを取得して meta 配列にタグを設定することで、自動インスツルメンテーションにカスタムタグを設定できます。

<?php
  namespace App\Http\Controllers;

  class ShoppingCartController extends Controller
  {
      public shoppingCartAction (Request $request) {
          // 現在のアクティブスパンを取得
          $span = \DDTrace\active_span();
          if (null !== $span) {
              // customer_id -> 254889
              $span->meta['customer_id'] = $request->get('customer_id');
          }

          // [...]
      }
  }
?>
更新したコードをデプロイしてから新しいタグが Datadog の UI に表示されるまで、数分かかることがあります。

Datadog UI を活用してカスタムスパンタグを検索する

  1. サービスページに移動し、タグを追加したサービスをクリックします。リソース表でタグが追加されたところまでスクロールダウンし、特定のリソースをクリックします。トレース表までスクロールダウンします
リソースページ

トレース表には、現在のスコープ (サービス、リソース、時間枠) における全トレースのレイテンシー分布と、各トレースへのリンクが表示されます。期間やエラーコードで表を並べ替えて問題のあるオペレーションや最適化の機会を特定できます。

  1. トレースの 1 つをクリックします。
フレームグラフ

このビューでは、一番上にフレームグラフ、その下に付加情報のウィンドウが表示されます。Datadog のフレームグラフから、リクエストに影響を与える各論理ユニット (スパン) の期間と状態が一目でわかります。フレームグラフは完全にインタラクティブで、ドラッグしてパンしたり、スクロールして拡大縮小したりできます。スパンをクリックすると、ビューの下部にそのスパンの詳細情報が表示されます。

ビューの下部にはトレースや選択したスパンの付加情報が表示されます。デフォルトタグや手作業で追加したタグのすべてをここで確認できます。さらに、ビューを切り替えて関連するホストとログの情報を表示することもできます。

このビューでログを有効化するためには、ログの収集を有効にした後、ログとトレースを紐付ける必要があります。

カスタムスパンタグを Analytics で活用する

  1. **トレースエクスプローラーページ**に移動します。

トレース検索ページでは、関心のある特定のトレースとインデックス化スパンを特定できます。ここでは、時間によってデフォルトタグ (EnvServiceResource など、さまざまなタグ) にフィルターをかけることができます。

  1. 新しいタグが設定されたトレースを探す。トレースを探すには、左側のファセット検索を使用して本ガイドの始めで設定したリソース名を見つけ、そのうちの 1 行をクリックします。

  2. トレースに追加した新しいタグを探します。見つけたらその新しいタグをクリックし、Create facet for @[your facet name] をクリックします (この例では customer_id)。

ファセットメニューの作成

次に、ファセットの表示名とファセット検索での分類場所を決定します。

ファセットモデルの作成

これで、作成したファセットがファセット検索に表示されるようになります。Search facets ボックスを使用すると、ファセットを素早く見つけられます。

  1. Analytics ページに移動します

Analytics は、クエリを作成し無限濃度でトレースの調査を実施できる視覚的ツールです。ファセットを使用して、クエリにフィルターとスコープを設定します。詳細については、トレースエクスプローラーの概要をご確認ください。

  1. サービスファセット一覧で作業中のサービスを選択し、ファセットのステータスで Error を選択したら、group by フィールドで customer_id (またはスパンに追加した他のタグ) を選択します。
  1. クエリから Error を削除し、measure を count * から Durationグラフタイプを Top List に変更します。

これで、平均リクエストが最も遅いカスタマーが表示されます。: カスタマーのパフォーマンスが今後一定の閾値を越えないようにする場合は、このクエリをモニターにエクスポートするか、この視覚的情報をダッシュボードに保存して長期的に監視します。

最後に、表示された情報をクリックして View traces を選択することで、クエリに関連するすべてのトレースを確認できます。

その他の参考資料