【実務・中級編】Prometheus exporter自作入門:Go/Pythonでカスタムメトリクスを公開する方法 – 運用監視・オブザーバビリティ活用バイブル

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分短縮させることを期待している。

タイトルとURLをコピーしました