カスタム OpenMetrics チェックの書き方
Datadog の調査レポート: サーバーレスの状態 レポート: サーバーレスの状態

カスタム OpenMetrics チェックの書き方

概要

ここでは、Kube DNS からタイミングメトリクスとステータスイベントを収集する簡単なチェックを例に挙げて、OpenMetricsBaseCheck インターフェイスの高度な使用方法について説明します。基本的な OpenMetrics チェックの構成については、Agent に関するドキュメントを参照してください。

高度な使用方法: OpenMetrics チェックインターフェイス

汎用のチェックより高度なチェック (たとえば、メトリクスの前処理) が必要な場合は、カスタム OpenMetricsBaseCheck を作成してください。これは汎用チェックの基本クラスです。Prometheus から公開されるメトリクス、イベント、サービスチェックを収集するための構造とヘルパーを提供します。このクラスに基づいてチェックを構成するには、少なくとも以下が必要です。

  • self.NAMESPACE のオーバーライド
  • self.metrics_mapper のオーバーライド
  • check() メソッドの実装 および/または
  • チェックで処理する OpenMetric メトリクスの名前を付けたメソッドの作成 (例: self.prometheus_metric_name)

カスタム Prometheus チェックの書き方

ここでは、簡単な Kube DNS チェックの記述例を示して、OpenMetricsBaseCheck クラスの使用方法について説明します。次の例は、以下の汎用 Prometheus チェックの機能を再現します。

instances:
  - prometheus_url: http://localhost:10055/metrics
    namespace: "kubedns"
    metrics:
      - kubedns_kubedns_dns_response_size_bytes: response_size.bytes
      - kubedns_kubedns_dns_request_duration_seconds: request_duration.seconds
      - kubedns_kubedns_dns_request_count_total: request_count
      - kubedns_kubedns_dns_error_count_total: error_count
      - kubedns_kubedns_dns_cachemiss_count_total: cachemiss_count

コンフィグレーション

構成とチェックファイルは、名前が一致していなければなりません。チェックが mycheck.py という名前なら、構成ファイルは mycheck.yaml という名前にしなければなりません。

Prometheus チェックの構成は、標準の Agent チェックとほぼ同じです。主な違いは、check.yaml ファイルに変数 prometheus_endpoint を入れることです。conf.d/kube_dns.yaml は以下のようになります。

init_config:

instances:
    # Prometheus のメトリクスエンドポイントの URL
  - prometheus_endpoint: http://localhost:10055/metrics

チェックの書き方

すべての OpenMetrics チェックは、checks/openmetrics_check.py にある OpenMetricsBaseCheck クラスを継承します。

from datadog_checks.base import OpenMetricsBasicCheck

class KubeDNSCheck(OpenMetricsBasicCheck):

self.NAMESPACE のオーバーライド

NAMESPACE は、メトリクスのプレフィックスです。これをチェッククラスでハードコードする必要があります。

from datadog_checks.base import OpenMetricsBaseCheck

class KubeDNSCheck(OpenMetricsBaseCheck):
    def __init__(self, name, init_config, agentConfig, instances=None):
        super(KubeDNSCheck, self).__init__(name, init_config, agentConfig, instances)
        self.NAMESPACE = 'kubedns'

self.metrics_mapper のオーバーライド

metrics_mapper は、取得するメトリクスをキーとし、対応する Datadog メトリクス名を値とする辞書です。 これをオーバーライドするのは、OpenMetrics チェックによって報告されるメトリクスがカスタムメトリクスとしてカウントされないようにするためです。

from datadog_checks.base import OpenMetricsBaseCheck

class KubeDNSCheck(OpenMetricsBaseCheck):
    def __init__(self, name, init_config, agentConfig, instances=None):
        super(KubeDNSCheck, self).__init__(name, init_config, agentConfig, instances)
        self.NAMESPACE = 'kubedns'
        self.metrics_mapper = {
            #kubernetes 1.6.0 でメトリクスの名前が kubedns に変更されました
            'kubedns_kubedns_dns_response_size_bytes': 'response_size.bytes',
            'kubedns_kubedns_dns_request_duration_seconds': 'request_duration.seconds',
            'kubedns_kubedns_dns_request_count_total': 'request_count',
            'kubedns_kubedns_dns_error_count_total': 'error_count',
            'kubedns_kubedns_dns_cachemiss_count_total': 'cachemiss_count'
        }

