Remarques :

Surveiller Oracle Cloud Infrastructure Database avec PostgreSQL à l'aide de Datadog

Introduction

Oracle Cloud Infrastructure (OCI) est une plate-forme cloud robuste et hautement évolutive conçue pour répondre aux besoins des entreprises modernes. Il fournit une suite complète de services pour l'informatique, le stockage, la mise en réseau, la base de données et le développement d'applications, optimisés pour les performances, la sécurité et la rentabilité. OCI est idéal pour exécuter des workloads natifs du cloud et traditionnels, offrant aux entreprises une infrastructure flexible et fiable.

Datadog est une plate-forme complète d'analyse et de surveillance cloud conçue pour aider les entreprises à obtenir une visibilité de bout en bout sur leur infrastructure informatique, leurs applications et leurs services. Il permet la surveillance en temps réel, le dépannage et l'optimisation des performances dans des environnements cloud hybrides dynamiques. Datadog s'intègre de manière transparente à une large gamme d'outils, de plates-formes et de services, ce qui en fait une solution polyvalente pour les équipes d'exploitation DevOps et informatiques modernes.

Ce tutoriel explique comment OCI Database avec les utilisateurs de PostgreSQL et Datadog peut configurer des solutions efficaces et évolutives pour transmettre de manière transparente des mesures d'OCI à Datadog à l'aide d'OCI Connector Hub et d'OCI Functions.

Objectifs

Prérequis

Tâche 1 : créer un compte Datadog

  1. Configurez un compte dans l'outil d'intégration Datadog à l'aide du site Web Datadog. Fournissez les détails de compte nécessaires et terminez la configuration de l'agent en configurant les paramètres d'environnement appropriés.

  2. Installez l'agent Datadog pour collecter des mesures et des événements à partir de la base de données OCI avec PostgreSQL. Pour plus d'informations sur la configuration et la configuration de l'agent Datadog, reportez-vous à Configuration de l'agent Datadog. Pour plus d'informations sur le dépannage et le débogage sur l'agent Datadog, reportez-vous à Utilisation de base de l'agent Datadog.

  3. Sélectionnez OCI comme intégration et poursuivez son installation. L'image suivante présente la post-installation de l'intégration OCI pour Datadog.

    image

  4. Cliquez sur Ajouter une location et entrez les informations d'OCID de location et de région d'origine.

    image

Tâche 2 : créer des ressources d'authentification Datadog

Créez un utilisateur, un groupe et une stratégie d'authentification Datadog dans Oracle Cloud Infrastructure (OCI).

  1. Pour créer un domaine, accédez à Identité et créez un domaine nommé DataDog.

  2. Créez un groupe nommé DatadogAuthGroup.

  3. Créez un utilisateur nommé DatadogAuthUser à l'aide de votre adresse électronique (la même adresse électronique que celle utilisée pour la connexion à l'outil de surveillance Datadog) et affectez DatadogAuthGroup au groupe.

  4. Copiez l'OCID utilisateur et collez-le dans le champ OCID utilisateur de la mosaïque d'intégration OCI Datadog pour configurer l'OCID utilisateur.

  5. Configurer l'API.

    1. Accédez à votre profil et sélectionnez votre nom d'utilisateur.

    2. Accédez à Ressources dans l'angle inférieur gauche et sélectionnez Clés d'API.

    3. Cliquez sur Ajouter une clé d'API, téléchargez la clé privée, puis cliquez sur Ajouter.

    4. Fermez la fenêtre Aperçu du fichier de configuration. Aucune action requise.

    5. Copiez la valeur d'empreinte et collez-la dans le champ Empreinte de la mosaïque d'intégration OCI Datadog.

  6. Configurez la clé privée.

    1. Ouvrez le fichier de clés privées téléchargé (.pem) dans un éditeur de texte ou utilisez une commande de terminal (par exemple, cat) pour afficher son contenu.

    2. Copiez la clé entière, y compris les lignes -----BEGIN PRIVATE KEY----- et -----END PRIVATE KEY-----.

    3. Collez la clé privée dans le champ Clé privée de la mosaïque d'intégration OCI Datadog.

  7. Créez une stratégie nommée DataDogPolicy dans le compartiment postgresqlinteg (racine).

  8. Utilisez le générateur de stratégies en mode éditeur manuel pour entrer l'instruction de stratégie requise.

    Allow group DatadogAuthGroup to read all-resources in tenancy
    

Voici un exemple de mosaïque d'intégration OCI Datadog après l'ajout de la location et des détails utilisateur.

