Autonomous Databaseに自身のメトリックデータを取得させて表に保存する

# はじめに

Autonomous Databaseで利用可能なPL/SQL SDKを使用して、Autonomous DatabaseからOCI MonitoringにアクセスしてAutonomous Database自身のメトリック・データを取得し、表に保存することができるか検証してみました。

:::note warn
注意
こちらの記事の内容はあくまで個人の実験メモ的な内容のため、こちらの内容を利用した場合のトラブルには一切責任を負いません。
また、こちらの記事の内容を元にしたOracleサポートへの問い合わせはご遠慮ください。
:::

# 1. 事前準備

メトリックデータを格納するための表「metric_data」を作成します。
```
SQL> CREATE TABLE metric_data (
  2      dbname  VARCHAR2(255),
  3      metric  VARCHAR2(32767),
  4      time    TIMESTAMP WITH TIME ZONE,
  5      value   NUMBER
  6  );

Table created.

SQL> 
```

# 2. リソース・プリンシパルの有効化
リソース・プリンシパルを使用すると、Autonomous Databaseに対して、OCIリソースに対するアクセスを許可することができます。
リソース・プリンシパルを使用する手順は、以下の通りです。

1.対象となるAutonomous Databaseを含む動的グループを作成
2.動的グループに対して、OCIリソースへのアクセスを許可するポリシーを作成
3.adminユーザとしてAutonomous Databaseに接続し、リソース・プリンシパルを有効化

まずはじめに、使用するAutonomous Databaseを含む動的グループを作成します。
ここでは、「ADB-dg」という名前の動的グループを作成しました。
一致ルールには、単一のAutonomous Databaseにマッチするルールを以下のように設定しました
```
All {resource.id = 'Autonomous DatabaseのOCID'}
```
![スクリーンショット 2025-02-26 9.38.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/784824/0ec8ca2d-5931-47f4-ab79-736ce8346e16.png)

![スクリーンショット 2025-02-26 9.39.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/784824/94cee7b2-4ce5-4eb3-aef2-2a3a9ffd90ad.png)


次に、作成した動的グループに対してOCI Monitoringの使用を許可するポリシーを作成します。
ここでは、テナンシ内の全てのストリームの利用を許可するポリシー「ADB-use-Monitoring」をrootコンパートメントに作成しました。
ポリシー・ステートメントは、以下のように設定しました。
```
allow dynamic-group ADB-dg to read metrics in tenancy
```

最後に、adminユーザとしてAutonomous Databaseに接続し、DBMS_CLOUD_ADMIN.ENABLE_RESOURCE_PRINCIPALプロシージャを実行して、リソース・プリンシパルを有効化します。

```
EXEC DBMS_CLOUD_ADMIN.ENABLE_RESOURCE_PRINCIPAL();
```

```
SQL> EXEC DBMS_CLOUD_ADMIN.ENABLE_RESOURCE_PRINCIPAL();

PL/SQL procedure successfully completed.

SQL>
```
adminユーザ以外にリソース・プリンシパルの使用を許可する場合には、リソース・プリンシパルを有効化したあとに、以下のようにユーザ名を指定してDBMS_CLOUD_ADMIN.ENABLE_RESOURCE_PRINCIPALプロシージャを実行します。
```
EXEC DBMS_CLOUD_ADMIN.ENABLE_RESOURCE_PRINCIPAL(username => 'ADBユーザ名');
```

```
SQL> EXEC DBMS_CLOUD_ADMIN.ENABLE_RESOURCE_PRINCIPAL(username => 'adbuser');

PL/SQL procedure successfully completed.

SQL>
```

# 3. メトリック・データを取得して表にデータをINSERTするPL/SQLプロシージャの作成

OCI Monitoringから前日分のメトリック・データ（ここではCPU使用率）を取得し、表にデータをINSERTするプロシージャ「store_metric」を作成します。

各部の処理内容は、ソース内のコメントを参照してください。

::: note info
取得するメトリックの指定
この例では
**CpuUtilization[1m]{resourceId = "'||adb_ocid||'"}.max()**
の部分で、MQLで1分ごとのCPU使用率の最大値を取得するように指定しています。
**CpuUtilization[1m]** の部分を変更することで取得するメトリックと間隔を、**max()** の部分でどのような値を返すかを指定します。
例えば、max()の部分をmean()に変更することで平均値を取得することができます。
:::

