tk_ch’s blog

インフラエンジニアのブログ

Node ExporterのTextfile Collectorで独自メトリクスを収集する

Node Exporterでハードウェア・OSのメトリクスを収集して、Prometheus、Grafanaで可視化しているのだが、独自メトリクスも可視化したくなった。
Prometheus用のExporterを自作すればよいらしいが、Webサーバも起動する必要があるし、少し面倒そう。
Node ExporterのTextfile Collectorを使えば簡単に独自メトリクスを収集できそうなので、試してみる。

※今回使う環境の構築方法や、Prometheus、Grafana、Node Exporterの設定は以下記事参照。 tk-ch.hatenablog.com

環境

  • OS:RockyLinux8.6
  • Prometheus:v2.37.1
  • Grafana:9.1.6
  • Node Exporter:1.4.0
  • Python:3.9.7
  • prometheus_client:0.14.1

実施内容

Node ExporterのREADMEによると、Node Exporterは、--collector.textfile.directoryオプションで指定したディレクトリ内の「*.prom」という名前のファイルに記載した内容を収集する。
これを利用して独自メトリクスを収集できるようなので、使ってみる。

コマンド実行で試してみる

先ほどのREADMEを参考に、本当に収集されるか試してみる。
Node Exporterが動作している管理対象サーバで、以下を実行する。
(Node Exporterは「--collector.textfile.directory /var/lib/node_exporter/textfile_collector」というオプションで動作している。)

「my_batch_job_completion_time」というメトリクス名で、現在時刻を記載したファイルを作成する
# echo my_batch_job_completion_time $(date +%s) > /var/lib/node_exporter/textfile_collector/my_batch_job.prom.$$
# mv /var/lib/node_exporter/textfile_collector/my_batch_job.prom.$$ /var/lib/node_exporter/textfile_collector/my_batch_job.prom

作成したファイルの中身を確認する
# cat /var/lib/node_exporter/textfile_collector/my_batch_job.prom
my_batch_job_completion_time 1665059541

Node Exporterの収集メトリクスを確認すると「my_batch_job_completion_time」が収集されていることが確認できる
# curl -s http://localhost:9100/metrics | grep my_batch_job_completion_time
# HELP my_batch_job_completion_time Metric read from /var/lib/node_exporter/textfile_collector/my_batch_job.prom
# TYPE my_batch_job_completion_time untyped
my_batch_job_completion_time 1.665059541e+09

→想定通り、ファイルに記載した内容がメトリクスとして収集された。
上記ではコマンドを手動実行したが、実際には独自メトリクスを収集してファイルに記載するスクリプトを定期実行することになる。
スクリプトの例はここにある。

※上記手順では、my_batch_job.promに直接リダイレクトせず、my_batch_job.prom.$$をリネームする形にしている。
これはファイルをアトミックに更新することで、Node Exporterが更新途中のテキストファイルを読み込まないようにするため。
更新途中のデータを読み込むと、エラー発生や不正なデータを収集してしまうリスクがある。
参考:https://www.robustperception.io/atomic-writes-and-the-textfile-collector/

シェルスクリプトで独自メトリクスの値を定期更新する

ランダムな数値をmy_random_numberというメトリクス名で更新するスクリプトを作成する。
メトリクスのタイプについてはここに記載がある。 今回はランダムな数値なので、gaugeにした。

# mkdir /root/script

# vim /root/script/output_random.sh

output_random.sh

#!/bin/bash

# テキストファイルの情報
TEXT_DIR="/var/lib/node_exporter/textfile_collector"
TEXT_BASE="my_random_number"
TEXT_EXT=".prom"
TEXT_PATH=${TEXT_DIR}/${TEXT_BASE}${TEXT_EXT}

# メトリクスの情報
METRICS_NAME="my_random_number"
METRICS_HELP="My random number"
METRICS_TYPE="gauge"

# メトリクスの説明・タイプの出力
echo "# HELP ${METRICS_NAME} ${METRICS_HELP}" > ${TEXT_PATH}.$$
echo "# TYPE ${METRICS_NAME} ${METRICS_TYPE}" >> ${TEXT_PATH}.$$

# メトリクス名と値の出力
echo "my_random_number $RANDOM" >> ${TEXT_PATH}.$$

# テキストファイルの更新
mv ${TEXT_PATH}.$$ ${TEXT_PATH}

