Lua is a lightweight and highly efficient scripting language. In gateway development, Lua can be used to write and execute various gateway programs, such as API gateways, message gateways, and reverse proxies. Developers can use Lua to write scripts for request routing, filtering, and authentication, and to perform customized processing. Lua can be embedded into some proxies, such as NGINX and Envoy for request and response processing, log output, and other customized operations. In this topic, Lua is embedded into the Envoy proxy for request and response processing, and you'll learn how to use it to log request and response headers and bodies.
Limitations
The version of your Microservices Engine (MSE) cloud-native gateway must be 1.2.11 or later.
For security purposes, the following Lua libraries and functions are disabled for MSE cloud-native gateways by default.
debug.debug
debug.getfenv
debug.getregistry
dofile
io
loadfile
os.execute
os.getenv
os.remove
os.rename
os.tmpname
Configure routing rules
Log on to the MSE console, and select a region in the top navigation bar.
In the left-side navigation pane, choose Cloud-native Gateway > Gateways. On the Gateways page, click the ID of the gateway.
In the left-side navigation pane of the gateway details page, click Plug-in Marketplace.
On the All Plug-ins tab, click the Custom sub-tab and click the resource card of lua.
On the Plug-in Configuration tab, set the rule level and configure the rule.
NoteAll requests received by a gateway match plug-in rules in the following order of precedence: route-level plug-in rules → domain-level plug-in rules → instance-level plug-in rules.
Route-level plug-in rules
Click Add Rule. On the page that appears, turn on the switch, select a target route, and enter the Lua script in the Configure Rule editor.
Click OK.
Domain-level plug-in rules
Click Add Rule. On the page that appears, turn on the switch, select a target domain, and enter the Lua script in the Configure Rule editor.
ImportantDomain names that contain an asterisk (*) are not supported in a Lua plug-in rule.
Click OK.
Instance-level plug-in rules
An instance-level plugin rule is configured for the Lua plugin by default. To edit the rule, you must first remove the edit lock.
Turn on the switch and enter the Lua script in the Configure Rule editor.
Click Save.
API references
For more information about the Lua APIs that are provided by cloud-native gateways, see Lua.
If an error occurs during the serialization or deserialization, Lua calls the error function to return an error and terminates the current process.
Common use cases
Display complete request and response information in plug-in logs
When you configure the routing rule, use the following Lua code.
In the sample code, only the following request bodies and response bodies of the
content typeare displayed. The body size cannot exceed 1,024 bytes (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") .. "]") endView logs of the plug-in
This feature requires you to enable log shipping for gateway plug-ins. If it is not enabled, click Immediately Enable Log Shipping. After you enable log shipping, the plug-in logs are shipped to Simple Log Service and can be viewed in the console. As shown in the following figure, you can use
request-idin the access log to locate the complete request and response information in the Lua plug-in log.
Display complete request and response information in plug-in logs
When you configure the routing rule, use the following Lua code.
You can configure custom dynamic metadata for the access log parameters of a gateway. In this case, you must define the metadata in the plug-in. The following sample code defines four types of metadata information, which correspond to the request header, request body, response header, and response body.
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")) endAdjust the log format.
In the left-side navigation pane, click Parameter Settings and then Default Format (Manual Input). Add the corresponding metadata to the custom log fields. You can then view the metadata in the access logs.
