0
1

More than 3 years have passed since last update.

Prometheus client_python tips - 複数の対象のmetricsを作る方法

Last updated at Posted at 2019-11-28

Overview

Prometheusには様々なexporterがあるが、APIを作ったりして
独自のmetricsを生成したい場合は、client libraryを使うようになっている。

従ってpythonにもそれ用のlibraryがあり、それがこちら
基本的にはGaugeを使って作れば良いのでだいたい以下のようなコードになる。

#!/usr/bin/env python3
# import os
import sys
import re
from logging import getLogger
from prometheus_client import generate_latest
from prometheus_client import Gauge
from prometheus_client import REGISTRY
logger = getLogger(__name__)

class MetricsGenetator(object):

    def __init__(self):
        self.g = Gauge('my_inprogress_requests', 'Description of gauge')

    def run(self):
        self.g.inc()      # Increment by 1
        self.g.dec(10)    # Decrement by given value
        self.g.set(4.2)   # Set to a given value
        metrics = generate_latest(self.registry)
        return metrics



def main():
    app = MetricsGenerator()
    metrics = app.run()
    print(metrics)

if __name__ == '__main__':
    main()

これを都度、実行しているならば良いが、
例えばself.g.setに渡されている4.2という値が以下のような使い方をしていると困ったことが起きる。

  • snmpget cpu_usage from のように対象が分かれるだけでコード自体は使い回されている場合
  • 上記のようなコードがモジュール化されており常時プロセスとしては起動し続けている
  • 値が取得できたときは返すが、取得できない時にダミー値を入れない

具体的にはどのようなことが起きるかというと

  1. Aサーバから CPU usageを得る - 50 とする
  2. Bサーバから CPU usageを得ようとして失敗する (None)
    • この時に、Noneが返ってきた場合に self.g.set()自体をスキップする
  3. するとBサーバの CPU usage が 50 として返る

つまり前の値がそのまま流用されてしまうのである。
上記のような構造の場合は CPU usage = None 等を明示的に入れれば良いのだが
Aサーバ、BサーバのCPU数が流動的で、 for cpu in cpu_num: というような形で
ラベルを動的に生成をしている場合はダミー値を入れることができない。

どうするか

2019年9月に新しくcommitされた CollectorRegistryのtarget_infoを使う事で
Registryを分けることができるようになる。
こんな感じ。

#!/usr/bin/env python3
# import os
import sys
import re
import click
from logging import getLogger
from prometheus_client import generate_latest
from prometheus_client import Gauge
# from prometheus_client import REGISTRY
from prometheus_client.core import CollectorRegistry
logger = getLogger(__name__)

class MetricsGenetator(object):

    def __init__(self, target):
        registry = CollectorRegistry(target_info={"target": server_name})
        self.g = Gauge(
                     'my_inprogress_requests',
                     'Description of gauge',
                     registry=registry)

    def run(self):
        self.g.inc()      # Increment by 1
        self.g.dec(10)    # Decrement by given value
        self.g.set(4.2)   # Set to a given value
        metrics = generate_latest(self.registry)
        return metrics


@click.command()
@click.option('-h', '--hostname', required=True, type=str,
              default="localhost", help="get metrics from hostname. (default: localhost)")
def cli():
    app = MetricsGenerator(target)
    metrics = app.run()
    print(metrics)


def main():
    cli()


if __name__ == '__main__':
    main()
0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1