```sql:store_metricプロシージャ
CREATE OR REPLACE PROCEDURE store_metric
IS
    adb_region            VARCHAR2(255);
    adb_compartment_ocid  VARCHAR2(255);
    adb_ocid              VARCHAR2(255);
    adb_name              VARCHAR2(255);

    summarize_metrics_data_detail    dbms_cloud_oci_monitoring_summarize_metrics_data_details_t := dbms_cloud_oci_monitoring_summarize_metrics_data_details_t();
	summarize_metrics_data_res       dbms_cloud_oci_mn_monitoring_summarize_metrics_data_response_t;
    summarize_metrics_data_res_body  dbms_cloud_oci_monitoring_metric_data_t;
	
    l_name       VARCHAR2(32767);
	l_timestamp  TIMESTAMP WITH TIME ZONE;
    l_value      NUMBER;

BEGIN
-- ADBのあるリージョン、ADBのコンパートメントのOCID、ADBのOCID、ADBの名前を取得
    SELECT JSON_VALUE(cloud_identity, '$.REGION'), 
           JSON_VALUE(cloud_identity, '$.COMPARTMENT_OCID'),
           JSON_VALUE(cloud_identity, '$.DATABASE_OCID'),
           JSON_VALUE(cloud_identity, '$.DATABASE_NAME')
      INTO adb_region, adb_compartment_ocid, adb_ocid, adb_name FROM v$pdbs;

-- メトリックデータ（CPU利用率）を取得するためのパラメータをセット
    summarize_metrics_data_detail.namespace  := 'oci_autonomous_database';
    summarize_metrics_data_detail.query      := 'CpuUtilization[1m]{resourceId = "'||adb_ocid||'"}.max()';
    summarize_metrics_data_detail.start_time := TO_CHAR(sysdate-1, 'DD-MON-RR')||' 12:00.00 AM +09:00';
    summarize_metrics_data_detail.end_time   := TO_CHAR(sysdate-1, 'DD-MON-RR')||' 11:59.59 PM +09:00';
	
-- メトリックデータの取得
    summarize_metrics_data_res := DBMS_CLOUD_OCI_MN_MONITORING.SUMMARIZE_METRICS_DATA(
                                      compartment_id => adb_compartment_ocid,
                                      summarize_metrics_data_details => summarize_metrics_data_detail,
                                      region => adb_region,
                                      credential_name => 'OCI$RESOURCE_PRINCIPAL'
                                  );
    summarize_metrics_data_res_body := summarize_metrics_data_res.response_body(1);
    l_name := summarize_metrics_data_res_body.name;

-- 取得したメトリックデータのデータポイントの数だけループし、ADB名、メトリック名および各データポイントのタイムスタンプと値を表にINSERT
    FOR i IN summarize_metrics_data_res_body.aggregated_datapoints.first..summarize_metrics_data_res_body.aggregated_datapoints.last LOOP
	    l_timestamp   := summarize_metrics_data_res_body.aggregated_datapoints(i).l_timestamp;
		l_value       := summarize_metrics_data_res_body.aggregated_datapoints(i).value;
        INSERT INTO metric_data VALUES ( adb_name, l_name, FROM_TZ(CAST(l_timestamp AS TIMESTAMP),'+0:00') AT TIME ZONE '+9:00', l_value );
    END LOOP;

-- コミット実行
	COMMIT;
END;
/
```