check メソッドの実装

instance から、メトリクスをポーリングするための Prometheus または OpenMetrics のメトリクスエンドポイント endpoint を使用します。

def check(self, instance):
    endpoint = instance.get('prometheus_endpoint')
例外

不正な構成、プログラミングエラー、メトリクスを収集できないなどの理由でチェックを実行できない場合は、わかりやすい例外を生成する必要があります。デバッグが容易になるように、この例外はログに記録され、Agent のステータスコマンドに表示されます。以下に例を示します。

$ sudo /etc/init.d/datadog-agent info

  Checks
  ======

    my_custom_check
    ---------------
      - instance #0 [ERROR]: Unable to find prometheus_endpoint in config file.
      - Collected 0 metrics & 0 events

CheckException を使用して check() メソッドを補強します。

from datadog_checks.base.errors import CheckException

def check(self, instance):
    endpoint = instance.get('prometheus_endpoint')
    if endpoint is None:
        raise CheckException("コンフィギュレーションファイルで prometheus_endpoint が見つかりません。")

次に、データを取得するとすぐにフラッシュします。

from datadog_checks.base.errors import CheckException

def check(self, instance):
    endpoint = instance.get('prometheus_endpoint')
    if endpoint is None:
        raise CheckException("Unable to find prometheus_endpoint in config file.")
    # デフォルトでは、バケットを送信します。
    if send_buckets is not None and str(send_buckets).lower() == 'false':
        send_buckets = False
    else:
        send_buckets = True

    self.process(endpoint, send_histograms_buckets=send_buckets, instance=instance)

ここまでのまとめ

from datadog_checks.base import OpenMetricsBaseCheck
from datadog_checks.base.errors import CheckException

class KubeDNSCheck(OpenMetricsBaseCheck):
    """
    Prometheus エンドポイントからの kube-dns メトリクスの収集
    """
    def __init__(self, name, init_config, agentConfig, instances=None):
        super(KubeDNSCheck, self).__init__(name, init_config, agentConfig, instances)
        self.NAMESPACE = 'kubedns'

        self.metrics_mapper = {
            # kubernetes 1.6.0 でメトリクスの名前が kubedns に変更されました
            'kubedns_kubedns_dns_response_size_bytes': 'response_size.bytes',
            'kubedns_kubedns_dns_request_duration_seconds': 'request_duration.seconds',
            'kubedns_kubedns_dns_request_count_total': 'request_count',
            'kubedns_kubedns_dns_error_count_total': 'error_count',
            'kubedns_kubedns_dns_cachemiss_count_total': 'cachemiss_count',
        }

    def check(self, instance):
        endpoint = instance.get('prometheus_endpoint')
        if endpoint is None:
            raise CheckException("コンフィギュレーションファイルで prometheus_endpoint が見つかりません。")

        send_buckets = instance.get('send_histograms_buckets', True)
        # デフォルトでは、バケットを送信します。
        if send_buckets is not None and str(send_buckets).lower() == 'false':
            send_buckets = False
        else:
            send_buckets = True

        self.process(endpoint, send_histograms_buckets=send_buckets, instance=instance)

さらに改良するには

以下のメソッドを使用して、OpenMetrics チェックをさらに改良できます。

self.ignore_metrics

メトリクスの一部は重複していたり、カーディナリティが非常に高くなるという理由で無視されます。このリストに含まれるメトリクスは、ログに Unable to handle metric というデバッグ行を残すことなく、暗黙にスキップされます。

self.labels_mapper

labels_mapper 辞書が提供されている場合は、ゲージの送信時に、labels_mapper 内のメトリクスラベルに対応する値がタグ名として使用されます。

self.exclude_labels

exclude_labels は、除外するラベルの配列です。除外されるラベルは、メトリクスの送信時にタグとして追加されません。

self.type_overrides

type_overrides は、Prometheus または OpenMetrics のメトリクス名をキーとし、メトリクスタイプ (文字列の名前) を値とする辞書です。これが、ペイロードにリストされているタイプの代わりに使用されます。タイプが指定されていないメトリクスにタイプを適用するために使用できます。 使用可能なタイプは countergaugesummaryuntypedhistogram です。

: この値は基本クラスでは空ですが、最終的なチェックではカスタムメトリクスとしてカウントされないように、オーバーロード/ハードコードする必要があります。

その他の参考資料