ノート:
- このチュートリアルでは、Oracle Cloudへのアクセスが必要です。無料アカウントにサインアップするには、Oracle Cloud Infrastructure Free Tierの開始を参照してください。
- Oracle Cloud Infrastructureの資格証明、テナンシおよびコンパートメントの値の例を使用します。演習を完了するときに、これらの値をクラウド環境に固有の値に置き換えます。
Datadogを使用したPostgreSQLによるOracle Cloud Infrastructure Databaseの監視
イントロダクション
Oracle Cloud Infrastructure(OCI)は、最新の企業のニーズを満たすように設計された、堅牢でスケーラブルなクラウド・プラットフォームです。パフォーマンス、セキュリティおよびコスト効率のために最適化された、コンピューティング、ストレージ、ネットワーキング、データベースおよびアプリケーション開発のための包括的なサービス・スイートを提供します。OCIは、クラウドネイティブと従来の両方のワークロードの実行に最適であり、柔軟で信頼性の高いインフラストラクチャを企業に提供します。
Datadogは、組織がITインフラストラクチャ、アプリケーションおよびサービスをエンドツーエンドで可視化できるように設計された、包括的なクラウドベースの監視および分析プラットフォームです。動的なハイブリッド・クラウド環境全体にわたるリアルタイムの監視、トラブルシューティング、パフォーマンスの最適化を実現します。Datadogは、幅広いツール、プラットフォーム、およびサービスとシームレスに統合されているため、最新のDevOpsおよびIT運用チーム向けの汎用性の高いソリューションとなります。
このチュートリアルでは、OCI Database with PostgreSQLおよびDatadogユーザーが、OCI Connector HubおよびOCI Functionsを使用してOCIからDatadogにメトリックをシームレスに送信するための効率的でスケーラブルなソリューションをどのように設定できるかを示します。
目的
- データベース・パフォーマンスのリアルタイム監視、アラートおよび可観測性を実現し、操作を円滑にし、問題を事前に解決します。
前提条件
-
OCIテナンシへのアクセス。
-
PostgreSQLシステムがプライベート・サブネットにプロビジョニングされたOCIデータベース。
-
要塞ホスト(コンピュート・イメージ)。
タスク1: Datadogアカウントの作成
-
Datadog Webサイトを使用して、Datadog統合ツールでアカウントを設定します。必要なアカウント詳細を指定し、適切な環境設定を構成してエージェントの設定を完了します。
-
Datadogエージェントをインストールして、PostgreSQLを使用してOCIデータベースからメトリックおよびイベントを収集します。Datadogエージェントの設定および構成の詳細は、Setup Datadog Agentを参照してください。Datadog Agentでのトラブルシューティングおよびデバッグの詳細は、Basic Datadog Agent Usageを参照してください。
-
統合として「OCI」を選択し、インストールを続行します。次の図は、Datadog用のOCI統合のインストール後を示しています。
-
「テナンシの追加」をクリックし、テナンシOCIDおよびホーム・リージョンの情報を入力します。
タスク2: Datadog認証リソースの作成
Oracle Cloud Infrastructure (OCI)でDatadog認証ユーザー、グループおよびポリシーを作成します。
-
ドメインを作成するには、「アイデンティティ」に移動し、
DataDog
という名前のドメインを作成します。 -
DatadogAuthGroup
というグループを作成します。 -
電子メール・アドレス(Datadogモニタリング・ツールへのログインに使用するのと同じ電子メール)を使用して
DatadogAuthUser
という名前のユーザーを作成し、グループとしてDatadogAuthGroup
を割り当てます。 -
「ユーザーOCID」をコピーし、「Datadog OCI統合タイル」の「ユーザーOCID」フィールドに貼り付けて、ユーザーOCIDを構成します。
-
APIを設定します。
-
プロファイルに移動し、ユーザー名を選択します。
-
左下隅の「リソース」に移動し、「APIキー」を選択します。
-
「APIキーの追加」をクリックし、秘密キーをダウンロードして「追加」をクリックします。
-
「構成ファイルのプレビュー」ウィンドウを閉じます。処置は不要です。
-
「フィンガープリント」値をコピーし、「Datadog OCI統合タイル」の「フィンガープリント」フィールドに貼り付けます。
-
-
秘密キーを構成します。
-
ダウンロードした秘密キー・ファイル(
.pem
)をテキスト・エディタで開くか、ターミナル・コマンド(catなど)を使用してその内容を表示します。 -
-----BEGIN PRIVATE KEY-----
および-----END PRIVATE KEY-----
行を含むキー全体をコピーします。 -
秘密キーをDatadog OCI統合タイルの「秘密キー」フィールドに貼り付けます。
-
-
postgresqlinteg
(ルート)コンパートメントにDataDogPolicy
という名前のポリシーを作成します。 -
手動エディタ・モードでポリシー・ビルダーを使用して、必要なポリシー・ステートメントを入力します。
Allow group DatadogAuthGroup to read all-resources in tenancy
次に、テナンシおよびユーザー詳細を追加した後のDatadog OCI統合タイルの例を示します。
タスク3: OCIスタックの作成
「アイデンティティ」セクションに移動し、ルート・コンパートメントの下にポリシー・スタックを作成します。これにより、コネクタ・ハブはメトリックを読み取り、次の文で関数を呼び出すことができます。
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
Datadog統合のためにOCIでアイデンティティ・ポリシーを構成し、メトリック転送スタックをデプロイするには、次のタスクに従います:
タスク3.1: ポリシー・スタックの作成(ORM_policy_stack
)
-
Datadog OCI統合タイルで「ポリシー・スタックの作成」をクリックし、提供されたリンク(必要なTerraformスクリプトを含む)を使用して、Oracle使用条件に同意します。
-
「作業ディレクトリ」ドロップダウン・メニューをクリックし、
datadog-oci-orm/policy-setup
を選択します。 -
「カスタムTerraformプロバイダの使用」の選択を解除します。
-
わかりやすい名前(
datadog-metrics-policy-setup
など)を入力し、デプロイメントするコンパートメントを選択します。 -
「次へ」をクリックし、動的グループおよびポリシーに名前を付け(またはデフォルト名を使用)、テナンシのホーム・リージョンが選択されていることを確認して、「作成」をクリックします。
タスク3.2: メトリック転送スタックの作成
リソースは、指定されたコンパートメントにデプロイされます。スタックを実行しているユーザーに適切なアクセス権があることを確認します。
-
「Datadog OCI統合」タイルで「ポリシー・スタックの作成」をクリックし、Oracle使用条件に同意します。
-
「作業ディレクトリ」ドロップダウン・メニューをクリックし、
datadog-oci-orm/metrics-setup
を選択して、「カスタムTerraformプロバイダの使用」の選択を解除します。 -
スタックに名前を付けてデプロイメント・コンパートメントを選択し、「次へ」をクリックします。
-
テナンシ値は変更せずに、Datadog APIキーを入力し、US5エンドポイント(
ocimetrics-intake.us5.datadoghq.com
)を選択します。 -
ネットワーク構成の場合、「VCNの作成」が選択されていることを確認し、VCN作成に適したコンパートメントを選択します。
-
「関数設定」セクションで、デフォルトのアプリケーション・シェイプを
GENERIC_ARM
のままにします。OCI Dockerレジストリのユーザー名とパスワード(アーティファクト・パスワード)を入力します。 -
「サービス・コネクタ・ハブ」バッチ・サイズを5000に設定し、「次へ」をクリックします。
-
「作成」をクリックします。
タスク3.3: 構成の確定
-
Datadog OCI統合タイルに戻り、「構成の作成」をクリックして設定を完了します。
-
このプロセスにより、Datadogのメトリックと機能がOCIとの統合用に適切に構成されます。
タスク4: OCIファンクションの作成
OCIコンソールでアプリケーションを作成するには、次のステップを実行します。
-
「アプリケーション」にナビゲートし、「アプリケーションの作成」を選択します。
-
アプリケーション名を入力し、適切なVirtual Cloud Network (VCN)およびサブネットの詳細を選択して、「作成」をクリックします。
-
新しく作成したアプリケーションにアクセスするには、「リソース」で「開始」を選択します。
-
「クラウド・シェルの起動」をクリックし、「リージョンのコンテキストの使用」から次のコマンドをコピーします。
fn list context fn use context <region name>
-
コンテキストを更新して、ファンクションのコンパートメントIDを含めます。
fn update context oracle.compartment-id <compartment-id>
-
コンテキストを更新して、使用するレジストリの場所を含めます。
fn update context registry phx.ocir.io/<tenancy_name>/[YOUR-OCIR-REPO]
ノート:コンテキスト内の
phx
を3桁のリージョン・コードに置き換えます。 -
authトークンをパスワードとして使用してレジストリにログインします。
docker login -u 'TENACNY_NAME/OCI_USERNAME' phx.ocir.io
-
パスワードを要求されます。適切なパスワードを指定します。
ノート:
phx
を3桁のリージョン・コードに置き換えます。- Oracle Identity Cloud Serviceを使用している場合、ユーザー名は
<tenancyname>/oracleidentitycloudservice/<username>
です。
-
hello-worldボイラープレート関数を生成します
fn list apps fn init --runtime python datadog
fn init
コマンドは、func.py
、func.yaml
およびrequirements.txt
という3つのファイルを含むdatadog
というフォルダを生成します。 -
cd datadog
コマンドを実行します。 -
func.py
を開き、ファイルの内容を次のコード・スニペットに置き換えます。# 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')
-
func.yaml
を次のコードで更新します。DATADOG_TOKEN
をDatadog APIキーに置き換え、DATADOG_HOST
をRESTエンドポイント(https://http-intake.logs.datadoghq.com/v1/input
)に置き換えます。RESTエンドポイントの詳細は、ログ収集および統合を参照してください。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
-
requirements.txt
を次のコードで更新します。fdk dattime requests oci
-
次のコマンドを実行してアプリケーションを作成し、機能をデプロイして設定を完了します。
fn create app datadog01 --annotation oracle.com/oci/subnetIds='["Provide your subnet OCID"]'
-
次のコマンドを実行してファンクションをデプロイし、設定を完了します。
fn -v deploy --app datadog
タスク5: OCIコネクタ・ハブの設定
-
OCIコンソールに移動し、「ロギング」、「コネクタ」に移動して、「コネクタの作成」をクリックします。
-
「ソース」を「モニタリング」に、「ターゲット」を「ファンクション」に設定します。
-
「ソース接続の構成」で、適切な「メトリック・コンパートメント」および「ネームスペース」を選択します。たとえば、データベース・モニタリングの場合は
oci_postgresql
です。 -
「ターゲットの構成」で、タスク4で作成した「コンパートメント」、「ファンクション・アプリケーション」および「ファンクション」を選択します。
-
プロンプトが表示されたら、「作成」をクリックして必要なポリシーを作成します。
-
「作成」をクリックして、OCIコネクタ・ハブの設定を確定します。
タスク6: Datadogでのメトリックの表示
OCI Connector Hubは、関数をトリガーするように構成され、新しいメトリックが検出されるたびにDatadogにメトリックを取り込むことができます。「Datadog統合」タイルで、「メトリック」に移動し、サマリーを確認してOCI関連のメトリックを表示します。
「Datadog統合」タイルで、「エクスプローラ」をクリックして、必要に応じて必要なOCIメトリックを分析および選択します。
トラブル・シューティング
「メトリック・サマリー」ページにデータが表示されない場合は、「ログの有効化」を選択して、ファンクションがログを確認して問題をデバッグするためのロギングを有効にします。
承認
- 著者 - Kaviya Selvaraj (上級メンバー技術スタッフ)
その他の学習リソース
docs.oracle.com/learnの他のラボを確認するか、Oracle Learning YouTubeチャネルで無料のラーニング・コンテンツにアクセスしてください。また、education.oracle.com/learning-explorerにアクセスしてOracle Learning Explorerになります。
製品ドキュメントについては、Oracle Help Centerを参照してください。
Monitor Oracle Cloud Infrastructure Database with PostgreSQL using Datadog
G28860-01
Copyright ©2025, Oracle and/or its affiliates.