Lua は、軽量で高効率なスクリプト言語です。ゲートウェイ開発において、Lua を使用して、API ゲートウェイ、メッセージゲートウェイ、リバースプロキシなど、さまざまなゲートウェイプログラムを作成・実行できます。開発者は Lua を使用して、リクエストのルーティング、フィルタリング、認証のためのスクリプトを作成し、カスタマイズされた処理を実行できます。Lua は、NGINX や Envoy などのプロキシに埋め込んで、リクエストとレスポンスの処理、ログ出力、その他のカスタマイズされた操作を実行できます。このトピックでは、Lua を Envoy プロキシに埋め込んでリクエストとレスポンスを処理し、リクエストとレスポンスのヘッダーとボディをログに記録する方法について説明します。
制限事項
ご利用の Microservices Engine (MSE) クラウドネイティブゲートウェイのバージョンは 1.2.11 以降である必要があります。
セキュリティ上の理由から、MSE クラウドネイティブゲートウェイでは、以下の Lua ライブラリと関数がデフォルトで無効になっています。
debug.debug
debug.getfenv
debug.getregistry
dofile
io
loadfile
os.execute
os.getenv
os.remove
os.rename
os.tmpname
ルーティングルールの設定
MSE コンソールにログインし、上部のナビゲーションバーでリージョンを選択します。
左側のナビゲーションウィンドウで、Cloud-Native Gateway > ゲートウェイリスト を選択します。[ゲートウェイ] ページで、対象ゲートウェイの ID をクリックします。
[ゲートウェイ詳細] ページの左側のナビゲーションウィンドウで、Plug-in Marketplace をクリックします。
All Plug-ins タブで、Custom サブタブをクリックし、[lua] のリソースカードをクリックします。
[プラグイン設定] タブで、ルールレベルを設定し、ルールを構成します。
説明ゲートウェイが受信したすべてのリクエストは、ルートレベルのプラグインルール → ドメインレベルのプラグインルール → インスタンスレベルのプラグインルール の優先順位でプラグインルールにマッチングします。
ルートレベルのプラグインルール
[ルールを追加] をクリックします。表示されたページで、スイッチをオンにし、ターゲットルートを選択して、[ルールの設定] エディターに Lua スクリプトを入力します。
[OK] をクリックします。
ドメインレベルのプラグインルール
[ルールを追加] をクリックします。表示されたページで、スイッチをオンにし、ターゲットドメインを選択して、[ルールの設定] エディターに Lua スクリプトを入力します。
重要アスタリスク (*) を含むドメイン名は、Lua プラグインルールではサポートされていません。
[OK] をクリックします。
インスタンスレベルのプラグインルール
インスタンスレベルのプラグインルールは、デフォルトで Lua プラグイン用に構成されています。ルールを編集するには、まず編集ロックを解除する必要があります。
スイッチをオンにし、[ルールの設定] エディターに Lua スクリプトを入力します。
[保存] をクリックします。
API リファレンス
ゲートウェイの Lua API の詳細については、「Lua」をご参照ください。
シリアル化またはデシリアライズ中にエラーが発生した場合、Lua はエラー関数を呼び出してエラーを返し、現在のプロセスを終了します。
一般的なユースケース
プラグインログへの完全なリクエスト・レスポンス情報の表示
ルーティングルールを設定する際に、次の Lua コードを使用します。
このコード設定では、次の
content-typeに一致し、サイズが 1024 バイト (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") .. "]") endプラグインのログの表示
この機能を使用するには、ゲートウェイプラグインのログ配布を有効にする必要があります。有効になっていない場合は、[今すぐログ配布を有効にする] をクリックします。ログ配布を有効にすると、プラグインのログは Simple Log Service に配布され、コンソールで表示できます。次の図に示すように、アクセスログの
request-idを使用して、Lua プラグインログ内の完全なリクエストとレスポンスの情報を特定できます。
アクセスログへの完全なリクエスト・レスポンス情報の追加
ルーティングルールを設定する際に、次の 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ログフォーマットの調整
左側のナビゲーションウィンドウで、[パラメーター設定] をクリックし、次に [デフォルトフォーマット (手動入力)] をクリックします。対応するメタデータをカスタムログフィールドに追加します。これで、アクセスログでメタデータを表示できるようになります。
