Nouvelles annonces sur les technologies sans serveur et réseau ainsi que sur le RUM (Real-User Monitoring) dévoilées à la conférence Dash ! Nouvelles annonces dévoilées à la conférence Dash !

Écrire un check Prometheus custom

Présentation

Cette page présente l’interface PrometheusCheck en détail pour une utilisation plus avancée, avec notamment un exemple de check simple qui recueille des métriques de temps et des états d’événements depuis Kube DNS. Pour en savoir plus sur la configuration d’un check Prometheus de base, consultez la documentation relative à l’Agent.

Utilisation avancée : interface de check Prometheus

Si vous avez besoin de fonctionnalités plus avancées que celles offertes par le check générique (telles que le prétraitement de métriques), vous pouvez écrire un PrometheusCheck custom. Il s’agit de la classe de base du check générique, qui fournit une structure et certains auxiliaires permettant de recueillir des métriques, des événements et des checks de service exposés via Prometheus. Les checks basés sur cette classe nécessitent d’effectuer les opérations de configuration suivantes :

  • Remplacement de self.NAMESPACE
  • Remplacement de self.metrics_mapper
  • Implémentation de la méthode check() ET/OU
  • Création d’une méthode portant le nom de la métrique Prometheus gérée par les checks (voir self.prometheus_metric_name)

Écrire un check Prometheus custom

Voici un exemple simple de check Kube DNS écrit afin d’illustrer l’utilisation de la classe PrometheusCheck. L’exemple ci-dessous reproduit les fonctionnalités du check Prometheus générique suivant :

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

Configuration

Vos fichiers de configuration et de check doivent porter le même nom. Si votre check s'appelle moncheck.py, votre fichier de configuration doit s'appeler moncheck.yaml.

La configuration d’un check Prometheus est pratiquement la même que celle d’un check de l’Agent classique. La principale différence est l’inclusion de la variable prometheus_endpoint dans votre fichier check.yaml. Le code suivant doit être ajouté dans conf.d/kube_dns.yaml :

init_config:

instances:
    # url de l'endpoint des métriques de prometheus
  - prometheus_endpoint: http://localhost:10055/metrics

Écrire le check

Tous les checks Prometheus héritent de la classe PrometheusCheck qui se trouve dans checks/prometheus_check.py :

from datadog_checks.checks.prometheus import PrometheusCheck

class KubeDNSCheck(PrometheusCheck):

Remplacement de self.NAMESPACE

NAMESPACE correspond au préfixe des métriques. Il doit être codé en dur dans la classe de votre check :

from datadog_checks.checks.prometheus import PrometheusCheck

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

Remplacement de self.metrics_mapper

metrics_mapper est un dictionnaire où la clé est la métrique à recueillir et la valeur est le nom de métrique correspondant dans Datadog. L’objectif du remplacement est de faire en sorte que les métriques envoyées par les checks Prometheus ne soient pas considérées comme des métriques custom :

from datadog_checks.checks.prometheus import PrometheusCheck

class KubeDNSCheck(PrometheusCheck):
    def __init__(self, name, init_config, agentConfig, instances=None):
        super(KubeDNSCheck, self).__init__(name, init_config, agentConfig, instances)
        self.NAMESPACE = 'kubedns'
        self.metrics_mapper = {
            # les métriques ont été renommées par kubedns dans kubernetes 1.6.0
            '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'
        }

Implémenter la méthode de check

Nous avons simplement besoin de récupérer, depuis instance, endpoint, qui correspond au endpoint de métriques Prometheus à partir duquel les métriques sont récupérées.

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

Si un check ne parvient pas à se lancer en raison d’une mauvaise configuration ou d’une erreur de programmation, ou s’il n’est pas en mesure de recueillir de métrique, il doit générer une exception explicative. Cette exception est loguée et affichée dans la commande status de l’Agent pour faciliter le debugging. Par exemple :

$ 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

Améliorez votre méthode check () avec CheckException :

from datadog_checks.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.")

Dès que des données seront disponibles, vous n’aurez qu’à transmettre ce qui suit :

from datadog_checks.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.")
    # Par défaut, nous envoyons les compartiments.
    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)

Synthèse

from datadog_checks.errors import CheckException
from datadog_checks.checks.prometheus import PrometheusCheck

class KubeDNSCheck(PrometheusCheck):
    """
    Collect kube-dns metrics from Prometheus
    """
    def __init__(self, name, init_config, agentConfig, instances=None):
        super(KubeDNSCheck, self).__init__(name, init_config, agentConfig, instances)
        self.NAMESPACE = 'kubedns'

        self.metrics_mapper = {
            # les métriques ont été renommées par kubedns dans kubernetes 1.6.0
            '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("Unable to find prometheus_endpoint in config file.")

        send_buckets = instance.get('send_histograms_buckets', True)
        # Par défaut, nous envoyons les compartiments.
        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)

Concepts avancés

Vous pouvez améliorer votre check Prometheus à l’aide des méthodes suivantes :

self.ignore_metrics

Certaines métriques sont ignorées car elles sont en double ou introduisent une très forte cardinalité. Les métriques incluses dans cette liste seront silencieusement ignorées sans afficher la ligne de debug Unable to handle metric dans les logs.

self.labels_mapper

Si le dictionnaire labels_mapper est fourni, les étiquettes de métriques dans labels_mapper utiliseront la valeur correspondante comme nom de tag lors de l’envoi des gauges.

self.exclude_labels

exclude_labels est un tableau d’étiquettes à exclure. Ces étiquettes ne seront pas ajoutées en tant que tags lors de l’envoi de la métrique.

self.type_overrides

type_overrides est un dictionnaire où les clés sont des noms de métrique Prometheus et les valeurs sont un type de métrique (nom sous forme de chaîne) à utiliser au lieu de celui indiqué dans la charge utile. Il peut être utilisé pour forcer l’application d’un type sur des métriques non associées à un type. Voici les types disponibles : counter, gauge, summary, untyped et histogram.

Remarque‭ : le dictionnaire est vide dans la classe de base, mais doit être surchargé/codé en dur dans le check final pour que les métriques ne soient pas considérées comme des métriques custom.

Pour aller plus loin