引き続き

dd-trace-py - python trace client

github.com

を弄っています。

Elasticsearch でも APM

Elasticsearch でも簡単に始めることが出来ます。もちろん、Amazon Elasticsearch Service でも無問題(IAM の処理が必要となる場合があります)です。尚、dd-trace-py については導入済みという体で進めます。

本記事作成時の環境

本記事を書くにあたり利用した環境は以下の通りです。

$ python --version
Python 2.7.13

$ pip list --format=columns | egrep 'elasticsearch|ddtrace'
ddtrace           0.8.0
elasticsearch     5.3.0

尚、Amazon Elasticsearch Service のアクセスポリシーは IP アドレスによるアクセス制御で利用します。

Python から Elasticsearch を扱う場合

以下のモジュールを利用します。

elasticsearch-py - Official Python low-level client for Elasticsearch.

github.com

Elastic 謹製です。

サンプルアプリケーション

今回は Elasticsearch に読み込ませた 20 万件程度のレストランデータを検索するコマンドラインツールを作ってみたので、そのコマンドラインツールを dd-trace-py を利用して各処理を追跡して可視化してみたいと思います。

gist.github.com

超ざっくりで Elasticsearch のクエリチューニングは一切行っていませんが、一応、以下のように --name--location オプションで指定したキーワードを含むレストランのリストがダーッと標準出力に表示されます。

$ python restaurant-search.py --name '焼き鳥' --location '福岡' 2> /dev/null
焼き鳥 一郎 | 福岡市博多区美野島2-11-14 |
焼き鳥の屋台 花山 | 福岡市東区箱崎1 |
焼き鳥 たかつ 三苫店 | 福岡市東区三苫1-16-44 |
焼き鳥 木鶏 | 福岡市中央区平尾4-5-15日之出第2平尾ビル |
炭火焼き鳥 ちびっこ大将 | 福岡市中央区高砂2-11-33北村コーポ 1F |
焼き鳥 いわた | 福岡市中央区渡辺通5-24-37レジデンス江崎 2F |
博多水炊きと焼き鳥 鳥善 | 福岡市中央区薬院2-15-2ルミエール薬院1F |

ちなみに、レストランデータは[こちら(https://github.com/livedoor/datasets)のデータを利用させて頂き、stream2es で Amazon Elasticsearch Service に放り込んでいます。

Patch

以下のように elasticsearch-py にパッチを当てるだけで Elasticsearch へのクエリを追跡出来るようになります。

from ddtrace import Pin, patch, patch_all
patch(elasticsearch=True)

ソースコードを大幅に手をいれる必要が無いのが嬉しいですね。

tracer.wrap

今回は Elasticsearch へのクエリ以外に、検索処理を担う関数をはじめ、スクリプトの各種関数についてもパフォーマンスをトレースしてみたいと思いますので、tracer.wrap を利用してみたいと思います。
tracer.wrap は関数全体をトレースするデコレータで、以下のように関数の上にちょこんとのっけるだけで、関数の処理結果を Datadog に送信することが出来るようになります。

...
@tracer.wrap('scroll_index', service='sample-app')
def scroll_index(scroll_size, sid):
    try:
        while (scroll_size > 0):
            page = es().scroll(scroll_id=sid, scroll='2m')
            sid = page['_scroll_id']
            scroll_size = len(page['hits']['hits'])
            output(page['hits']['hits'])
    except Exception, e:
        print e
...

ちなみに、デコレータとは対象となる関数をいじることなく、その関数の挙動にてを加える手法という認識で、上記だと scroll_index(scroll_size, sid): という関数に対して、@tracer.wrap という関数でデコレート(装飾)することになります。

さて、今日は何処で呑もうかな、何を食べようかな

やっぱもつ鍋ばい

もつ福岡で検索してみます。

$ python restaurant-search.py --name 'もつ' --location '福岡' 2> /dev/null
もつもつ天神店 | 福岡市中央区天神3−3−5久保田ビル2F |
もつ壙 | 福岡市博多区中洲3-3-3 |
...
...
二十四 永徳屋 博多もつ鍋 | 福岡市博多区美野島1-4-32松永ビル1F |

さすが、もつ鍋王国の博多です。

span = tracer.current_span()
span.set_tag('name', unicode(name, 'utf-8', 'ignore'))

上記のように span.set_tag で Span に対して任意のタグを付与することが出来ます。

福岡で焼肉食べたいばってん、禁煙の席があるといいねえ

もつ福岡 そして禁煙 で検索します。

$ python restaurant-search.py --name '焼肉' --location '福岡' --keyword '禁煙' 2> /dev/null
焼肉処 國 | 福岡市南区野間2-7-13ヴィラージュ野間 1F | 席数 25席 (掘りごたつ4つとカウンター5席)   駐車場 無  予約 予約可  貸切 可 (20人以下可)   禁煙・喫煙 全面喫煙可  カード 不可

一軒しかヒットしないのは寂しいですが、以下のように検索に利用したキーワードが span のタグとして確認することが出来ます。

Elasticsearch の検索が関数の殆どの時間を使っていることがひと目で判ります。

ということで

dd-trace-py を使うことで、アプリケーションの関数毎のパフォーマンスやデータベースへのアクセス時間をソースコードに殆ど手を加える事無く Datadog で監視出来るというのは嬉しい限りです。

元記事はこちら

Datadog APM の Python 用クライアント dd-trace-py をざっくりチュートリアルする 〜 Elasticsearch(Amazon Elasticsearch Service) 編 〜