Redashから始める計測生活

Misoca開発チームの黒曜(@kokuyouwind)です。

先週の土曜日に富山Burikaigi 2020でパターンマッチの話をしてきました。

M@S寿司… もとい鱒寿司も食べられたので満足です。

📊 社内Redash

去年の開発合宿で社内Redashが立ち上がり、現在では社内KGI/KPIやSREチームのSLOなど、いろいろな指標の可視化に活用されています。

tech.misoca.jp

tech.misoca.jp

とはいえ、もっといろいろなものを測りたくなってきますよね。

🤖 リリース準備にかかる時間の計測

リリース準備にかかる時間が意外と長いのでは? またリリース前のトラブルが多いのでは? という問題意識があり、これをRedashで可視化したくなりました。

Misocaでは現在、以下のような流れでリリース準備が行われています。

  1. Slackの特定チャンネルで「リリースしたい」と発言する
  2. 以下の2つが並列で起動する
    1. リリース前のテストジョブ(Jenkins)
    2. ステージング環境へのデプロイ(CodePipeline)
  3. 2b. が終わったらビジュアルリグレッションテストのジョブが起動する(Jenkins)
  4. 2a.3.のジョブが両方完了したらリリース準備完了
    • それぞれのジョブ完了はSlackに通知される

順序を図にすると以下のような流れです。

f:id:kokuyouwind:20200129183113p:plain

「リリース準備にかかる時間」は1.から4.までの時間ですが、いくつかのツールをまたいでいるため、どうやって計測するかという問題がありました。

🐍 Python Data Source

ここで1.4.はどちらもSlackを介しているため、Slackの発言時刻を使えば簡単に計測できるのでは? と思いつきました。

RedashにはPythonデータソースがあるので、Slack APIを叩くことができますね。

ただしPythonデータソースはオンプレミスでないと利用できず事前の設定も必要なので、データ加工が必要なければJSON data sourceを使うほうが良いかもしれません。

例えば #release チャンネルで「リリースしたい」と発言した時刻を集めるためのクエリコードは以下のようになります。

import requests
import json
import datetime
import re

url = "https://slack.com/api/search.messages"
token = "(your_token)"
payload = {
    "token": token,
    "query": 'in:#release "リリースしたい"',
    "sort": "timestamp",
    "count": 100
}
response = requests.get(url, params=payload)

json_data = response.json()
messages = json_data["messages"]["matches"]
result = {}

for i in messages:
    add_result_row(result, {
        'datetime': datetime.datetime.utcfromtimestamp(float(i["ts"]))
    })
add_result_column(result, 'datetime', '', 'datetime')

これで「リリースしたいと発言した時刻」だけが入ったテーブルができあがります。

UTCになっていますが、これは後でJSTに補正します。

f:id:kokuyouwind:20200129184900p:plain

同じように「リリース前のテストが完了した時刻」と「ビジュアルリグレッションテストが完了した時刻」もそれぞれクエリを作ります。

💻 Query Resultデータソース

この3つが取れれば、あとは「リリースしたいと発言した時刻」に対して、それ以降で最も近い「リリース前のテストが完了した時刻」と「ビジュアルリグレッションテストが完了した時刻」を対応づければ「リリース準備にかかった時間」を計算することができます。

こちらはQuery Resultデータソースを利用すれば書くことができます。

SELECT
    datetime(release_start_time,"+9 hour") as jst,
    *,
    (strftime("%s", test_finish_time) - strftime("%s", release_start_time)) as test_duration,
    (strftime("%s", visual_finish_time) - strftime("%s", release_start_time)) as visual_duration,
    MAX(
        strftime("%s", test_finish_time) - strftime("%s", release_start_time),
        strftime("%s", visual_finish_time) - strftime("%s", release_start_time)
    ) AS prepare_duration
FROM (
    SELECT
        release_start.datetime as release_start_time,
        (
            SELECT test_finish.datetime
            FROM query_2 as test_finish
            WHERE test_finish.datetime > release_start.datetime
            ORDER BY test_finish.datetime ASC
            LIMIT 1
        ) as test_finish_time,
        (
            SELECT visual_finish.datetime
            FROM query_3 as visual_finish
            WHERE visual_finish.datetime > release_start.datetime
            ORDER BY visual_finish.datetime ASC
            LIMIT 1
        ) as visual_finish_time
    FROM query_1 as release_start
    WHERE test_finish_time IS NOT NULL
    AND visual_finish_time IS NOT NULL
) as t

ここで、query_xはそれぞれ以下のクエリです。

  • query_1: リリースしたいと発言した時刻
  • query_2: リリース前のテストが完了した時刻
  • query_3: ビジュアルリグレッションテストが完了した時刻

「ある時刻以降で直近のレコード」を取るためにサブクエリを使う必要があったり、JSTに補正したりといった部分で複雑になっていますが、基本的にはquery_1をベースに情報を混ぜているだけになっています。

これで「リリース準備にかかる時間」を可視化できるようになりました!

f:id:kokuyouwind:20200130113909p:plain

縦軸は隠していますが、たまにリリーストラブルが起こり準備完了までにものすごく時間がかかっていることがわかりますね。

よくないけどヨシ!

💬 感想

Redashは普通にRDSなどの情報を可視化するだけでも便利ですが、Pythonデータソースを使ってAPIを叩けるようにすると活用の幅がめちゃくちゃ広がって便利でした。

特にSlackを使ったChatOpsをしている場合は、とりあえずSlackに投げておいてAPIから集計・可視化ということができるのは大体何にでも応用できそうです。

📢 宣伝

Misocaでは計測生活したいエンジニアを募集しています!