image

Tâche 3 : créer une pile OCI

image

Accédez à la section Identité et créez une pile de stratégies sous le compartiment racine. Cela permet aux hubs de connecteurs de lire des mesures et d'appeler des fonctions avec les instructions suivantes.

Allow dynamic-group DatadogAuthGroup to read metrics in tenancy
Allow dynamic-group DatadogAuthGroup to use fn-function in tenancy
Allow dynamic-group DatadogAuthGroup to use fn-invocation in tenancy

Pour configurer des stratégies d'identité et déployer des piles de transfert de mesure dans OCI pour l'intégration Datadog, procédez comme suit :

Tâche 3.1 : créer une pile de stratégies (ORM_policy_stack)

  1. Cliquez sur Créer une pile de stratégies dans la mosaïque d'intégration OCI Datadog, assurez-vous d'utiliser le lien fourni, qui inclut le script Terraform nécessaire et acceptez les conditions d'utilisation Oracle.

  2. Cliquez sur le menu déroulant Répertoire de travail et sélectionnez datadog-oci-orm/policy-setup.

  3. Désélectionnez Utiliser des fournisseurs Terraform personnalisés.

  4. Entrez un nom descriptif (par exemple, datadog-metrics-policy-setup) et sélectionnez le compartiment pour le déploiement.

  5. Cliquez sur Suivant, nommez le groupe dynamique et la stratégie (ou utilisez des noms par défaut), assurez-vous que la région d'origine de la location est sélectionnée, puis cliquez sur Créer.

Tâche 3.2 : créer une pile de transmission de mesure

Les ressources sont déployées vers le compartiment indiqué. Assurez-vous que l'utilisateur exécutant la pile dispose des droits d'accès appropriés.

  1. Cliquez sur Créer une pile de stratégies dans la mosaïque d'intégration OCI Datadog et acceptez les conditions d'utilisation Oracle.

  2. Cliquez sur le menu déroulant Répertoire de travail, sélectionnez datadog-oci-orm/metrics-setup et désélectionnez Utiliser des fournisseurs Terraform personnalisés.

  3. Nommez la pile et sélectionnez le compartiment de déploiement, puis cliquez sur Suivant.

  4. Laissez les valeurs de location inchangées, entrez votre clé d'API Datadog et sélectionnez l'adresse US5 (ocimetrics-intake.us5.datadoghq.com).

  5. Pour la configuration réseau, assurez-vous que la case Créer un VCN est cochée et sélectionnez le compartiment approprié pour la création du VCN.

  6. Dans la section Paramètres de fonction, conservez la forme d'application par défaut GENERIC_ARM. Entrez le nom utilisateur et le mot de passe du registre OCI Docker (mot de passe artificiel).

  7. Définissez la taille de batch Service Connector Hub sur 5000, puis cliquez sur Suivant.

  8. Cliquez sur Créer.

Tâche 3.3 : finalisation de la configuration

  1. Revenez à la mosaïque d'intégration OCI Datadog et cliquez sur Créer une configuration pour terminer la configuration.

  2. Ce processus garantit que les mesures et les fonctions Datadog sont correctement configurées pour être intégrées à OCI.

    image

Tâche 4 : création de fonctions OCI

