ようへいの日々精進XP

よかろうもん

Datadog APM の Python 用クライアント dd-trace-py をざっくりチュートリアルする 〜 ddtrace-run と Patch 編〜

前回は

Sinatra でざっくりと Datadog APM サービスを使ってみました。

inokara.hateblo.jp

今回は

Python 版の Trace Agent を触ってみたいと思います。

github.com

とりあえず、2 回位に分けて書く予定です。

試す環境

既に Datadog Agent が動いている状態です。

$ sudo /etc/init.d/datadog-agent info

...

======================
Trace Agent (v 5.12.2)
======================

  Pid: 23754
  Uptime: 52031 seconds
  Mem alloc: 1766392 bytes

  Hostname: i-xxxxxxxxxxxxxxxx
  Receiver: localhost:8126
  API Endpoints: https://trace.agent.datadoghq.com

  Bytes received (1 min): 0
  Traces received (1 min): 0
  Spans received (1 min): 0

  Bytes sent (1 min): 0
  Traces sent (1 min): 0
  Stats sent (1 min): 0

Python は以下のバージョンを利用しています。

$ python --version
Python 2.7.13

dd-trace-py

導入

導入はとっても簡単です。

$ pip install ddtrace

以上です。

実装

dd-trace-py は Python のメジャーどころな Web Application Framework 及び Database 系のモジュールに対応しています。

Database 系のモジュールについては…

Then let’s patch widely used Python libraries:

と書かれているように、モジュールに Patch を当てる感じになるようです。

コマンドラインツール 〜 ddtrace-run 〜

ddtrace-run

dd-trace-py を導入すると、一緒に ddtrace-run というコマンドも一緒にインストールされます。

$ ddtrace-run -h

Execute the given Python program after configuring it to emit Datadog traces.
Append command line arguments to your program as usual.

Usage: [ENV_VARS] ddtrace-run <my_program>

Available environment variables:

    DATADOG_ENV : override an application's environment (no default)
    DATADOG_TRACE_ENABLED=true|false : override the value of tracer.enabled (default: true)
    DATADOG_TRACE_DEBUG=true|false : override the value of tracer.debug_logging (default: false)
    DATADOG_PATCH_MODULES=module:patch,module:patch... e.g. boto:true,redis:false : override the modules patched for this execution of the program (default: none)
    DATADOG_TRACE_AGENT_HOSTNAME=localhost: override the address of the trace agent host that the default tracer will attempt to submit to  (default: localhost)
    DATADOG_TRACE_AGENT_PORT=8126: override the port that the default tracer will submit to (default: 8126)
    DATADOG_SERVICE_NAME : override the service name to be used for this program (no default)
                           This value is passed through when setting up middleware for web framework integrations.
                           (e.g. pylons, flask, django)
                           For tracing without a web integration, prefer setting the service name in code.

先述のように Patch に対応したモジュールを import した Python プログラムを引数にして実行することで、簡単に Datadog APM 用のメトリクスを送信することが出来ます。

ddtrace-run x sqlite3

以下のような雑な sqlite にアクセスするスクリプトがあったとします。

import sqlite3

db = sqlite3.connect(":memory:")
sql = """
create table users (
  id integer,
  name varchar(10),
  age integer
);
"""
db.execute(sql)
sql = "insert into users values (1, 'foo', 26)"
db.execute(sql)
c = db.cursor()
c.execute("select * from users where id = 1")
for row in c:
    print row

普通に実行すると以下のように出力されます。

$ python trace-demo-sqlite.py
(1, u'foo', 26)

これを ddtrace-run でフックして実行してみます。

$ ddtrace-run python trace-demo-sqlite.py
(1, u'foo', 26)

実行結果にはなにも影響は見られませんが、Datadog APM のコンソールを見ると…

f:id:inokara:20170401091349p:plain

発行されたクエリ等の Trace 情報を確認することが出来ます。

Patch

スクリプトの修正

コマンドラインで実行するようなスクリプトであれば ddtrace-run を利用すれば良いと思いますが、Web アプリケーション等からライブラリとして利用されるアプリケーションの場合には、モジュールに Patch を当てるような感じで dd-trace-py を利用することが出来ます。

ということで、先述の sqlite にアクセスする雑なスクリプトを以下のように修正しました。

import sqlite3
from ddtrace import Pin, patch
patch(sqlite3=True)

db = sqlite3.connect(":memory:")
sql = """
create table users (
  id integer,
  name varchar(10),
  age integer
);
"""
db.execute(sql)
sql = "insert into users values (1, 'foo', 26)"
db.execute(sql)
c = db.cursor()
c.execute("select * from users where id = 1")
for row in c:
    print row

下図のように Datadog APM にデータが送信されていることを確認出来ます。

f:id:inokara:20170401091414p:plain

Pin で任意のメタデータを付与

また、接続オブジェクトに任意のメタデータ送信データに含めたい場合には以下のように Pin を利用することが Service 名を変更することが出来ます。

import sqlite3
from ddtrace import Pin, patch
patch(sqlite3=True)

db3 = sqlite3.connect(":memory:")
Pin.override(db3, service='sqlite2')
sql = """
create table users (
  id integer,
  name varchar(10),
  age integer
);
"""
db3.execute(sql)
sql = "insert into users values (1, 'foo', 26)"
db3.execute(sql)
c = db3.cursor()
c.execute("select * from users where id = 1")
for row in c:
    print row

以下のように Service 名を変更することが出来ました。

f:id:inokara:20170401091424p:plain

ということで

ざっくりと dd-trace-py を触ってみました。

コマンドラインで実行出来るスクリプトであれば ddtrace-run を利用することで、簡単に Datadog APM にメトリクスを送信することが出来そうです。

引き続き、Flask を利用した雑なアプリケーションで dd-trace-py を深掘り出来ればと考えています。