Prometheus Exporterの神髄:ブラックボックスを「計測可能な資産」に変える技術
オブザーバビリティの真髄は、「システムが何を語るか」ではなく、「我々がシステムから何を聴き出せるか」にある。
Prometheusを単なる「死活監視ツール」として使っているなら、それはフェラーリを買い物カゴ代わりに使うようなものだ。ビジネスの核心であるKPIや、ミドルウェアの内部挙動を可視化できて初めて、我々は「運用」の次元から「エンジニアリング」の次元へ到達できる。
本稿では、レガシーなスクリプトや独自DB、あるいは既存ツールが追い切れない複雑なビジネスロジックを、Prometheusのメトリクスとして昇華させる「Exporter自作」の極意を伝授する。
—
1. なぜ「自作」が必要なのか?
既存のExporter(`node_exporter`など)はあくまで汎用品だ。現場で起きる「なぜか特定のAPIのレスポンスが300msだけ遅延する」「非同期キューの滞留状況がビジネスの成否を分ける」といった事象は、専用のメトリクスを自前で定義しなければ決して見えない。
自作の鉄則:
メトリクスは「事後検知」のためではなく、「推論(インファレンス)」のために作る。何が起きているかではなく、「次に何が起きるか」を予測できる粒度で数値を切り出せ。
—
2. Pythonでの実装:プロトタイピングのスピードを最大化する
まずは手早く、かつ確実に。Pythonの `prometheus_client` は、PoC(概念実証)において無敵だ。
from prometheus_client import start_http_server, Gauge
import time
import random
ラベル設計は慎重に。高カーディナリティ(大量のユニーク値)はPrometheusを殺す
「インスタンスID」や「ユーザーID」をラベルに入れるのは厳禁だ。
REQUEST_QUEUE_SIZE = Gauge(‘app_queue_size_total’, ‘Current items in internal queue’, [‘region’])
def simulate_app_logic():
while True:
# 内部ロジックから取得した値をセット
size = random.randint(0, 100)
REQUEST_QUEUE_SIZE.labels(region=’ap-northeast-1′).set(size)
time.sleep(5)
if __name__ == ‘__main__’:
# 8000番ポートで公開
start_http_server(8000)
simulate_app_logic()
【プロの技】Python開発の加速テクニック
- 神プラグイン: VSCodeの `Pylance` + `Ruff`。`Ruff`は一瞬でコードを整形し、不要なインポートを消し去る。思考を止めないために必須。
- ショートカット: `Cmd+Shift+P` (Mac) から `Python: Select Interpreter` を瞬時に呼び出し、仮想環境を切り替える習慣をつけろ。
—
3. Goでの実装:高パフォーマンスな本番運用へ
Pythonのオーバーヘッドが許されない高頻度メトリクスや、常駐型のExporterにはGoが唯一の解だ。
package main
import (
“net/http”
“github.com/prometheus/client_golang/prometheus”
“github.com/prometheus/client_golang/prometheus/promhttp”
)
// 構造体にまとめるのがGo流のベストプラクティス
var (
opsProcessed = prometheus.NewCounter(prometheus.CounterOpts{
Name: “app_processed_ops_total”,
Help: “The total number of processed events”,
})
)
func init() {
// レジストリへの登録を忘れるな
prometheus.MustRegister(opsProcessed)
}
func main() {
http.Handle(“/metrics”, promhttp.Handler())
// 高並列に耐えるため、標準ライブラリをそのまま使うのが最も堅牢
http.ListenAndServe(“:8080”, nil)
}
【チーム開発のルール】設定共有化のベストプラクティス
- YAML構成: 複雑なExporterの設定は必ずHelm ChartかKustomizeで管理せよ。直書きのYAMLは「技術的負債」の温床だ。
- 命名規則: `[prefix]_[metric_name]_[unit]` の形式を強制せよ(例: `http_request_duration_seconds`)。単位を名前に含めるだけで、監視設計のミスは半分になる。
—
4. Prometheusへのスクレイピング設定
Exporterを動かすだけでは不十分だ。Prometheus側で「誰が・何を・どこから」取るかを明確に定義する。
prometheus.yml
scrape_configs:
- job_name: ‘custom_app_exporter’
scrape_interval: 15s # 5s未満はPrometheusのディスクを圧迫するため推奨しない
static_configs:
- targets: [‘localhost:8080’]
# リラベル設定で環境情報を自動付与するのがプロの流儀
relabel_configs:
- source_labels: [__address__]
target_label: instance
regex: ‘([^:]+)(:[0-9]+)?’
replacement: ‘${1}’
—
最後に:オブザーバビリティの先へ
自作Exporterを作り始めると、必ず直面する問題がある。「メトリクスを取りすぎてPrometheusが重くなる問題」だ。
その時こそ、君が真のアーキテクトに成長する瞬間だ。
1. Histogramを疑え: `Summary`よりも`Histogram`を使い、`le`(less than or equal)バケットの設計を最適化せよ。
2. 高カーディナリティの排除: ログで追うべきデータまでメトリクスにしていないか? ログとメトリクスの役割分担を再定義せよ。
監視とは、ただ眺めることではない。システムの本質をコードで切り出し、暗闇の中に光を当てる作業だ。 今日から君の書く一行が、チームの障害対応時間を1分短縮させることを期待している。