実行して、テキストファイルが作成されること、想定通りメトリクス収集されていることを確認する

実行権限を付与
# chmod a+x /root/script/output_random.sh

実行
# /root/script/output_random.sh

テキストファイルを確認
# cat /var/lib/node_exporter/textfile_collector/my_random_number.prom
# HELP my_random_number My random number
# TYPE my_random_number gauge
my_random_number 16633

メトリクスとして収集されていることを確認
# curl -s http://localhost:9100/metrics | grep my_random_number
# HELP my_random_number My random number
# TYPE my_random_number gauge
my_random_number 16633
node_textfile_mtime_seconds{file="/var/lib/node_exporter/textfile_collector/my_random_number.prom"} 1.665064408e+09

想定通り出力されている。
毎分定期実行されるようcronに設定する。

# crontab -e
* * * * * /root/script/output_random.sh

暫く待ってからGrafanaのダッシュボード作成画面で「my_random_number」をクエリとしてグラフ作成すると、以下のようにmy_random_numberの値を可視化できる。

独自メトリクスをGrafanaで表示
独自メトリクスをGrafanaで表示

Pythonスクリプトで独自メトリクスの値を定期更新する

Prometheus公式のPython用Client(prometheus-client)がある。
Pythonプログラムに仕込んでメトリクス収集したりできるようだが、これを使ってTextfile Collector用のテキストファイルを作成できる。
こちらを参考に試してみる。

Pythonのインストール

# dnf module -y install python39

# python3 -V
Python 3.9.7

prometheus-clientのインストール

# pip3 install prometheus-client
WARNING: Running pip install with root privileges is generally not a good idea. Try `pip3 install --user` instead.
Collecting prometheus-client
  Downloading prometheus_client-0.14.1-py3-none-any.whl (59 kB)
     |????????????????????????????????| 59 kB 10.4 MB/s
Installing collected packages: prometheus-client
Successfully installed prometheus-client-0.14.1

シェルスクリプトの時と同様、ランダムな数値をmy_random_numberというメトリクス名で更新するスクリプトを作成する。

# vim output_random.py

output_random.py

#!/usr/bin/env python3

import random
from prometheus_client import CollectorRegistry, Gauge, write_to_textfile

FILE_PATH = '/var/lib/node_exporter/textfile_collector/my_random_number_py.prom'
METRICS_NAME="my_random_number_py"
METRICS_HELP="My random number by python script"

registry = CollectorRegistry()
g = Gauge(METRICS_NAME, METRICS_HELP, registry=registry)
g.set(random.randint(0, 10000))
write_to_textfile(FILE_PATH, registry)
  • Gauge()の第1引数はメトリック名、第2引数はヘルプ文字列。
  • コマンド、シェルスクリプトでファイル更新する際は、一時ファイルを経由することでアトミックなファイル更新を行っていた。
    prometheus-clientでは、write_to_textfile()関数がこの処理を行ってくれている。
    ここにあるwrite_to_textfile()のソースを見ると、一時ファイルを経由して更新する処理になっていることが分かる。
実行権限を付与
# chmod a+x /root/script/output_random.py

実行
# /root/script/output_random.py

出力を確認
# cat /var/lib/node_exporter/textfile_collector/my_random_number_py.prom
# HELP my_random_number_py My random number by python script
# TYPE my_random_number_py gauge
my_random_number_py 5277.0

メトリクスとして収集されていることを確認
# curl -s http://localhost:9100/metrics | grep my_random_number_py
# HELP my_random_number_py My random number by python script
# TYPE my_random_number_py gauge
my_random_number_py 1915
node_textfile_mtime_seconds{file="/var/lib/node_exporter/textfile_collector/my_random_number_py.prom"} 1.665068941e+09

想定通り収集されている。
あとはシェルスクリプトの時と同様に、定期実行してやればよい。
prometheus-clientを使うと、出力フォーマットを適切に整形してアトミックにテキストファイルを作成・更新してくれることが分かった。

まとめ

  • Node ExporterのTextfile Collectorで、簡単に独自メトリクスを収集できた。
  • Textfile Collector用のファイル更新は、シェルスクリプトでもPythonスクリプトでも比較的簡単なコードで実現できる。
    環境や独自メトリクス収集の処理内容に応じて選択すればよい。