※ 本記事は、Martin Bachによる”An Introduction to Post Execution Debugging in Oracle 23c Free – Developer Release“を翻訳したものです。

2023年8月22日


Oracle 23c Free – Developer Releaseでの実行後のデバッグ

デバッグ・プロファイルをライブJavaScriptコードにアタッチできても、必要なときにのみ接続できれば問題ありませんか? 監視する変数を指定し、特定の条件下でその値をレポートできる間、可能なかぎり最小限の侵入効果を持つものがありますか? これは、実行後のデバッグに役立ちます。

変数および格納する値に関するインサイトを取得する必要がある場合があります。前の記事fetch()の例を続けると、APIに誤りがある場合にREST APIコールからフェッチされた値を記録するタスクがあると仮定します。この記事で使用されるREST-APIはORDSによって提供されます。employees表の値をJSONとして返します。Database Actionsを使用すると、実行後のデバッグを有効にして結果を表示することは非常に簡単です。

データのフェッチに使用される関数は、便宜上ここで繰り返されます。

/**
 * use the fetch() API to retrieve data from a remote source
 * @param {string} url - the URL from where to fetch. Requires an ACE
 * @returns {json} the resulting JSON data
 */
export async function fetchExample(url) {

    if (url === undefined || url.length < 0) {
        throw new Error("please provide a URL");
    }

    try {
        const response = await fetch(
            url,
            {
                credentials: "include"
            }
        );

        if (! response.ok) {
            throw new Error(`A network error occurred: ${response.status}`);
        }

        const jsonData = await response.json();

        return jsonData;
    } catch (err) {
        throw err;
    }
}

fetchExample()は、FETCH_DEMO_MODULEという名前のJavaScriptモジュールの一部として提供され、関数の形式でのコール仕様(fetch_example())も使用できます。次の図は、Database Actionsでレンダリングされるモジュールのコードを示しています。

MLE module

この例は、実行後のデバッグに簡単に集中できることに注意してください。実際のアプリケーションでは、認証および認可にOAuth2を使用します。

この記事の残りの部分では、MLE JSエディタを使用してORDS 23.2.0インスタンスにログインしていることを前提としています。

正しいURLを指定すると、コードによってORDSインスタンスからJSONがフェッチされます。:

SQL> SELECT
  2      JSON_SERIALIZE(fetch_example(
  3          'https://1.2.3.4:8443/ords/freepdb1/emily/employees/100'
  4*     ) PRETTY) AS jsonData;

JSONDATA
____________________________________________________________________ 
{
  "department_id" : 90,
  "salary" : 24000,
  "manager_id" : null,
  "commission_pct" : null,
  "hire_date" : "2013-06-17T00:00:00Z",
  "first_name" : "Steven",
  "email" : "SKING",
  "employee_id" : 100,
  "phone_number" : "1.515.555.0100",
  "links" :
  [
    {
      "rel" : "self",
      "href" : "https://1.2.3.4:8443/ords/freepdb1/emily/employees/100"
    },
    {
      "rel" : "edit",
      "href" : "https://1.2.3.4:8443/ords/freepdb1/emily/employees/100"
    },
    {
      "rel" : "describedby",
      "href" : "https://1.2.3.4:8443/ords/freepdb1/emily/metadata-catalog/employees/item"
    },
    {
      "rel" : "collection",
      "href" : "https://1.2.3.4:8443/ords/freepdb1/emily/employees/"
    }
  ],
  "last_name" : "King",
  "job_id" : "AD_PRES"
}

実行後デバッグを使用したJavaScriptコードのデバッグ

実行後のデバッグでは、JSON形式のデバッグ仕様を定義する必要があります。デバッグ仕様では、結合によって1つ以上のアクションを定義します。

  • JavaScriptモジュール名
  • プローブが起動するモジュールを示す行番号
  • プローブのタイプ(ウォッチポイントまたはスナップショット)

前提条件

実行後デバッグの使用を開始する前に、MLE環境を定義する必要があります。Database Actionsはこれにも役立ちます。この記事で使用されるMLE環境定義のスクリーンショットを次に示します。

