継続は力なり

タイトル通り定期的な更新を心掛けるブログです。

Python を使ってサービスメトリクスを投稿して可視化する

タダです.

以前フロントエンドの計測指標として Lighthouse の実行結果を Mackerel のサービスメトリクスに投稿して可視化しました.今回はバックエンドの API 計測指標としてパス毎のレスポンスタイム を Mackerel のサービスメトリクスに定期投稿して可視化したのでこの記事にまとめます.

sadayoshi-tada.hatenablog.com

レスポンスタイム の数値収集

自分が担当しているバックエンドの API は ALB -> ECS -> DB といった構成になっています.そこで ALB のアクセスログを S3 に出力して Athena からクエリを発行し,パス毎のレスポンスタイムを収集しました.

Mackerel への定期投稿

Mackerel への定期投稿はフロントエンドと同じで GitHub Actions で行うことにして,サービスメトリクスへデータを送るのは Python でコードを作成しました.Athena の実行結果をとってきてその要素分を繰り返して Mackerel に投稿するようなコードになっています.

コード例

# -*- coding: utf-8 -*-
import urllib.request
import json
import time 
import requests
import os

headers = {"content-type": "application/json"}
res = urllib.request.urlopen(url)
data = json.loads(res.read().decode('utf-8'))
n = len(data["xxx"]["xxx"]["rows"])

for count in range(n):
    hoge_data = data["xxx"]["xxx"]["rows"][count]['hoge']
    hoge2_data = data["xxx"]["xxx"]["rows"][count]['hoge2']

    if count == 0:
        metrics = [
            {
                "name": "api_response.hoge", 
                "time": int(time.time()), 
                "value": hoge_data
            }, 
            {
                "name": "api_response.hoge2", 
                "time": int(time.time()),
                "value": hoge2_data
            }
        ]
        requests.post(
            'https://mackerel.io/api/v0/services/[サービス名]/tsdb', 
            json.dumps(metrics).encode("utf-8"),
            headers={'Content-Type': 'application/json', 'X-Api-Key': os.environ.get('MACKEREL_API_KEY')}
        )
    ~中略~
    else:
        print('Mackerel Service Metrics post end.')

GitHub Actions の定義

name: Backend response time record

on:
  schedule:
    - cron: "0 0 * * *"
  workflow_dispatch:

jobs:
  tolly:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
    - name: Set up Python 3.9
      uses: actions/setup-python@v2
      with:
        python-version: "3.9"
    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
    - name: Mackerel Post
      env:
        MACKEREL_API_KEY: ${{ secrets.MACKEREL_API_KEY }}
      run: |
        python backend-slo-count.py
    - name: Slack notify of failure
      if: failure()
      uses: rtCamp/action-slack-notify@v2
      env :
        SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }}
        SLACK_COLOR: '#dc143c'
        SLACK_USERNAME: レスポンスタイム投稿定期実行
        SLACK_ICON_EMOJI: ':done-snaqme:'
        SLACK_TITLE: GitHub Actions失敗
        SLACK_MESSAGE: 失敗です 

Mackerel への投稿結果

Mackerel に投稿されるとサービスメトリクスでグラフで表示されます.

サービスメトリクス投稿イメージ f:id:sadayoshi_tada:20211226115912p:plain

レスポンスタイムの数値を収集したら可視化してみます.フロント同様に式監視を使って表示してみます.全件リクエストから SLO の値を超えたリクエスト数の割合を出すようにしました.

式監視のイメージ

movingAverage(scale(divide(sum(service(
      'サービス名',
      'api_response.*_hoge'
    )),
  sum(service(
      'サービス名',
'api_response.*_hoge2'
    ))
    ),100),1w)

f:id:sadayoshi_tada:20211226121412p:plain

式監視で数値で出せたので,これをアラートに設定して SLO を超過するような時にアラート通知するようにもできました.

まとめ

API のレスポンスタイムを Mackerel に定期投稿するようにしてみました.当初は自分が手動集計するようになっててトイルになっちゃってたんですが,1つ仕組み化できて良かったです.