1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

1. はじめに

AWS の RDS for Oracle や Aurora では、アラートログや監査ログを CloudWatch Logs に連携し、メトリクスフィルタや CloudWatch Alarm でエラーを検知してメール通知する、という監視がチェックボックス1つで設定できます。ログをためる場所(CloudWatch Logs)と、気づく仕組み(Alarm + SNS)がマネージドサービスとして用意されているからです。

一方 OCI の Autonomous Database(以下 ADB)は、フルマネージドゆえに OS にアクセスできず、CloudWatch エージェント相当をホストに入れることもできません。では「ログを監視して、エラーが出たら気づく」を ADB でどう作るのか。SQLcl や MCP で ADB を触ってきた延長で、AWS の CloudWatch ログ監視に当たる運用を ADB-S(Serverless)で一通り組んでみた、というのが本記事です。

なお Oracle は ADB を「自律運用(self-driving / self-repairing)」と位置づけ、監視・チューニング・パッチを自動化するため 手動のデータベース監視は不要 としています1。もっとも、アプリ起因の ORA エラーのように「自分のワークロード側で起きたこと」に気づきたい場面は残り、本当に監視ゼロでよいかは意見が分かれます。本記事は、その最小限の「気づき」の部分をなるべくマネージドな部品だけで用意してみる試みでもあります。

結論を先に箇条書きでまとめます。

  • 26ai の ADB-S では、従来の V$DIAG_ALERT_EXT がアラートログ用途では使えなくなり、クライアントエラーは V$CLIENT_ERRORS で見る
  • 「ためる」は DBMS_CLOUD_PIPELINEV$CLIENT_ERRORS を Object Storage へ差分エクスポートする(エージェント不要)
  • 「気づく」は新着エラーを OCI Notifications(ONS) に publish し、登録したメール宛に通知する(AWS の SNS 相当、エージェント不要)
  • CloudWatch では1つに見える機能が、OCI では「ためる」と「気づく」を別々のサービスで組み合わせる形になる

今回の検証ゴール

# 検証項目
1 26ai の ADB-S でクライアントエラーを V$CLIENT_ERRORS から取得できる
2 DBMS_CLOUD_PIPELINEV$CLIENT_ERRORS を Object Storage へ差分エクスポートできる
3 新着エラーを OCI Notifications(ONS)へ流し、メールで気づける

検証環境

