Lua は軽量で高効率なスクリプト言語です。ゲートウェイ開発では、Lua を使用して、API ゲートウェイ、メッセージゲートウェイ、リバースプロキシなど、さまざまなゲートウェイプログラムを作成し、実行できます。開発者は Lua を使用して、リクエストのルーティング、フィルタリング、認証などの機能を実装するスクリプトを作成し、カスタマイズされた処理を実行できます。 Lua は、リクエストとレスポンスの処理、ログ出力、その他のカスタマイズされた操作のために、NGINX や Envoy などの一部のプロキシに埋め込むことができます。このトピックでは、Lua はリクエストとレスポンスの処理のために Envoy プロキシに埋め込まれています。このトピックでは、Lua を使用してリクエストとレスポンスのヘッダーと本文をログに出力する方法について説明します。
制限事項
クラウドネイティブ API Gateway インスタンスのバージョンは 2.0.0 以降である必要があります。
注意事項
セキュリティ上の考慮事項から、クラウドネイティブ API Gateway では、次の Lua ライブラリと関数はデフォルトで無効になっています。
debug.debug
debug.getfenv
debug.getregistry
dofile
io
loadfile
os.execute
os.getenv
os.remove
os.rename
os.tmpname
手順
クラウドネイティブ API Gateway コンソール にログオンします。
左側のナビゲーションウィンドウで、[インスタンス] をクリックします。上部のナビゲーションバーで、リージョンを選択します。
[インスタンス] ページで、管理するゲートウェイインスタンスの名前をクリックします。
左側のナビゲーションツリーで、[プラグイン] をクリックします。次に、[プラグインのインストール] をクリックします。
検索ボックスで、キーワード lua で検索します。[lua] カードで、[インストール] をクリックします。表示されるダイアログボックスで、[インストールと構成] をクリックします。
[ルールの構成] パネルで、次のパラメーターを構成します。
[有効範囲] セクションで、Lua プラグインのアプリケーション範囲を選択します。
[操作/ルートレベルのプラグインルール] または [ドメインレベルのプラグインルール] を [有効範囲] パラメーターに選択した場合は、右側の [ルールの追加] をクリックし、表示されるパネルでパラメーターを構成します。[プラグインルール] フィールドに Lua コードを記述し、[OK] をクリックします。
[インスタンスレベルのプラグインルール] を [有効範囲] パラメーターに選択した場合は、右側の [プラグインルール] フィールドに Lua コードを記述し、[保存] をクリックします。
API リファレンス
クラウドネイティブゲートウェイによって提供される Lua API の詳細については、「Lua」をご参照ください。
シリアル化またはデシリアライズ中にエラーが発生した場合、Lua は error 関数を呼び出してエラーを返し、現在のプロセスを終了します。
一般的なユースケース
プラグインログに完全なリクエストとレスポンスの情報を表示する
クラウドネイティブ API Gateway コンソール にログオンします。
左側のナビゲーションウィンドウで、[インスタンス] をクリックします。上部のナビゲーションバーで、リージョンを選択します。
[インスタンス] ページで、管理するゲートウェイインスタンスの名前をクリックします。
左側のナビゲーションツリーで、[プラグイン] をクリックします。管理するプラグインを見つけ、[アクション] 列の [ルールの構成] をクリックします。
[ルールの構成] パネルで、次の Lua コードを構成します。
説明サンプルコードでは、
content typeの次のリクエスト本文とレスポンス本文のみが表示されます。本文のサイズは 1,024 バイト (1 KB) を超えることはできません。application/x-www-form-urlencoded
application/json
text/plain
local maxBodySize = 1024 function check_content_readable(type) if type == nil then return false end if string.find(type, "application/x-www-form-urlencoded",1,true) or string.find(type, "application/json",1,true) or string.find(type, "text/plain",1,true) then return true end return false end function envoy_on_request(request_handle) local headers = request_handle:headers() local headersStr = "" local contentType for key, value in pairs(headers) do if key == "content-type" then contentType = value end headersStr = headersStr .. key .. "=" .. value .. ", " end request_handle:streamInfo():dynamicMetadata():set("envoy.lua","request_headers",headersStr) local requestBody = "" if check_content_readable(contentType) then for chunk in request_handle:bodyChunks() do if (chunk:length() > 0) then requestBody = requestBody .. chunk:getBytes(0, chunk:length()) end if (#requestBody > maxBodySize) then requestBody = requestBody .. "<truncated>" break end end end request_handle:streamInfo():dynamicMetadata():set("envoy.lua","request_body",string.gsub(requestBody,"\n","\\n")) end function envoy_on_response(response_handle) local headers = response_handle:headers() local headersStr = "" local contentType local contentEncoding = false for key, value in pairs(headers) do if key == "content-type" then contentType = value elseif key == "content-encoding" then contentEncoding = true end headersStr = headersStr .. key .. "=" .. value .. ", " end local responseBody = "" if check_content_readable(contentType) and not contentEncoding then for chunk in response_handle:bodyChunks() do if (chunk:length() > 0) then responseBody = responseBody .. chunk:getBytes(0, chunk:length()) end if (#responseBody > maxBodySize) then responseBody = responseBody .. "<truncated>" break end end end local reqHeaders = "" local reqBody = "" local metadata = response_handle:streamInfo():dynamicMetadata():get("envoy.lua") if metadata ~= nil then local headers = response_handle:streamInfo():dynamicMetadata():get("envoy.lua")["request_headers"] if headers ~= nil then reqHeaders = headers end local body = response_handle:streamInfo():dynamicMetadata():get("envoy.lua")["request_body"] if body ~= nil then reqBody = body end end response_handle:logInfo("request Headers: [" .. reqHeaders .. "] request Body: [" .. string.gsub(reqBody,"\n","\\n") .. "] response Headers: [" .. headersStr .. "] response Body: [" .. string.gsub(responseBody,"\n","\\n") .. "]") endlua プラグインの詳細ページをクリックし、[ログ] タブをクリックして、[ログ配布を有効にする] をクリックします。
ログ配布を有効にすると、プラグインのログは Simple Log Service に配布され、コンソールで表示できます。
アクセスログに完全なリクエストとレスポンス情報を追加する
クラウドネイティブ API Gateway コンソール にログオンします。
左側のナビゲーションウィンドウで、[インスタンス] をクリックします。上部のナビゲーションバーで、リージョンを選択します。
[インスタンス] ページで、管理するゲートウェイインスタンスの名前をクリックします。
左側のナビゲーションツリーで、[プラグイン] をクリックします。管理するプラグインを見つけ、[アクション] 列の [ルールの構成] をクリックします。
[ルールの構成] パネルで、次の Lua コードを構成します。
ゲートウェイのアクセスログパラメーターのカスタム動的メタデータを構成できます。この場合、プラグインでメタデータを定義する必要があります。次のサンプルコードでは、リクエストヘッダー、リクエスト本文、レスポンスヘッダー、レスポンス本文に対応する 4 種類のメタデータ情報を定義しています。
envoy.lua:request_headers
envoy.lua:request_body
envoy.lua:response_headers
envoy.lua:response_body
local maxBodySize = 1024 function check_content_readable(type) if type == nil then return false end if string.find(type, "application/x-www-form-urlencoded",1,true) or string.find(type, "application/json",1,true) or string.find(type, "text/plain",1,true) then return true end return false end function envoy_on_request(request_handle) local headers = request_handle:headers() local headersStr = "" local contentType for key, value in pairs(headers) do if key == "content-type" then contentType = value end headersStr = headersStr .. key .. "=" .. value .. ", " end request_handle:streamInfo():dynamicMetadata():set("envoy.lua","request_headers",headersStr) local requestBody = "" if check_content_readable(contentType) then for chunk in request_handle:bodyChunks() do if (chunk:length() > 0) then requestBody = requestBody .. chunk:getBytes(0, chunk:length()) end if (#requestBody > maxBodySize) then requestBody = requestBody .. "<truncated>" break end end end request_handle:streamInfo():dynamicMetadata():set("envoy.lua","request_body",string.gsub(requestBody,"\n","\\n")) end function envoy_on_response(response_handle) local headers = response_handle:headers() local headersStr = "" local contentType local contentEncoding = false for key, value in pairs(headers) do if key == "content-type" then contentType = value elseif key == "content-encoding" then contentEncoding = true end headersStr = headersStr .. key .. "=" .. value .. ", " end response_handle:streamInfo():dynamicMetadata():set("envoy.lua","response_headers",headersStr) local responseBody = "" if check_content_readable(contentType) and not contentEncoding then for chunk in response_handle:bodyChunks() do if (chunk:length() > 0) then responseBody = responseBody .. chunk:getBytes(0, chunk:length()) end if (#responseBody > maxBodySize) then responseBody = responseBody .. "<truncated>" break end end end response_handle:streamInfo():dynamicMetadata():set("envoy.lua","response_body",string.gsub(responseBody,"\n","\\n")) end左側のナビゲーションツリーで、[パラメーター] をクリックします。[可観測性パラメーター] セクションで、ログ形式を変更します。[ログ形式の調整] ダイアログボックスで、ビジネス要件に基づいてメタデータ項目を追加します。対応するデータがログに表示されます。
