Table of Contents
- はじめに
- プラットフォームメトリクスだけでは不十分な理由
- 前提条件
- なぜカスタムメトリクスを送信するのか?
- アプリケーションパフォーマンスの3つの基本メトリクス
- アプリケーションから StatsD メトリクスを送信する
- 実際の現場でチームはどのように活用できるか
- 1: シンプルな StatsD ヘルパーを追加
- 2:アプリ全体でリクエストレイテンシとエラーを計測する
- 3:カスタムアプリケーションイベントをトラッキングする
- Hosted Grafana でメトリクスを確認
- まとめ
はじめに
Heroku はサーバー管理を行うことなく、アプリケーションのデプロイや運用を容易にしてくれます。しかし、アプリケーションが内部でどのように振る舞っているかを理解するためには、計測・監視が必要です。
CPU 使用率、メモリ消費量、ルーターのリクエスト数やステータスといったプラットフォームメトリクスは有用ですが、コードの実行にどれくらい時間がかかっているのか、いつアプリケーションでエラーが発生しているのか、あるいはユーザーが重要な機能を実際に利用しているかどうかまでは分かりません。
本ガイドでは、Hosted Graphite の StatsD エンドポイントを使用して、Heroku アプリケーションからカスタムアプリケーションメトリクスを送信する方法を、いかに簡単に実装できるかをご紹介します。
例として Python / Django の小規模なアプリケーションを使用しますが、Heroku 上で動作するあらゆる言語やフレームワークに同じ考え方を適用できます。
目的は複雑な監視システムを構築することではなく、適切に選んだいくつかのメトリクスだけで、最小限のコード変更にもかかわらず可視性を大幅に向上できることを示すこととなります。ぜひ、ご参考ください。
プラットフォームメトリクスだけでは不十分な理由
Heroku は、ルーターメトリクス、ログドレイン、ランタイムテレメトリを通じて優れた可視性を提供しています。Heroku の Hosted Graphite マーケットプレイスアドオンを有効化すると、これらのメトリクスは自動的に取得できます。
これらのシグナルは、dyno の健全性、リクエスト量、インフラの挙動を理解するうえで不可欠ですが、あくまでアプリケーションの「周辺」で起きていることを示すものであり、アプリケーション内部の挙動までは把握できません。
カスタムアプリケーションメトリクスは、コード内でイベントが発生した瞬間に、構造化された数値データを直接送信することで、こうした見えない部分を補完します。
レイテンシーのタイマーは実際の処理時間を計測し、エラーカウンターは実際の失敗率を反映します。また、イベントメトリクスを使えば、プラットフォームログには現れない意味のあるユーザー行動を捉えることも可能です。
これらのシグナルを組み合わせることで、アプリケーションの状態をより明確かつ実践的に把握できます。Hosted Graphite が提供する既存のメトリクスとカスタムアプリケーションメトリクスを組み合わせることで、オブザーバビリティは完成形となります。
前提条件
開始する前に、以下のものをご用意ください。
Herokuアプリケーション
既存の Heroku アプリケーションが存在している、もしくはデプロイに慣れていることが前提です。本ガイドでは、アプリケーションがすでに Heroku 上で稼働しており、Heroku CLI またはダッシュボードを使って設定変数(Config Vars)を設定できることを想定しています。
Heroku の Hosted Graphite アドオン
Hosted Graphite の API キーおよび Hosted Grafana 環境を取得するために必要です。
この API キーは StatsD エンドポイントへメトリクスを送信する際の認証に使用され、本番環境では Heroku の設定変数として保存する必要があります。
Python と Django
この例では、シンプルな Django アプリケーションを使用します。
ローカル環境で Django アプリを実行でき、Heroku にデプロイできる方であれば、このガイドを問題なく進めることができます。
なぜカスタムメトリクスを送信するのか?
Heroku ではすでに、dyno の CPU 使用率、メモリ消費量、ルーターレベルのリクエスト処理時間など、インフラレベルのメトリクスが提供されています。これらはプラットフォームの健全性を把握するうえで非常に重要ですが、アプリケーション内部で何が起きているかまでは分かりません。
そのギャップを埋めるのが、カスタムアプリケーションメトリクスです。これにより、以下のような疑問に答えられるようになります。
-
アプリケーションはリクエスト処理にどれくらいの時間を使っているのか?
-
ユーザーはサーバー側のエラーに遭遇していないか?
-
先ほどデプロイした新機能は実際に使われているのか?
これらのメトリクスはコードから直接送信されるため、推測に基づくシグナルではなく、実際のアプリケーション挙動を正確に反映します。
アプリケーションパフォーマンスの3つの基本メトリクス
シンプルさを保つため、少ない工数で最大の効果が得られる、以下の3つのメトリクスに焦点を当てます。
1. アプリケーション内リクエストレイテンシ
アプリケーションコードがリクエストを処理するのに要した時間を計測します。Heroku のルーター計測とは独立しており、遅いクエリやブロッキング処理を検知する最も迅速な方法の一つです。
2. アプリケーションエラー率
未処理の例外や 5xx レスポンスをカウントします。問題が発生した際に、明確かつ実用的なシグナルを提供し、アラートにも非常に適しています。
3. カスタムユーザーイベント
ボタンのクリックなど、特定のユーザー操作をトラッキングします。これにより、アプリケーションの健全性と実際のユーザー行動を結びつけることができます。
アプリケーションから StatsD メトリクスを送信する
Hosted Graphite は、Heroku との相性が非常に良い公開 StatsD エンドポイントを提供しています。
メトリクスは UDP 経由で送信されるため、オーバーヘッドが小さく、リクエスト処理をブロックすることもありません。
全体の流れは以下の通りです。
-
アプリケーションが StatsD 形式のメトリクスを生成
-
メトリクスが UDP 経由で Hosted Graphite に送信
-
データが Graphite および Grafana に表示され、可視化やアラートに利用可能
-
エージェントやバックグラウンドワーカーは不要
以下は、statsd.hostedgraphite.com:8125 の公開エンドポイントに対して、ソケット接続を用いて StatsD メトリクスを送信する Python 3 の基本例です。
import socket, ssl
import socket
statsd_host = 'statsd.hostedgraphite.com'
statsd_port = 8125
metric_key = 'YOUR-HG-API-KEY.metric.name'
metric_value = 1.2
metric_message = f"{metric_key}:{metric_value}|c"
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.sendto(metric_message.encode('utf-8'), (statsd_host, statsd_port))
sock.close()
実際の現場でチームはどのように活用できるか
Heroku を基盤とした本番環境では、SRE や DevOps チームが、デプロイ前後の主要な判断材料(シグナル)としてカスタムアプリケーションメトリクスを活用しています。
リクエストレイテンシの推移は新しいリリースの妥当性を迅速に確認するために使われ、エラーカウンターは、ログやユーザーからの報告に明確に現れる前に障害を早期検知するのに役立ちます。
時間の経過とともに、これらのメトリクスは運用上のガードレールの基盤となっていきます。
チームはこれらを用いて、アラートのしきい値を定義し、エラーバジェットを管理し、インフラの健全性ではなく実際のアプリケーション挙動を反映したサービスレベル指標(SLI)を確立します。
また、メトリクスはアプリケーションコードから直接送信されるため、プラットフォーム起因の問題と、アプリケーションレベルのリグレッション(性能劣化や不具合)を切り分けるために必要なコンテキストを提供します。
そして何より重要なのは、この計測方法がシステムの成長に合わせてスケールするという点です。
重要な処理経路が変わったり、新機能が追加されたりした場合でも、コードと一緒にメトリクスを調整できるため、本番環境でサービスが実際に行っていることと、可観測性(Observability)を常に一致させることができます。
1: シンプルな StatsD ヘルパーを追加
まず、StatsD メトリクスを送信するための小さなヘルパーを追加します。
アプリケーション内に新しいファイルを作成してください(例:myapp/hg_statsd.py)。
import os
import socket
STATSD_HOST = "statsd.hostedgraphite.com"
STATSD_PORT = 8125
HG_API_KEY = os.getenv("HG_API_KEY", "<YOUR-HG-API-KEY>")
HG_PREFIX = os.getenv("HG_PREFIX", "demo.heroku_django")
_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
def counter(path, value=1):
key = f"{HG_API_KEY}.{HG_PREFIX}.{path}"
msg = f"{key}:{value}|c"
try:
_sock.sendto(msg.encode("utf-8"), (STATSD_HOST, STATSD_PORT))
except Exception:
pass
def timing_ms(path, value_ms):
key = f"{HG_API_KEY}.{HG_PREFIX}.{path}"
msg = f"{key}:{value_ms:.3f}|ms"
try:
_sock.sendto(msg.encode("utf-8"), (STATSD_HOST, STATSD_PORT))
except Exception:
pass
Hosted Graphite の API キーをお持ちでない場合でも、MetricFire の無料14日間トライアルを開始することで取得できます。
2:アプリ全体でリクエストレイテンシとエラーを計測する
各ルートごとに個別に計測を仕込む代わりに、Django のミドルウェアを使って、レイテンシとエラーを一元的に計測できます。
この方法では、すべてのリクエストに自動的に適用され、ビュー内に計測コードを書かずに済みます。
新しいファイルを作成してください(例:myapp/metrics_middleware.py):
import time
from .hg_statsd import counter, timing_ms
class HostedGraphiteAppMetricsMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
start = time.perf_counter()
response = None
had_exception = False
try:
response = self.get_response(request)
return response
except Exception:
had_exception = True
raise
finally:
elapsed_ms = (time.perf_counter() - start) * 1000.0
timing_ms("app.http.request_latency_ms", elapsed_ms)
status = getattr(response, "status_code", 200) if response else 200
if had_exception or status >= 500:
counter("app.http.errors", 1)
次に、settings.py の MIDDLEWARE セクションに登録します:
MIDDLEWARE = [
"myapp.metrics_middleware.HostedGraphiteAppMetricsMiddleware",
...
]
これで、以下のアプリケーション内タイマーメトリクスが Hosted Graphite に送信されるようになります。
-
app.http.request_latency_ms -
app.http.errors
3:カスタムアプリケーションイベントをトラッキングする
一部のメトリクスは、アプリケーション内の特定のポイントでのみ意味を持ちます。
例えば、ユーザーがボタンをクリックした回数や、特定のワークフローが実行された回数をカウントしたい場合などです。
そのような場合、最もシンプルな方法は、Django のビュー内で直接カウンターをインクリメントすることです。
from django.http import JsonResponse
from .hg_statsd import counter
def demo_click(request):
counter("app.events.button_clicks", 1)
return JsonResponse({"ok": True})
このたった1行の計測コードにより、イベントが発生した瞬間に、構造化された数値データが送信されます。
アプリ内のボタンに組み込むと、例えば次のようになります:
<form action="{% url 'demo_click' %}" method="get">
<button type="submit"">
Click Event
</button>
</form>
Hosted Grafana でメトリクスを確認
Heroku アプリをデプロイし、必要な config var を設定すると、メトリクスはほぼ即座に Hosted Graphite に表示されます。
HG Metrics Search UI で、新しく送信されたメトリクス(例:demo.heroku_django)を確認できます。
その後、HG アプリ内の Dashboards に移動し、Hosted Grafana を開いて、新しいダッシュボードを作成し、メトリクスを表示するためのパネルを追加します。
メトリクスは単純なGraphiteパスであるため、標準的なGraphite/Grafana機能を使用して集計、アラート設定、可視化が可能です。
カスタム ダッシュボード や アラート の作成については、HG の公式ドキュメントをご参照ください。
また、この一連の流れを実際に確認できる分かりやすい動画も用意されています。
まとめ
Heroku アプリにカスタムアプリケーションメトリクスを追加するために、複雑なツールや重い計測基盤は必要ありません。いくつかのポイントを押さえた変更だけで、レイテンシ・エラー・ユーザーイベントといった意味のあるシグナルを、アプリケーションから直接 Hosted Graphite に送信できます。
この軽量なアプローチにより、最も重要なメトリクスから簡単に計測を始め、段階的に可視性を高めていくことが可能です。アプリケーションの成長に合わせて、より深いインサイト、迅速なデバッグ、そして自信を持った運用判断を実現できます。
ぜひ 無料トライアルにサインアップして、インフラおよびアプリケーションの監視を始めてください。また、デモのご予約を通じて、MetricFire チームと直接、監視に関するご相談をしていただくことも可能です。