```
SQL> CREATE OR REPLACE PROCEDURE store_metric
  2  IS
  3  	 adb_region	       VARCHAR2(255);
  4  	 adb_compartment_ocid  VARCHAR2(255);
  5  	 adb_ocid	       VARCHAR2(255);
  6  	 adb_name	       VARCHAR2(255);
  7  
  8  	 summarize_metrics_data_detail	  dbms_cloud_oci_monitoring_summarize_metrics_data_details_t := dbms_cloud_oci_monitoring_summarize_metrics_data_details_t();
  9  	     summarize_metrics_data_res       dbms_cloud_oci_mn_monitoring_summarize_metrics_data_response_t;
 10  	 summarize_metrics_data_res_body  dbms_cloud_oci_monitoring_metric_data_t;
 11  
 12  	 l_name       VARCHAR2(32767);
 13  	     l_timestamp  TIMESTAMP WITH TIME ZONE;
 14  	 l_value      NUMBER;
 15  
 16  BEGIN
 17  -- ADBのあるリージョン、ADBのコンパートメントのOCID、ADBのOCID、ADBの名前を取得
 18  	 SELECT JSON_VALUE(cloud_identity, '$.REGION'),
 19  		JSON_VALUE(cloud_identity, '$.COMPARTMENT_OCID'),
 20  		JSON_VALUE(cloud_identity, '$.DATABASE_OCID'),
 21  		JSON_VALUE(cloud_identity, '$.DATABASE_NAME')
 22  	   INTO adb_region, adb_compartment_ocid, adb_ocid, adb_name FROM v$pdbs;
 23  
 24  -- メトリックデータ（CPU利用率）を取得するためのパラメータをセット
 25  	 summarize_metrics_data_detail.namespace  := 'oci_autonomous_database';
 26  	 summarize_metrics_data_detail.query	  := 'CpuUtilization[1m]{resourceId = "'||adb_ocid||'"}.max()';
 27  	 summarize_metrics_data_detail.start_time := TO_CHAR(sysdate-1, 'DD-MON-RR')||' 12:00.00 AM +09:00';
 28  	 summarize_metrics_data_detail.end_time   := TO_CHAR(sysdate-1, 'DD-MON-RR')||' 11:59.59 PM +09:00';
 29  
 30  -- メトリックデータの取得
 31  	 summarize_metrics_data_res := DBMS_CLOUD_OCI_MN_MONITORING.SUMMARIZE_METRICS_DATA(
 32  					   compartment_id => adb_compartment_ocid,
 33  					   summarize_metrics_data_details => summarize_metrics_data_detail,
 34  					   region => adb_region,
 35  					   credential_name => 'OCI$RESOURCE_PRINCIPAL'
 36  				       );
 37  	 summarize_metrics_data_res_body := summarize_metrics_data_res.response_body(1);
 38  	 l_name := summarize_metrics_data_res_body.name;
 39  
 40  -- 取得したメトリックデータのデータポイントの数だけループし、ADB名、メトリック名および各データポイントのタイムスタンプと値を表にINSERT
 41  	 FOR i IN summarize_metrics_data_res_body.aggregated_datapoints.first..summarize_metrics_data_res_body.aggregated_datapoints.last LOOP
 42  		 l_timestamp   := summarize_metrics_data_res_body.aggregated_datapoints(i).l_timestamp;
 43  		     l_value	   := summarize_metrics_data_res_body.aggregated_datapoints(i).value;
 44  	     INSERT INTO metric_data VALUES ( adb_name, l_name, FROM_TZ(CAST(l_timestamp AS TIMESTAMP),'+0:00') AT TIME ZONE '+9:00', l_value );
 45  	 END LOOP;
 46  
 47  -- コミット実行
 48  	     COMMIT;
 49  END;
 50  /

Procedure created.

SQL> 
```

PL/SQLプロシージャ「store_metric」が作成できました。

# 4. PL/SQLプロシージャの動作確認

現在の日付を確認します。
```
SQL> SELECT sysdate;

SYSDATE
---------
06-MAR-25

SQL>
```

表「metric_data」にデータががないことを確認します。
```
SQL> SELECT * FROM metric_data;

no rows selected

SQL>
```