Pour créer une application dans la console OCI, procédez comme suit :

  1. Accédez à Applications et sélectionnez Créer une application.

  2. Entrez le nom de l'application, sélectionnez le réseau cloud virtuel (VCN) et les détails du sous-réseau appropriés, puis cliquez sur Créer.

  3. Pour accéder à l'application nouvellement créée, sous Ressources, sélectionnez Pour commencer.

    image

  4. Cliquez sur Lancer Cloud Shell et copiez les commandes suivantes à partir de Utiliser le contexte pour votre région.

    fn list context
    fn use context <region name>
    
  5. Mettez à jour le contexte pour inclure l'ID de compartiment de la fonction.

    fn update context oracle.compartment-id <compartment-id>
    
  6. Mettre à jour le contexte pour inclure l'emplacement du registre à utiliser.

    fn update context registry phx.ocir.io/<tenancy_name>/[YOUR-OCIR-REPO]
    

    Remarque : remplacez phx en contexte par le code de région à trois chiffres.

  7. Connectez-vous au registre à l'aide du jeton d'authentification en tant que mot de passe.

    docker login -u 'TENACNY_NAME/OCI_USERNAME' phx.ocir.io
    
  8. Un mot de passe vous sera demandé. Indiquez votre mot de passe approprié.

    Remarque :

    • Remplacez phx par le code de région à trois chiffres.
    • Si vous utilisez Oracle Identity Cloud Service, votre nom utilisateur est <tenancyname>/oracleidentitycloudservice/<username>.
  9. Générer une fonction hello-world.

    fn list apps
    fn init --runtime python datadog
    

    La commande fn init génère un dossier nommé datadog contenant trois fichiers : func.py, func.yaml et requirements.txt.

  10. Exécutez la commande cd datadog.

  11. Ouvrez func.py et remplacez le contenu du fichier par le fragment de code suivant.

    # oci-monitoring-metrics-to-datadog version 1.0.
    #
    # Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
    # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl.
    
    import io
    import json
    import logging
    import os
    import re
    import requests
    from fdk import response
    from datetime import datetime
    
    """
    This sample OCI Function maps OCI Monitoring Service Metrics to the DataDog
    REST API 'submit-metrics' contract found here:
    
    https://docs.datadoghq.com/api/latest/metrics/#submit-metrics
    
    """
    
    # Use OCI Application or Function configurations to override these environment variable defaults.
    
    api_endpoint = os.getenv('DATADOG_METRICS_API_ENDPOINT', 'not-configured')
    api_key = os.getenv('DATADOG_API_KEY', 'not-configured')
    is_forwarding = eval(os.getenv('FORWARD_TO_DATADOG', "True"))
    metric_tag_keys = os.getenv('METRICS_TAG_KEYS', 'name, namespace, displayName, resourceDisplayName, unit')
    metric_tag_set = set()
    
    # Set all registered loggers to the configured log_level
    
    logging_level = os.getenv('LOGGING_LEVEL', 'INFO')
    loggers = [logging.getLogger()] + [logging.getLogger(name) for name in logging.root.manager.loggerDict]
    [logger.setLevel(logging.getLevelName(logging_level)) for logger in loggers]
    
    # Exception stack trace logging
    
    is_tracing = eval(os.getenv('ENABLE_TRACING', "False"))
    
    # Constants
    
    TEN_MINUTES_SEC = 10 * 60
    ONE_HOUR_SEC = 60 * 60
    
    # Functions
    
    def handler(ctx, data: io.BytesIO = None):
        """
        OCI Function Entry Point
        :param ctx: InvokeContext
        :param data: data payload
        :return: plain text response indicating success or error
        """
    
        preamble = " {} / event count = {} / logging level = {} / forwarding to DataDog = {}"
    
        try:
            metrics_list = json.loads(data.getvalue())
            logging.getLogger().info(preamble.format(ctx.FnName(), len(metrics_list), logging_level, is_forwarding))
            logging.getLogger().debug(metrics_list)
            converted_event_list = handle_metric_events(event_list=metrics_list)
            send_to_datadog(event_list=converted_event_list)
    
        except (Exception, ValueError) as ex:
            logging.getLogger().error('error handling logging payload: {}'.format(str(ex)))
            if is_tracing:
                logging.getLogger().error(ex)
    
    
    def handle_metric_events(event_list):
        """
        :param event_list: the list of metric formatted log records.
        :return: the list of DataDog formatted log records
        """
    
        result_list = []
        for event in event_list:
            single_result = transform_metric_to_datadog_format(log_record=event)
            result_list.append(single_result)
            logging.getLogger().debug(single_result)
    
        return result_list
    
    
    def transform_metric_to_datadog_format(log_record: dict):
        """
        Transform metrics to DataDog format.
        See: https://github.com/metrics/spec/blob/v1.0/json-format.md
        :param log_record: metric log record
        :return: DataDog formatted log record
        """
    
        series = [{
            'metric': get_metric_name(log_record),
            'type' : get_metric_type(log_record),
            'points' : get_metric_points(log_record),
            'tags' : get_metric_tags(log_record),
        }]
    
        result = {
            'series' : series
        }
        return result
    
    
    def get_metric_name(log_record: dict):
        """
        Assembles a metric name that appears to follow DataDog conventions.
        :param log_record:
        :return:
        """
    
        elements = get_dictionary_value(log_record, 'namespace').split('_')
        elements += camel_case_split(get_dictionary_value(log_record, 'name'))
        elements = [element.lower() for element in elements]
        return '.'.join(elements)
    
    
    def camel_case_split(str):
        """
        :param str:
        :return: Splits camel case string to individual strings
        """
    
        return re.findall(r'[A-Z](?:[a-z]+|[A-Z]*(?=[A-Z]|$))', str)
    
    
    def get_metric_type(log_record: dict):
        """
        :param log_record:
        :return: The type of metric. The available types are 0 (unspecified), 1 (count), 2 (rate), and 3 (gauge).
        Allowed enum values: 0,1,2,3
        """
    
        return 0
    
    
    def get_now_timestamp():
        return datetime.now().timestamp()
    
    
    def adjust_metric_timestamp(timestamp_ms):
        """
        DataDog Timestamps should be in POSIX time in seconds, and cannot be more than ten
        minutes in the future or more than one hour in the past.  OCI Timestamps are POSIX
        in milliseconds, therefore a conversion is required.
    
        See https://docs.datadoghq.com/api/latest/metrics/#submit-metrics
        :param oci_timestamp:
        :return:
        """
    
        # positive skew is expected
        timestamp_sec = int(timestamp_ms / 1000)
        delta_sec = get_now_timestamp() - timestamp_sec
    
        if (delta_sec > 0 and delta_sec > ONE_HOUR_SEC):
            logging.getLogger().warning('timestamp {} too far in the past per DataDog'.format(timestamp_ms))
    
        if (delta_sec < 0 and abs(delta_sec) > TEN_MINUTES_SEC):
            logging.getLogger().warning('timestamp {} too far in the future per DataDog'.format(timestamp_ms))
    
        return timestamp_sec
    
    
    def get_metric_points(log_record: dict):
        """
        :param log_record:
        :return: an array of arrays where each array is a datapoint scalar pair
        """
    
        result = []
    
        datapoints = get_dictionary_value(dictionary=log_record, target_key='datapoints')
        for point in datapoints:
            dd_point = {'timestamp': adjust_metric_timestamp(point.get('timestamp')),
                        'value': point.get('value')}
    
            result.append(dd_point)
    
        return result
    
    
    def get_metric_tags(log_record: dict):
        """
        Assembles tags from selected metric attributes.
        See https://docs.datadoghq.com/getting_started/tagging/
        :param log_record: the log record to scan
        :return: string of comma-separated, key:value pairs matching DataDog tag format
        """
    
        result = []
    
        for tag in get_metric_tag_set():
            value = get_dictionary_value(dictionary=log_record, target_key=tag)
            if value is None:
                continue
    
            if isinstance(value, str) and ':' in value:
                logging.getLogger().warning('tag contains a \':\' / ignoring {} ({})'.format(key, value))
                continue
    
            tag = '{}:{}'.format(tag, value)
            result.append(tag)
    
        return result
    
    
    def get_metric_tag_set():
        """
        :return: the set metric payload keys that we would like to have converted to tags.
        """
    
        global metric_tag_set
    
        if len(metric_tag_set) == 0 and metric_tag_keys:
            split_and_stripped_tags = [x.strip() for x in metric_tag_keys.split(',')]
            metric_tag_set.update(split_and_stripped_tags)
            logging.getLogger().debug("tag key set / {} ".format (metric_tag_set))
    
        return metric_tag_set
    
    
    def send_to_datadog (event_list):
        """
        Sends each transformed event to DataDog Endpoint.
        :param event_list: list of events in DataDog format
        :return: None
        """
    
        if is_forwarding is False:
            logging.getLogger().debug("DataDog forwarding is disabled - nothing sent")
            return
    
        if 'v2' not in api_endpoint:
            raise RuntimeError('Requires API endpoint version "v2": "{}"'.format(api_endpoint))
    
        # creating a session and adapter to avoid recreating
        # a new connection pool between each POST call
    
        try:
            session = requests.Session()
            adapter = requests.adapters.HTTPAdapter(pool_connections=10, pool_maxsize=10)
            session.mount('https://', adapter)
    
            for event in event_list:
                api_headers = {'Content-type': 'application/json', 'DD-API-KEY': api_key}
                logging.getLogger().debug("json to datadog: {}".format (json.dumps(event)))
                response = session.post(api_endpoint, data=json.dumps(event), headers=api_headers)
    
                if response.status_code != 202:
                    raise Exception ('error {} sending to DataDog: {}'.format(response.status_code, response.reason))
    
        finally:
            session.close()
    
    
    def get_dictionary_value(dictionary: dict, target_key: str):
        """
        Recursive method to find value within a dictionary which may also have nested lists / dictionaries.
        :param dictionary: the dictionary to scan
        :param target_key: the key we are looking for
        :return: If a target_key exists multiple times in the dictionary, the first one found will be returned.
        """
    
        if dictionary is None:
            raise Exception('dictionary None for key'.format(target_key))
    
        target_value = dictionary.get(target_key)
        if target_value:
            return target_value
    
        for key, value in dictionary.items():
            if isinstance(value, dict):
                target_value = get_dictionary_value(dictionary=value, target_key=target_key)
                if target_value:
                    return target_value
    
            elif isinstance(value, list):
                for entry in value:
                    if isinstance(entry, dict):
                        target_value = get_dictionary_value(dictionary=entry, target_key=target_key)
                        if target_value:
                            return target_value
    
    
    def local_test_mode(filename):
        """
        This routine reads a local json metrics file, converting the contents to DataDog format.
        :param filename: cloud events json file exported from OCI Logging UI or CLI.
        :return: None
        """
    
        logging.getLogger().info("local testing started")
    
        with open(filename, 'r') as f:
            transformed_results = list()
    
            for line in f:
                event = json.loads(line)
                logging.getLogger().debug(json.dumps(event, indent=4))
                transformed_result = transform_metric_to_datadog_format(event)
                transformed_results.append(transformed_result)
    
            logging.getLogger().debug(json.dumps(transformed_results, indent=4))
            send_to_datadog(event_list=transformed_results)
    
        logging.getLogger().info("local testing completed")
    
    
    """
    Local Debugging
    """
    
    if __name__ == "__main__":
        local_test_mode('oci-metrics-test-file.json')
    
  12. Mettez à jour func.yaml avec le code suivant. Remplacez DATADOG_TOKEN par votre clé d'API Datadog et DATADOG_HOST par l'adresse REST - https://http-intake.logs.datadoghq.com/v1/input. Pour plus d'informations sur l'adresse REST, reportez-vous à Collecte de journaux et intégrations.

    schema_version: 20180708
    name: datadogapp
    version: 0.0.1
    runtime: python
    entrypoint: /python/bin/fdk /function/func.py handler
    memory: 1024
    timeout: 120
    config:
    DATADOG_HOST: https://http-intake.logs.datadoghq.com/v1/input
    DATADOG_TOKEN: ZZZZZzzzzzzzzzz
    
  13. Mettez à jour requirements.txt avec le code suivant.

    fdk
    dattime
    requests
    oci
    
  14. Exécutez la commande suivante pour créer l'application et déployer les fonctions pour terminer la configuration.

    fn create app datadog01 --annotation oracle.com/oci/subnetIds='["Provide your subnet OCID"]'
    
  15. Exécutez la commande suivante pour déployer les fonctions afin de terminer la configuration.

    fn -v deploy --app datadog
    

