Datadog APM について

See metrics from all of your apps, tools & services in one place with Datadog's cloud monitoring as a service solution. Try it for free.

www.datadoghq.com

NewRelic や X-Ray とか Application Insights 等の Application Performance Monitoring なソリューション。お仕事ではとある案件で Datadog APM を実戦投入していて、Datadog APM で監視していた内容でアプリケーションのチューニングに役立てていたりする。(実際に 10 倍くらいの速度改善が見られた)

この Datadog APM を利用する場合には、アプリケーションに SDK を組み込んで利用することになるが、Datadog がオフィシャルに公開している SDK は以下の言語に限られているのが現状。

しかし、Tracing API が公開されているので Bash からでも利用することが出来るので、シェルスクリプトで作ったアプリケーションのモニタリングも可能になる。

ということで、Tracing API

Tracing API

See metrics from all of your apps, tools & services in one place with Datadog's cloud monitoring as a service solution. Try it for free.

docs.datadoghq.com

俺のサンプル

datadog-TracingAPI-php-sample - Datadog Tracing API Sample for PHP

github.com

  • dd_trace.php が Tracing API を叩く薄いラッパー
  • sample1.php は Tracing API を利用するアプリケーション (適当に sleep を入れているだけ)

仕組み

Tracing API は下図ように Datadog Agent に同梱されている Trace Agent(trace-agent) により提供されている。

Docker コンテナで動かしている Datadog Agent のプロセスを見てみると以下のようなプロセス起動していて、process-agent と trace-agent が Datadog のEndpoint と通信していることが判る。

root@a830e2803aaf:/var/log/datadog# ss -anp| grep tcp
tcp    LISTEN     0      128                    *:17123                 *:*      users:(("python",pid=13,fd=5))
tcp    LISTEN     0      128            127.0.0.1:6062                  *:*      users:(("process-agent",pid=11,fd=4))
tcp    ESTAB      0      0             172.17.0.6:33460     52.55.150.131:443    users:(("process-agent",pid=11,fd=9))
tcp    ESTAB      0      0             172.17.0.6:55856     54.173.78.245:443    users:(("trace-agent",pid=12,fd=7))
tcp    LISTEN     0      128                   :::8126                 :::*      users:(("trace-agent",pid=12,fd=5))
tcp    LISTEN     0      128                   :::17123                :::*      users:(("python",pid=13,fd=4))

ふむふむ。

ちなみに、process-agent はベータ提供 (??) されている機能の為に利用するエージェントのようで、htop みたいにプロセス単位でドリルダウンしてモニタリング出来るようになるようだ。

See metrics from all of your apps, tools & services in one place with Datadog's cloud monitoring as a service solution. Try it for free.

docs.datadoghq.com

Trace されたデータで見る put するデータの構造

sample1.php を何度か実行すると以下のように Datadog にてトレース情報を確認することが出来る。

トレース情報は dd_trace.php の以下のメソッドで Datadog に飛ばしている。

...
        public function generateSpandata($span_name, $span_id, $parent_span_id = NULL, $startTime, $durationTime) {
            $data = array(
                'trace_id' => $this->traceId,
                'span_id' => $span_id,
                'name' => $span_name,
                'resource' => $span_name,
                'type' => $this->Type,
                'start' => intval($startTime * 1000000000),
                'duration' => round($durationTime * 1000000000),
            );
            if (! is_null($parent_span_id)) {
                $data['service'] = $this->serviceName . '-' . $span_name;
                $data['parent_id'] = $parent_span_id;
            } else {
                $data['service'] = $this->serviceName;
            }
            return $data;
        }
...

これを実行すると以下のような JSON データが生成されて Datadog に put されることになる。

[
  [
    {
      "trace_id": 1038524275,
      "span_id": 488372325,
      "name": "step_one_sleep", ... 図中の (3)
      "resource": "step_one_sleep",
      "type": "web",
      "start": 1506841510052099800,
      "duration": 1419700146,
      "service": "sample1.php-step_one_sleep",
      "parent_id": 1824231734
    },
    {
      "trace_id": 1038524275,
      "span_id": 569978220,
      "name": "step_two_sleep", ... 図中の (2)
      "resource": "step_two_sleep",
      "type": "web",
      "start": 1506841511471800000,
      "duration": 1753799915,
      "service": "sample1.php-step_two_sleep",
      "parent_id": 1824231734
    },
    {
      "trace_id": 1038524275,
      "span_id": 1824231734,
      "name": "root_sleep", ... 図中の (1)
      "resource": "root_sleep",
      "type": "web",
      "start": 1506841510052099800,
      "duration": 3173500061,
      "service": "sample1.php"
    }
  ]
]
  • parent_id で指定している ID で複数関数の個々の処理時間と合計の処理時間を上図のように 1 つの Trace として扱いたい場合に指定が必要になる(これが肝だと思う)
  • 上記に合わせて、1 つの Trace として扱いたい場合には trace_id を揃えておく必要がある(上記だと 1038524275 で揃えている)
  • startduration については UNIX タイムを送信する必要がある(ナノ秒)※但し、上記 JSON の duration はマイクロ秒だよな…でも問題無さそう

Datadog へのポスト

生成された JSON は HTTP Put メソッドで Datadog Agent に同梱されている Trace Agent に送信する。sample1.php だと以下の部分。

        public function finish($data) {
            echo json_encode([$data]);
            $endpoint = $this->agentEndpoint;
            $curl = curl_init($endpoint);
            $options = array(
                CURLOPT_HTTPHEADER => array(
                    'Content-Type: application/json',
                ),
                CURLOPT_CUSTOMREQUEST => "PUT",
                CURLOPT_POSTFIELDS => json_encode([$data]),
            );
            curl_setopt_array($curl, $options);
            $result = curl_exec($curl);

            return $result;
        }

正常にリクエストが処理された場合にレスポンスは OK が返却されてステータスコードは 200 を返す。リクエストに異常がある場合には 500 エラーが返却される。

ということで… sample1.php をしばらく流してみると…

以下のように sample1.php をしばらく流しておくと以下のようにトレースデータが出力される。

何となくではあるが、プログラムの処理時間を確認することが出来ているつもり。

最後に

dd-trace-php を使ってみたいかど…

以下のように既にサードパーティ製ではあるが、PHP 向けのクライアントライブラリが公開されていた。

dd-trace-php - Datadog tracing in PHP

github.com

README を参考にして以下のようなサンプルを作ってみたけど…手元の環境では Datadog Agent にデータが送信されてないので何でだろう…何でだろう…。

<?php

require_once __DIR__ . "/vendor/autoload.php";

use DdTrace\Tracer;

$tracer = Tracer::noop();
$span = $tracer->createRootSpan("sleep_test", "sleep_test", "sleep_test");

var_dump($span);
try {
    $rand_sleep_time = rand(1500000,3000000);
    usleep($rand_sleep_time);
    $span->setMeta("sleep_time", $rand_sleep_time);
} catch (RequestException $e) {
    $span->setError($e);
}

$span->finish();
?>

元記事はこちら

Tracing API を PHP で使って少しずつ理解する Datadog APM