プロシージャ「store_metric」を実行してみます。
```
SQL> EXEC store_metric;

PL/SQL procedure successfully completed.

SQL>
```
表「metric_data」の内容を確認してみます。
```
SQL> col dbname for a12
SQL> col metric for a15
SQL> col time for a40
SQL> SELECT * FROM metric_data ORDER BY time;

DBNAME	     METRIC	         TIME					                  VALUE
------------ --------------- ---------------------------------------- ----------
ATP23AITEST  CpuUtilization  05-MAR-25 12.00.00.000000 AM +09:00      .023684818
ATP23AITEST  CpuUtilization  05-MAR-25 12.01.00.000000 AM +09:00      .012627746
ATP23AITEST  CpuUtilization  05-MAR-25 12.02.00.000000 AM +09:00      .011090389
ATP23AITEST  CpuUtilization  05-MAR-25 12.03.00.000000 AM +09:00      .033581999
ATP23AITEST  CpuUtilization  05-MAR-25 12.04.00.000000 AM +09:00       .01290273
ATP23AITEST  CpuUtilization  05-MAR-25 12.05.00.000000 AM +09:00      .033866887
ATP23AITEST  CpuUtilization  05-MAR-25 12.06.00.000000 AM +09:00      .021267195
ATP23AITEST  CpuUtilization  05-MAR-25 12.07.00.000000 AM +09:00      .012295399
ATP23AITEST  CpuUtilization  05-MAR-25 12.08.00.000000 AM +09:00      .013251389
ATP23AITEST  CpuUtilization  05-MAR-25 12.09.00.000000 AM +09:00       .01225542
ATP23AITEST  CpuUtilization  05-MAR-25 12.10.00.000000 AM +09:00       1.8039693
＜中略＞
ATP23AITEST  CpuUtilization  05-MAR-25 11.50.00.000000 PM +09:00      .066233702
ATP23AITEST  CpuUtilization  05-MAR-25 11.51.00.000000 PM +09:00      .011639696
ATP23AITEST  CpuUtilization  05-MAR-25 11.52.00.000000 PM +09:00       .03958063
ATP23AITEST  CpuUtilization  05-MAR-25 11.53.00.000000 PM +09:00       .01205107
ATP23AITEST  CpuUtilization  05-MAR-25 11.54.00.000000 PM +09:00      .013237561
ATP23AITEST  CpuUtilization  05-MAR-25 11.55.00.000000 PM +09:00      .013523452
ATP23AITEST  CpuUtilization  05-MAR-25 11.56.00.000000 PM +09:00      .012499312
ATP23AITEST  CpuUtilization  05-MAR-25 11.57.00.000000 PM +09:00      .038647072
ATP23AITEST  CpuUtilization  05-MAR-25 11.58.00.000000 PM +09:00	  .0130181
ATP23AITEST  CpuUtilization  05-MAR-25 11.59.00.000000 PM +09:00      2.29321611

1440 rows selected.

SQL>
```

プロシージャ「store_metric」を実行して、前日分のメトリックデータを表「metric_data」に格納できることが確認できました。

# 参考情報
・[Obtain Tenancy Details](https://docs.oracle.com/en/cloud/paas/autonomous-database/serverless/adbsb/autonomous-database-support-ocid.html#GUID-C2B866BD-379D-46AA-9277-DC78F974FAD2)
・[BMS_CLOUD_OCI_MN_MONITORING.SUMMARIZE_METRICS_DATA Function](https://docs.oracle.com/en-us/iaas/Content/pl-sql-sdk/doc/dbms_cloud_oci_mn_monitoring.html#ADSDK-GUID-969FC89C-4878-47BA-851D-584F82B56B1B)
・[DBMS_CLOUD_OCI_MONITORING_SUMMARIZE_METRICS_DATA_DETAILS_T Type](https://docs.oracle.com/en-us/iaas/Content/pl-sql-sdk/doc/monitoring_t.html#ADSDK-GUID-556580A0-3D34-4F04-86FB-D8B3DA920649)
・[DBMS_CLOUD_OCI_MN_MONITORING_SUMMARIZE_METRICS_DATA_RESPONSE_T Type](https://docs.oracle.com/en-us/iaas/Content/pl-sql-sdk/doc/dbms_cloud_oci_mn_monitoring_t.html#ADSDK-GUID-9A3CBEF0-8F61-40FD-B75F-9B0F17C5C828)
・[DBMS_CLOUD_OCI_MONITORING_METRIC_DATA_TBL Type](https://docs.oracle.com/en-us/iaas/Content/pl-sql-sdk/doc/dbms_cloud_oci_mn_monitoring_t.html#ADSDK-GUID-ED095F05-E1F9-4844-80EF-5B736DEF6C9E)
・[DBMS_CLOUD_OCI_MONITORING_METRIC_DATA_T Type](https://docs.oracle.com/en-us/iaas/Content/pl-sql-sdk/doc/monitoring_t.html#ADSDK-GUID-A2F46864-3635-485E-8FD7-A945CBB0B288)