Tâche 5 : configuration d'OCI Connector Hub

  1. Accédez à la console OCI, accédez à Journalisation, à Connecteurs et cliquez sur Créer un connecteur.

  2. Définissez la source sur Surveillance et la cible sur Fonctions.

  3. Sous Configurer la connexion source, sélectionnez le compartiment de mesure et l'espace de noms appropriés. Par exemple, oci_postgresql pour la surveillance de base de données.

  4. Sous Configurer la cible, sélectionnez le compartiment, l'application de fonction et la fonction créés dans la tâche 4.

  5. Si vous y êtes invité, cliquez sur Créer pour créer la stratégie nécessaire.

  6. Cliquez sur Créer pour finaliser la configuration d'OCI Connector Hub.

image

Tâche 6 : afficher les mesures dans Datadog

OCI Connector Hub est maintenant configuré pour déclencher la fonction, ce qui permet l'ingestion de mesures dans Datadog chaque fois que de nouvelles mesures sont détectées. Dans la mosaïque Intégration Datadog, accédez à Mesures et consultez le récapitulatif pour visualiser les mesures liées à OCI.

image

Dans la mosaïque Intégration Datadog, cliquez sur Explorateur pour analyser et sélectionner les mesures OCI requises, le cas échéant.

image

Dépannage

Si aucune donnée n'apparaît sur la page Récapitulatif des mesures, sélectionnez Activer le journal afin d'activer la journalisation pour vos fonctions afin de vérifier les journaux et de déboguer le problème.

image

Remerciements

Ressources de formation supplémentaires

Explorez d'autres ateliers sur docs.oracle.com/learn ou accédez à d'autres contenus de formation gratuits sur le canal Oracle Learning YouTube. De plus, visitez le site education.oracle.com/learning-explorer pour devenir un explorateur Oracle Learning.

Pour obtenir la documentation produit, consultez le site Oracle Help Center.