FIXER cloud.config Tech Blog
Prometheusで辞書形式のメトリクスを持つExporterを作りたい!
2023年08月02日 10時00分更新
本記事はFIXERが提供する「cloud.config Tech Blog」に掲載された「Prometheusで辞書形式でメトリクスを持つようなExporterを作りたい!」を再編集したものです。
PrometheusのExporterは自作することができ、先人が既に簡単な書き方の記事を挙げています。 しかし、タイトルにある通り辞書型のような形式でメトリクスを保持するような方法が記載されているドキュメントは見当たらなかったので、ブログにしてみようと思いました。
動作環境
・macOS
・Ventura 13.2.1
・Go
・1.20.3
・Rancher Desktop
そもそもPrometheusとは? Exporterとは?
Prometheusはざっくり言うと、「メトリック監視のために時系列ごとの値を保存することができるOSS」です。 値の収集はymlで定義されたExporterと呼ばれるものからPrometheus側からスクレイピングをしており、そこで収集したデータを独自の圧縮形式でファイルに保存しています。 Prometheusで収集したデータはPrometheusのウェブUIまたはGrafanaなどの可視化ツールでpromqlと呼ばれるクエリを使うことで値の取得やグラフの描画ができます。
詳しくは公式ドキュメントを参考にしてみてください。
ソースコード
今回はプロセス監視のため、 psコマンドで取得したcpu使用率をアプリケーションのファイルパスをキーとするような辞書型のメトリクスで出力できるようにExporterを実装しました。
package main import ( "flag" "net/http" "os/exec" "strings" "strconv" "time" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" "github.com/prometheus/client_golang/prometheus/promhttp" ) // メトリクスの名前空間用の変数 var namespace = "process" // メトリクス保持をする変数 var cpuUsagePercentGauge = promauto.NewGaugeVec( prometheus.GaugeOpts{ Namespace: namespace, Name: "cpu_usage_percent", Help: "cpu usage percent by process", }, []string{"filename"}, ) // メトリクス収集用の関数 func Collect() { // psコマンドの実行結果を取得 commandResult, _ := exec.Command("/bin/zsh", "-c", "ps aux | awk '{ printf(\"%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s\\n\",$1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11);}'").Output() convertedCommandResult := string(commandResult) convertedCommandResultArray := strings.Split(convertedCommandResult, "\n") // 取得した実行結果からアプリケーションのファイルパスをキーとしてcpu使用率を代入 for i := 0; i < len(convertedCommandResultArray) - 1; i++ { row := strings.Split(convertedCommandResultArray[i + 1], ",") if len(row) > 10 { cpuUsagePercent, _ := strconv.ParseFloat(row[2], 64) fileName := row[10] cpuUsagePercentGauge.With(prometheus.Labels{"filename": fileName}).Set(cpuUsagePercent) } } } func main() { flag.Parse() // 並列処理で無限ループ go func() { for { // メトリクス収集 Collect() // 一度メトリクス収集してから30秒待つ time.Sleep(30 * time.Second) } }() // localhost:8191で待機 http.Handle("/metrics", promhttp.Handler()) http.ListenAndServe(":8191", nil) Collect() }
環境構築
Exporter
作成したソースコードをビルドして実行ファイルを生成した後、コマンドラインで実行しておけばExporter側の準備は完了です。
Prometheus
予め適当なディレクトリにprometheus.ymlを配置しておきます。
global: scrape_interval: 15s evaluation_interval: 15s scrape_configs: - job_name: 'process_exporter' static_configs: - targets: ['host.docker.internal:8191']
その後また別のディレクトリでdocker-compose.ymlを配置します。
version: '3' services: prometheus: image: prom/prometheus container_name: prometheus volumes: - /path/to/prometheus.yml:/etc/prometheus/prometheus.yml ports: - 9090:9090
最後にdocker-compose.ymlを配置したディレクトリで下記コマンドを実行すればPrometheus側の準備は完了です。
実行結果
http://localhost:9090 をブラウザーで開いた後、クエリの入力欄にprocess_cpu_usage_percentと入力してExecuteボタンを押せば確認できます。
また、クエリを編集すれば出力するプロセスの絞り込みができたり、関数を使って合計値をグラフで出力することも可能です。
感想
今回はローカルマシンでプロセスを監視しましたが、VM上で実行すればVMのプロセスを監視できるはずです。加えて、外部からPrometheusにアクセスできるようにすればわざわざVMに接続してタスクマネージャーなどを開かなくてもウェブ上から閲覧できます。そういう仕組みづくりができればVMの負荷が高騰した時もどのプロセスが原因なのか後から調査する場合でも対応ができるようになると思います。
こういった仕組みづくりはやっぱり好きだなぁとコードを書いていてしみじみ思いました。
三上柊悟/FIXER
開発したり運用したりしてる人。好物はメロンパン。
この連載の記事
-
TECH
Github Copilot Chatをさらに便利にする3つの機能 -
TECH
GTM経由でカスタムディメンションを取得するTypeScript -
TECH
Grafana Tempo×OpenTelemetryの導入方法 -
TECH
Grafana TempoとLokiの連携で進化するログ解析とトレーシング -
TECH
「Microsoft 365開発者プログラム」のアクティベーション方法 -
TECH
サインインなしでも使える! 開発者向けAI検索エンジン「Phind」をご紹介 -
TECH
え、高級言語しか触ったことないのにCPUを自作するんですか!? -
TECH
Github Copilotで、コミットメッセージもAIに考えてもらう方法 -
TECH
Terraform 1.5から追加されたimportブロックがすごい!! -
TECH
はじめてのOSSコントリビュートで“推しからのリプ”をもらった話 - この連載の一覧へ