MLE environment

MLEモジュールと環境が作成された状態で、デバッグを開始します。

デバッグ仕様の作成

次の「Snippets」タブに切り替えます。これにより、データベースで任意のJavaScriptコードを実行できます。次の図に示すドロップダウン・メニューを使用して、デバッグ仕様ウィザードに入ります。

Steps to create a debug specification

デバッグするモジュール(FETCH_DEMO_MODULE))を右側のドロップダウンから選択します。次に、デバッグ仕様を手動で入力するか、提供されているテンプレートのいずれかを使用できます。

Using snapshot and watch templates

この例では、次のように読むことにしました

  • 関数に渡されるURL
  • fetch()コールによって返されたJSONデータ

次の図に示す最後のデバッグ仕様では、それだけを実行できます。

Final debug specification

デバッグ

次に実行する必要があるのは、ORDSから一部のJSONをフェッチして、目的の変数を記録することです。この場合は、コード例に示されている架空のURLからフェッチしています。結果のjsonDataをコンソールに出力する必要もなく、実行後のデバッグ・エンジンによって変数のコンテンツがフェッチされます。次のコードをエディタに貼り付け、デバッグ・アイコンを押してプロセスを開始します。

(async() => {

    const { fetchExample } = await import ("fetchDemo");
    const jsonData = await fetchExample("https://1.2.3.4/ords/freepdb1/emily/employees/");

    console.log(`data fetched successfully`);
})();

デバッグ・コンソールには、JavaScriptエンジンによって検査される変数が表示されます。プローブが起動するたびに、記録されたデータとともに行番号が出力されます。次の図に出力が表示されます。:

Debug output shown in the console

小さい三角形をクリックすると、セクションが展開され、取得した値とともに変数が表示されます。変数をクリックすると、コードの場所が表示され、追加のコンテキストが提供されます。

PL/SQLを使用したデバッグ

アプリケーションでストアド・コードが適切に使用されている場合は、デバッグを有効にしてコードを実行できることがわかります。ここでは、GUIで使用されているものと同じデバッグ仕様を実行コンテキストに接続し、同じ情報を記録する方法の非常に基本的な例を示します。GUIで表示されるのではなく、テキスト表現が選択されています。

DECLARE
    l_debugspec JSON;
    l_debugsink BLOB;
    l_debugtext JSON;
    l_js_code   CLOB;
    l_data      JSON;
    -- l_ctx       dbms_mle.context_handle_t;
BEGIN
    l_debugspec := JSON(q'~
{
    "version": "1.0",
    "debugpoints": [
        {
            "at": {
                "name": "FETCH_DEMO_MODULE",
                "line": 12
            },
            "actions": [
                {
                    "type": "watch",
                    "id": "url"
                }
            ]
        },
        {
            "at": {
                "name": "FETCH_DEMO_MODULE",
                "line": 30
            },
            "actions": [
                {
                    "type": "watch",
                    "id": "jsonData"
                }
            ]
        }
    ]
}
~');

    dbms_lob.createTemporary(l_debugsink, true, dbms_lob.session);
    dbms_mle.enable_debugging(l_debugspec, l_debugsink);

    l_data := fetch_example('https://1.2.3.4:8843/ords/freepdb1/emily/employees/100');
    l_debugtext := dbms_mle.parse_debug_output(l_debugsink);

    dbms_output.put_line('-- debug output: ' ||
        json_serialize(l_debugtext returning clob pretty)
    );

    dbms_mle.disable_debugging();
EXCEPTION
    when others then
        raise;
END;
/

前述のコード・スニペットを実行すると、暗黙的に作成されたMLE実行コンテキストにデバッグ仕様がアタッチされます。DBMS_OUTPUTの呼出しにより、結果のデバッグ出力が画面に出力されます。

まとめ

多言語エンジンは、デバッガとデータベース間のネットワーク接続を一般的に禁止するクラウド・デプロイメントにおいて、オンプレミスで有効化および無効化できる便利なデバッグ・メカニズムを提供します。