項目 内容
Autonomous Database ADB-S(Autonomous Transaction Processing)、バージョン 23.26.2.2.0(26ai)
リージョン ap-tokyo-1(東京)
ためる先 OCI Object Storage(バケット adb-log-monitor
気づく経路 OCI Notifications(トピック adb-error-alerts + メール通知の登録)

2. 全体構成と AWS との対比

CloudWatch のログ監視を分解すると「ログをためる」と「気づいて通知する」の2段です。これを ADB-S の部品に対応させると次のようになります。

役割 AWS(RDS for Oracle) OCI(ADB-S 26ai)
エラーの取得元 alert log → CloudWatch Logs V$CLIENT_ERRORS(SQL で照会)
ためる CloudWatch Logs DBMS_CLOUD_PIPELINE → Object Storage
気づく(検知) メトリクスフィルタ + Alarm 新着行をジョブで抽出(作りこみ)
通知 SNS トピック → メール OCI Notifications(ONS)トピック → メール
エージェント 不要(マネージド) 不要(すべて DB 内 PL/SQL + OCI サービス)

CloudWatch では1機能に見える部分が、OCI では Object Storage(ためる)と Notifications(気づく)という別サービスの組み合わせになります。全体像は次の通りです。

「ためる」(Object Storage)と「気づく」(Notifications)は独立しています。長期保管・後から分析したいなら前者、リアルタイムにエラーを知りたいなら後者、という役割分担です。


3. エラーを取得する:V$CLIENT_ERRORS

26ai の ADB-S では、従来アラートログを SQL で読んでいた V$DIAG_ALERT_EXT がアラートログ用途では使えなくなり、公式ドキュメントもクライアントエラーの照会には V$CLIENT_ERRORS を案内しています2。この移行(V$DIAG_ALERT_EXT が 26ai で参照できなくなった件)は別記事で検証済みのため、本記事では V$CLIENT_ERRORS を使う前提で進めます3

3.1. V$CLIENT_ERRORS でエラーを取得する

V$CLIENT_ERRORS は、クライアントが受け取ったエラー(ORA エラー)を保持します。主な列は次の通りです。

内容
ERROR_NUM ORA エラー番号(942 など)
ERROR_MESSAGE エラーメッセージ
ERROR_TIME 発生時刻(UTC
SID / SERIAL# セッション識別子
MODULE / ACTION DBMS_APPLICATION_INFO で設定される呼び出し元情報

わざと存在しない表を引いてエラーを起こし、取得してみます。

-- わざとエラーを起こす
SELECT * FROM this_table_does_not_exist;
-- ORA-00942: ...

-- 取得
SELECT error_num, error_time, module, SUBSTR(error_message,1,60) AS msg
FROM   v$client_errors
ORDER  BY error_time DESC
FETCH FIRST 5 ROWS ONLY;
   ERROR_NUM ERROR_TIME           MODULE   MSG
   --------- -------------------- -------- --------------------------------------
         942 2026-06-26 13:13:42  SQLcl    ORA-00942: 表またはビュー ...は存在しません

起こしたエラーが番号・時刻・メッセージ付きで取得できました。MODULE 列には呼び出し元(接続クライアントやアプリ名)が入ります。アプリ側で DBMS_APPLICATION_INFO.SET_MODULE を呼んでおけば「どのアプリ/バッチ由来のエラーか」を識別できます。

ERROR_TIME は UTC で保存されます。JST で扱いたい場合は FROM_TZ(error_time,'UTC') AT TIME ZONE 'Asia/Tokyo' で変換します。後述の通知本文でもこの変換を使います。


4. ためる:Object Storage へ差分エクスポートする

4.1. なぜ DBMS_CLOUD_PIPELINE か

V$CLIENT_ERRORS を定期的に外へ書き出す方法はいくつかあります。DBMS_CLOUD.EXPORT_DATADBMS_SCHEDULER で回す手書き方式でも可能ですが、今回は DBMS_CLOUD_PIPELINE を使いました4。継続的な差分エクスポート・スケジュール実行・並列処理・状態テーブルでの監視が最初から備わっており、手書きより取り回しが楽だからです。

監査ログ(UNIFIED_AUDIT_TRAIL)には Oracle 提供のプリセットパイプライン ORA$AUDIT_EXPORT がありますが、クライアントエラー用のプリセットはありません。そこで query 属性を使ったカスタムのエクスポートパイプラインを組みます。

4.2. 認証:リソース・プリンシパル

パイプラインが Object Storage に書き込むための認証には リソース・プリンシパル を使います。API キーやパスワードを DB 内に保存せず、ADB 自身を OCI のプリンシパルとして認証させる仕組みで、資格情報の持ち回りが要りません。ADMIN で1回有効化します。

-- ADMIN で実行(DBMS_CLOUD_ADMIN は ADMIN 権限が必要)
EXEC DBMS_CLOUD_ADMIN.ENABLE_RESOURCE_PRINCIPAL();

OCI 側では、この ADB を表すダイナミックグループと、バケットへの書き込みを許可するポリシーを作成します(OCI CLI の例)。

# ADB をマッチするダイナミックグループ
oci iam dynamic-group create --name adb-log-dg \
  --description "ADB resource principal" \
  --matching-rule "ALL {resource.id = '<adb-ocid>'}"

# バケットへの書き込みを許可するポリシー
# Allow dynamic-group adb-log-dg to read buckets in compartment test01
# Allow dynamic-group adb-log-dg to manage objects in compartment test01 where target.bucket.name='adb-log-monitor'

4.3. カスタムエクスポートパイプライン

V$CLIENT_ERRORS直接 query 属性に指定してエクスポートできます(中間テーブルは不要でした)。差分の追跡キーには ERROR_TIME を使います。

-- パイプライン作成
BEGIN
  DBMS_CLOUD_PIPELINE.CREATE_PIPELINE(
    pipeline_name => 'EXPORT_CLIENT_ERRORS',
    pipeline_type => 'EXPORT',
    description   => 'Export V$CLIENT_ERRORS to Object Storage');
END;
/

-- 属性設定(リソース・プリンシパル / 出力先 / クエリ / 差分キー / 形式 / 間隔)
BEGIN
  DBMS_CLOUD_PIPELINE.SET_ATTRIBUTE(
    pipeline_name => 'EXPORT_CLIENT_ERRORS',
    attributes    => JSON_OBJECT(
      'credential_name' VALUE 'OCI$RESOURCE_PRINCIPAL',
      'location'        VALUE 'https://objectstorage.ap-tokyo-1.oraclecloud.com/n/<namespace>/b/adb-log-monitor/o/client_errors/',
      'query'           VALUE 'SELECT error_num, error_message, error_time, sid, serial#, module, action FROM v$client_errors',
      'format'          VALUE '{"type":"json"}',
      'key_column'      VALUE 'ERROR_TIME',
      'interval'        VALUE '1'));   -- interval は分単位('1' = 1分間隔)
END;
/

4.4. テスト実行と本番実行の違い(ハマりどころ)

まず RUN_PIPELINE_ONCE でテスト実行すると、Object Storage に JSON Lines(1行1エラー)が出力されます。

EXEC DBMS_CLOUD_PIPELINE.RUN_PIPELINE_ONCE('EXPORT_CLIENT_ERRORS');
{"ERROR_NUM":1476,"ERROR_MESSAGE":" ORA-01476: 除数がゼロです\n ","ERROR_TIME":"2026-06-26T13:55:09","SID":52913,"MODULE":"claude-opus-4-8","ACTION":"connect "}
{"ERROR_NUM":1722,"ERROR_MESSAGE":" ORA-01722: ...","ERROR_TIME":"2026-06-26T13:55:13", ...}

ここで一点注意があります。RUN_PIPELINE_ONCE は差分のウォーターマークを進めません。テスト用途のため、新しいエラーを足してもう一度 RUN_PIPELINE_ONCE しても、新しいファイルは作られませんでした。差分エクスポートを実際に動かすには、スケジュール実行の START_PIPELINE を使います。

EXEC DBMS_CLOUD_PIPELINE.START_PIPELINE('EXPORT_CLIENT_ERRORS');

開始後は interval ごとに動き、状態は USER_CLOUD_PIPELINE_HISTORY で確認できます(毎分 SUCCEEDED で記録されました)。この状態で新しいエラーを1件起こすと、次の実行で新規分だけが別ファイルとして出力されます。

// 新エラー発生後に追加された差分ファイル(新規2件のみ)
{"ERROR_NUM":904,"ERROR_MESSAGE":" ORA-00904: ...","ERROR_TIME":"2026-06-26T14:04:50", ...}
{"ERROR_NUM":942,"ERROR_MESSAGE":" ORA-00942: ...BRAND_NEW_MISSING_TABLE...","ERROR_TIME":"2026-06-26T14:05:30", ...}

差分(ERROR_TIME をキーにした新規分だけの出力)になっていることを確認できました。

ただし、ここまでで「ためる」はできても、それ自体は監視ではありません。出力先の Object Storage は貯まっていくだけで、エラーが出たことに気づくにはもう1段必要です。それが次章です。


5. 気づく:新着を OCI Notifications(ONS)へ送る

5.1. 設計方針:V$CLIENT_ERRORS の新着を「素直に」拾う

「気づく」を作るうえで、最初に押さえておきたい制約があります。V$CLIENT_ERRORS には INSERT トリガを仕掛けられません。これは実テーブルではなく動的パフォーマンスビュー(内部の X$ 固定表のラッパ)で、行は SQL の INSERT ではなくインスタンスが内部的に記録するため、「INSERT イベント」自体が存在しないからです。

そこで本記事では、ERROR_TIME のウォーターマークで新着行を抽出し、エラー番号でのフィルタをかけず(=意志を入れず)にそのまま ONS へ流す方針にしました。何を重要とみなすかの判断は V$CLIENT_ERRORS が記録した内容に委ね、こちらは新着をそのまま通知します。検知の遅延はジョブの実行間隔ぶん(1分なら最大1分)で、これが動的ビューを相手にする以上の下限です。

通知先に OCI Notifications(ONS)を選ぶ理由
ONS は AWS の SNS に当たるサービスで、トピックにメールなどの通知先を登録しておきます。DB から直接 SMTP でメールを送る方法もありますが、ONS はトピックへ publish するだけで配信を任せられ、通知先の追加・差し替えも容易です。

5.2. ONS トピックとメール通知先を用意する

OCI CLI でトピックを作り、メールアドレスを通知先として登録します。登録(サブスクリプション)は、メールの確認リンクをクリックするまで PENDING です。

# トピック作成
oci ons topic create --name adb-error-alerts --compartment-id <compartment-ocid>

# メール通知先の登録(確認メールが届く → リンクをクリックで ACTIVE)
oci ons subscription create --compartment-id <compartment-ocid> \
  --topic-id <topic-ocid> --protocol EMAIL \
  --subscription-endpoint your-address@example.com

確認メールのリンクをクリックすると、メール通知が有効化されます。

メール通知先の確認(Subscription confirmed)

ADB のリソース・プリンシパルがトピックへ publish できるよう、ポリシーも追加します。

Allow dynamic-group adb-log-dg to use ons-topics in compartment test01

5.3. 新着エラーを ONS に publish する

ONS への publish は、PublishMessage API を DBMS_CLOUD.SEND_REQUEST でリソース・プリンシパル認証で叩きます5。Object Storage と同じく OCI サービス宛のため、ネットワーク ACL の追加は不要でした(HTTP 202 Accepted が返ります)。

送信先ホストはトピックごとに割り当てられる publish エンドポイントで、oci ons topic get --topic-id <ocid> --query 'data."api-endpoint"' で確認できます(東京リージョンでは https://cell1.notification.ap-tokyo-1.oraclecloud.com のような形になり、先頭の cell1 は環境によって変わります)。

ウォーターマークを保持する小さな表を用意し、新着行だけを抽出して publish する手続きにします。

-- ウォーターマーク(1行)。初期値は現時点の最新エラー時刻にしておく
CREATE TABLE client_error_wm(last_error_time TIMESTAMP);
INSERT INTO client_error_wm
  SELECT NVL(MAX(error_time), SYS_EXTRACT_UTC(SYSTIMESTAMP)) FROM v$client_errors;
COMMIT;
CREATE OR REPLACE PROCEDURE publish_new_client_errors AS
  v_wm   TIMESTAMP;
  v_new  TIMESTAMP;
  v_cnt  NUMBER;
  v_body VARCHAR2(8000);
  resp   DBMS_CLOUD_TYPES.RESP;
  -- ホストはトピックの publish エンドポイント(oci ons topic get の api-endpoint)。cell 番号は環境依存
  c_uri  CONSTANT VARCHAR2(400) :=
    'https://cell1.notification.ap-tokyo-1.oraclecloud.com/20181201/topics/<topic-ocid>/messages';
BEGIN
  SELECT last_error_time INTO v_wm FROM client_error_wm FOR UPDATE;

  -- 新着行のみ(フィルタなし=V$CLIENT_ERRORS が記録したものをそのまま)
  SELECT COUNT(*), MAX(error_time),
         LISTAGG(TO_CHAR(FROM_TZ(error_time,'UTC') AT TIME ZONE 'Asia/Tokyo','MM-DD HH24:MI:SS')
                 ||' JST  ['||NVL(module,'-')||']  '
                 ||REPLACE(SUBSTR(error_message,1,160),CHR(10),' '),
                 CHR(10) ON OVERFLOW TRUNCATE) WITHIN GROUP (ORDER BY error_time)
  INTO v_cnt, v_new, v_body
  FROM v$client_errors
  WHERE error_time > v_wm;

  IF v_cnt > 0 THEN
    resp := DBMS_CLOUD.SEND_REQUEST(
      credential_name => 'OCI$RESOURCE_PRINCIPAL',
      uri    => c_uri,
      method => 'POST',
      body   => UTL_RAW.CAST_TO_RAW(JSON_OBJECT(
                  'title' VALUE '[ADB-S adbtest02] client errors '||v_cnt||' 件',
                  'body'  VALUE '新規クライアントエラー '||v_cnt||' 件'||CHR(10)||CHR(10)||v_body)));
    -- publish 成功(2xx)時だけウォーターマークを前進(失敗時は次回再送)
    IF DBMS_CLOUD.GET_RESPONSE_STATUS_CODE(resp) IN (200,201,202) THEN
      UPDATE client_error_wm SET last_error_time = v_new;
    END IF;
  END IF;
  COMMIT;
END;
/

これを DBMS_SCHEDULER で定期実行します(例では毎分。連続通知を避けたい間は無効のままにしておけます)。

BEGIN
  DBMS_SCHEDULER.CREATE_JOB(
    job_name        => 'PUBLISH_CLIENT_ERRORS_JOB',
    job_type        => 'STORED_PROCEDURE',
    job_action      => 'PUBLISH_NEW_CLIENT_ERRORS',
    start_date      => SYSTIMESTAMP,
    repeat_interval => 'FREQ=MINUTELY;INTERVAL=1',
    enabled         => FALSE);
END;
/

5.4. 動作確認

新しいエラーを1件起こして手続きを実行すると、ONS 経由でメールが届きました。本文には発生時刻(JST)・モジュール・メッセージが並びます。

ONS から届いたアラートメール

publish_new_client_errors は publish が 2xx を返したときだけウォーターマークを前進させるので、配信に失敗した分は次回に再送されます。これで「新着エラーを拾って ONS へ送り、メールで気づく」までがエージェントなしでつながりました。


6. 考察

6.1. なぜトリガで即時発火させないか

AFTER SERVERERROR ON DATABASE トリガを使えばエラー発生の瞬間に発火させられます(ADB-S でも作成でき、特定の ORA 番号でのフィルタも可能でした)。ただし「どの ORA 番号を拾うか」を手で決める恣意性と、エラー多発時に毎回ネットワーク往復が走る負荷があり、汎用監視には向きません。今回はトリガを使わず、新着を後追いで拾う方式にしています。

6.2. 「ためる」と「気づく」は別物

CloudWatch では1つに見えても、OCI では Object Storage への蓄積(4章)と Notifications での通知(5章)は独立した部品です。長期保管や後追い分析は前者、リアルタイムの気づきは後者、と役割が分かれます。今回は両方を組みましたが、用途によってどちらか一方だけでも構いません。

6.3. エージェント要否

ADB のログを OCI Logging Analytics に取り込む経路は、JDBC 接続できるホストに 管理エージェント を置く必要があります。今回の経路(V$CLIENT_ERRORS + DBMS_CLOUD_PIPELINE + DBMS_CLOUD.SEND_REQUEST + ONS)は、すべて DB 内の PL/SQL と OCI サービスの組み合わせで完結し、エージェントを1つも置かずに「ためる+気づく」を実現できました。AWS の CloudWatch ログ連携に近い使い勝手です。

6.4. この構成の前提と限界

  • V$CLIENT_ERRORS はすべてのエラーを拾うわけではない:クライアントが受け取るエラーが対象で、サーバー内部で完結する事象などは含まれないと考えられます。何が記録対象かはワークロードで確認するのが安全です
  • 遅延の下限はジョブ間隔:動的ビューに push 機構が無い以上、ポーリング間隔より速くは気づけません。秒単位が要るなら別アーキテクチャ(イベント駆動)の検討が必要です
  • 大量エラー時の通知抑制:新着を素直に全部流すと、エラーストーム時にメールが大量になります。実運用では件数の要約や重大度での絞り込み、一定時間のまとめ送信などが要ると考えられます

6.5. 自前ウォーターマークと、マネージドな代替

本記事では「メールにエラー内容を載せたい」ため、新着抽出のロジックを DB 内(ウォーターマーク+手続き)に置きました。これをよりマネージド寄りにする選択肢もあります。

  • 新着が出た「合図」だけでよい場合:パイプラインは新着があるときだけ新しいオブジェクトを作るので、その object-create を OCI Events で拾って Notifications に流せば、ウォーターマークも手続きも要りません。ただしメール本文はオブジェクト名などのイベント情報に限られます
  • 内容入りメールをマネージドで作る場合:Events と Notifications の間に OCI Functions(サーバーレス)を挟み、新しいオブジェクトを読んで整形します。サーバー管理は不要ですが関数のコードとデプロイが必要で、結局「ロジックをどこに置くか」が DB から Functions へ移るだけです

エラー内容まで欲しいならロジックは DB か Functions のどちらかに必要で、今回は取り回しのよい DB 内に置いた、という整理です。なお「ためる」側のパイプラインは差分を key_column で内部管理するため、こちらに自前のウォーターマークは要りません。


7. まとめ

# 検証項目 結論
1 V$CLIENT_ERRORS でエラー取得 取得できた。26ai では V$DIAG_ALERT_EXT は使えず、V$CLIENT_ERRORS に移行が必要
2 Object Storage へ差分エクスポート DBMS_CLOUD_PIPELINEV$CLIENT_ERRORS を直接 query 指定し、START_PIPELINE で差分エクスポートできた
3 ONS でメール通知 新着をフィルタせず ONS へ publish し、メールで気づけた。エージェント不要

AWS の CloudWatch でチェックボックス1つで設定できる「ログ監視→アラート」は、ADB-S では「V$CLIENT_ERRORS を読む」「DBMS_CLOUD_PIPELINE でためる」「ジョブで新着を拾って ONS で気づく」という部品の組み合わせが必要ですが、エージェントなしに似たようなことは再現できました。

参考

  1. Oracle 公式 — What Is an Autonomous AI Database?(自律運用・監視自動化の位置づけ) https://www.oracle.com/autonomous-database/what-is-autonomous-database/

  2. Oracle 公式(日本語)— Autonomous AI Database Serverless「クライアント・エラーのクエリー」 https://docs.oracle.com/ja-jp/iaas/autonomous-database-serverless/doc/autonomous-query-alert-log.html

  3. 拙記事 — 26ai の ADB-S でアラートログの取得方法が変わった件(V$DIAG_ALERT_EXTV$CLIENT_ERRORShttps://qiita.com/asahide/items/ddcdb7b15779feddbe1f

  4. Oracle 公式 — DBMS_CLOUD_PIPELINE(Oracle Database 26 PL/SQL Packages Reference, 第51章) https://docs.oracle.com/en/database/oracle/oracle-database/26/arpls/dbms_cloud_pipeline1.html

  5. Oracle 公式 — DBMS_CLOUD SEND_REQUEST Function / OCI Notifications PublishMessage API https://docs.oracle.com/en-us/iaas/Content/Notification/Tasks/publishingmessages.htm

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?