TornadoのトレースデータをOneAgent SDKを使ってDynatraceに送信する

概要

PythonのOneAgent SDKを使って、TornadoのトレースデータをDynatraceで送る実装方法を紹介しています。

Dynatraceとは

以下のページを参照してください。

https://www.dynatrace.com/ja/

実装

Python SDKを使った実装を追加します。
この記事では oneagent-sdk のバージョン 1.4.0.20210127.165413 を使用しています。

main()関数, shutdown()コルーチンでSDKの初期化、シャットダウンをしています。

トレースの開始、終了はそれぞれするprepare(), on_finish()メソッドで実装しています。
トレースを計測するコードはコンテキストマネージャを使って書くこともできますが、get()メソッドの中にトレース用の処理を混ぜたくなかったので、このようにしています。

import logging
import random
import signal

import oneagent
import tornado.ioloop
import tornado.web
from oneagent import InitResult
from oneagent.common import WebapplicationInfoHandle
from oneagent.sdk.tracers import IncomingWebRequestTracer


class TestHandler(tornado.web.RequestHandler):
    web_app_info: WebapplicationInfoHandle
    trace: IncomingWebRequestTracer

    def initialize(self) -> None:
        self.web_app_info = oneagent.get_sdk().create_web_application_info(
            virtual_host='localhost',
            application_id='TornadoTutorialApp',
            context_root='/'
        )

    def prepare(self) -> None:
        self.trace = oneagent.get_sdk().trace_incoming_web_request(
            self.web_app_info,
            self.request.full_url(),
            self.request.method,
            self.request.headers,
            self.request.remote_ip,
        )
        # トレーシング開始
        self.trace.start()

    def get(self) -> None:
        self.set_status(random.choice([200, 400, 500]))

    def on_finish(self) -> None:
        self.trace.set_status_code(self.get_status())
        # レスポンスヘッダを取得するIFがないので仕方なく非公開フィールドから取得する
        self.trace.add_response_headers(self._headers)
        self.trace.end()


async def shutdown():
    oneagent.shutdown()
    tornado.ioloop.IOLoop.current().stop()


def shutdown_handler(sig, frame):
    tornado.ioloop.IOLoop.instance().add_callback_from_signal(shutdown)


def main():
    signal.signal(signal.SIGTERM, shutdown_handler)
    signal.signal(signal.SIGINT, shutdown_handler)

    init_result = oneagent.initialize()
    if init_result.status is not InitResult.STATUS_INITIALIZED:
        logging.error(f'Error initializing OneAgent SDK. '
                      f'status = {init_result.status}, '
                      f'error = {init_result.error}')

    app = tornado.web.Application([
        (r'/test', TestHandler),
    ])
    app.listen(8080)
    tornado.ioloop.IOLoop.current().start()


if __name__ == '__main__':
    main()

動作確認

1. Dynatraceのフリートライアルに申し込む

https://www.dynatrace.com/ja/trial/

2. Dynatraceにログインする

https://sso.dynatrace.com/

3. OneAgentをDockerイメージにインストールする

OneAgentはMacをサポートしていないので、Dockerで実行します。

Deploy Dynatrace → Start Installation → Linux とページを辿って、OneAgentをインストールする手順を確認します。以下のURLのXXXXXX部分をDynatraceにログインしたときのURLに変更すると直接アクセスできます。

  • Deploy Dynatrace: https://XXXXXX.live.dynatrace.com/#deploy;gf=all
  • Download Dynatrace OneAgent: https://XXXXXX.live.dynatrace.com/#install;gf=all
  • Download Dynatrace OneAgent for Linux: https://XXXXXX.live.dynatrace.com/#install/agentlinux;gf=all

以下の赤枠で囲われた部分のURLとAPIトークンを取得します。

Deploy Dynatrace OneAgent as a Docker container に公式のイメージでコンテナを起動する方法が書かれているのですが、エラーを出さずに再起動を繰り返してうまくいかなかったので、上の手順を元にOneAgentを同梱したDockerイメージを作成します。

ARG PYTHOD_TAG=3.9.5-slim
FROM python:${PYTHOD_TAG} AS build-env
# FROMの上に書くと読み込まれない
ARG PACKAGE_PATH=/tmp/tornado-tutorial.tgz
COPY . /tmp/
WORKDIR /tmp
RUN python3 setup.py sdist
RUN mv /tmp/dist/tornado-tutorial-*.tar.gz ${PACKAGE_PATH}

FROM python:${PYTHOD_TAG}

ARG ONEAGENT_INSTALLER_SCRIPT_URL
ARG ONEAGENT_INSTALLER_DOWNLOAD_TOKEN
RUN apt-get update && \
    apt-get install -y wget && \
    wget -O Dynatrace-OneAgent-Linux-1.215.163.sh "${ONEAGENT_INSTALLER_SCRIPT_URL}" --header="Authorization: Api-Token ${ONEAGENT_INSTALLER_DOWNLOAD_TOKEN}" && \
    wget https://ca.dynatrace.com/dt-root.cert.pem ; ( echo 'Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg="sha-256"; boundary="--SIGNED-INSTALLER"'; echo ; echo ; echo '----SIGNED-INSTALLER' ; cat Dynatrace-OneAgent-Linux-1.215.163.sh ) | openssl cms -verify -CAfile dt-root.cert.pem > /dev/null && \
    /bin/sh Dynatrace-OneAgent-Linux-1.215.163.sh && \
    rm Dynatrace-OneAgent-Linux-1.215.163.sh && \
    apt remove -y --purge wget && \
    apt clean -y

# build-envと同じ変数, 値だが書く必要がある
ARG PACKAGE_PATH=/tmp/tornado-tutorial.tgz
COPY --from=build-env ${PACKAGE_PATH} ${PACKAGE_PATH}
RUN pip install ${PACKAGE_PATH}

ENTRYPOINT ["tutorial_server"]
docker image build -t tornado-tutorial \
    --build-arg 'ONEAGENT_INSTALLER_SCRIPT_URL=(ダウンロードURL)' \
    --build-arg 'ONEAGENT_INSTALLER_DOWNLOAD_TOKEN=(APIトークン)' \
    --file Dockerfile.dynatrace .

4. Dockerコンテナを実行する

docker run -p 8080:8080 --name tornado-tutorial -d --rm tornado-tutorial

5. Tornadoにリクエストを投げる

Dynatraceにグラフが表示されるようにするため、トレースするコードを実装した GET /test にしばらくリクエストを流し続けます。

while true; do curl localhost:8080/test; sleep 1; done

6. Dynatraceで確認する

左サイドバーの Transactions and services を選択すると、アプリケーションIDに設定したTornadoTutorialApp が見つかり、トレースデータが送られてきていることが確認できました。

まとめ

PythonのOneAgent SDKを使って、TornadoのトレースデータをDynatraceで確認することができました。

参考

コメントする