Copilot commented on code in PR #13336:
URL: https://github.com/apache/apisix/pull/13336#discussion_r3199158691


##########
docs/en/latest/plugins/serverless.md:
##########
@@ -87,37 +83,958 @@ admin_key=$(yq '.deployment.admin.admin_key[0].key' 
conf/config.yaml | sed 's/"/
 
 :::
 
-The following example enables `serverless-pre-function` and 
`serverless-post-function` Plugins on a Route:
+The examples below demonstrate how you can configure the 
`serverless-pre-function` and `serverless-post-function` plugins for different 
scenarios.
+
+### Log Information before and after a Phase
+
+The example below demonstrates how you can configure the serverless plugins to 
execute custom logics to log information to error logs before and after the 
`rewrite` [phase](../terminology/plugin.md#plugins-execution-lifecycle).
+
+Create a Route as such:
+
+<Tabs
+groupId="api"
+defaultValue="admin-api"
+values={[
+{label: 'Admin API', value: 'admin-api'},
+{label: 'ADC', value: 'adc'},
+{label: 'Ingress Controller', value: 'aic'}
+]}>
+
+<TabItem value="admin-api">
 
 ```shell
 curl "http://127.0.0.1:9180/apisix/admin/routes"; -X PUT \
   -H "X-API-KEY: ${admin_key}" \
   -d '{
-    "id": "serverless-route",
-    "uri": "/index.html",
+    "id": "serverless-pre-route",
+    "uri": "/anything",
     "plugins": {
+      # highlight-start
       "serverless-pre-function": {
         "phase": "rewrite",
-        "functions": ["return function() ngx.log(ngx.ERR, \"serverless pre 
function\"); end"]
+        "functions" : [
+          "return function()
+            ngx.log(ngx.ERR, \"serverless pre function\");
+          end"
+        ]
       },
       "serverless-post-function": {
         "phase": "rewrite",
-        "functions": ["return function(conf, ctx) ngx.log(ngx.ERR, \"match uri 
\", ctx.curr_req_matched and ctx.curr_req_matched._path); end"]
+        "functions" : [
+          "return function(conf, ctx)
+            ngx.log(ngx.ERR, \"match uri \", ctx.curr_req_matched and 
ctx.curr_req_matched._path);
+          end"
+        ]
       }
+      # highlight-end
     },
     "upstream": {
       "type": "roundrobin",
       "nodes": {
-        "127.0.0.1:1980": 1
+        "httpbin.org:80": 1
+      }
+    }
+  }'
+```
+
+</TabItem>
+
+<TabItem value="adc">
+
+```yaml title="adc.yaml"
+services:
+  - name: httpbin
+    routes:
+      - name: serverless-pre-route
+        uris:
+          - /anything
+        plugins:
+          # highlight-start
+          serverless-pre-function:
+            phase: rewrite
+            functions:
+              - |
+                return function()
+                  ngx.log(ngx.ERR, "serverless pre function")
+                end
+          serverless-post-function:
+            phase: rewrite
+            functions:
+              - |
+                return function(conf, ctx)
+                  ngx.log(ngx.ERR, "match uri ", ctx.curr_req_matched and 
ctx.curr_req_matched._path)
+                end
+          # highlight-end
+    upstream:
+      type: roundrobin
+      nodes:
+        - host: httpbin.org
+          port: 80
+          weight: 1
+```
+
+Synchronize the configuration to the gateway:
+
+```shell
+adc sync -f adc.yaml
+```
+
+</TabItem>
+
+<TabItem value="aic">
+
+<Tabs
+groupId="k8s-api"
+defaultValue="gateway-api"
+values={[
+{label: 'Gateway API', value: 'gateway-api'},
+{label: 'APISIX CRD', value: 'apisix-crd'}
+]}>
+
+<TabItem value="gateway-api">
+
+```yaml title="serverless-functions-ic.yaml"
+apiVersion: v1
+kind: Service
+metadata:
+  namespace: aic
+  name: httpbin-external-domain
+spec:
+  type: ExternalName
+  externalName: httpbin.org
+---
+apiVersion: apisix.apache.org/v1alpha1
+kind: PluginConfig
+metadata:
+  namespace: aic
+  name: serverless-functions-plugin-config
+spec:
+  plugins:
+    # highlight-start
+    - name: serverless-pre-function
+      config:
+        phase: rewrite
+        functions:
+          - |
+            return function()
+              ngx.log(ngx.ERR, "serverless pre function")
+            end
+    - name: serverless-post-function
+      config:
+        phase: rewrite
+        functions:
+          - |
+            return function(conf, ctx)
+              ngx.log(ngx.ERR, "match uri ", ctx.curr_req_matched and 
ctx.curr_req_matched._path)
+            end
+    # highlight-end
+---
+apiVersion: gateway.networking.k8s.io/v1
+kind: HTTPRoute
+metadata:
+  namespace: aic
+  name: serverless-pre-route
+spec:
+  parentRefs:
+    - name: apisix
+  rules:
+    - matches:
+        - path:
+            type: Exact
+            value: /anything
+      filters:
+        - type: ExtensionRef
+          extensionRef:
+            group: apisix.apache.org
+            kind: PluginConfig
+            name: serverless-functions-plugin-config
+      backendRefs:
+        - name: httpbin-external-domain
+          port: 80
+```
+
+</TabItem>
+
+<TabItem value="apisix-crd">
+
+```yaml title="serverless-functions-ic.yaml"
+apiVersion: apisix.apache.org/v2
+kind: ApisixUpstream
+metadata:
+  namespace: aic
+  name: httpbin-external-domain
+spec:
+  ingressClassName: apisix
+  externalNodes:
+  - type: Domain
+    name: httpbin.org
+---
+apiVersion: apisix.apache.org/v2
+kind: ApisixRoute
+metadata:
+  namespace: aic
+  name: serverless-pre-route
+spec:
+  ingressClassName: apisix
+  http:
+    - name: serverless-pre-route
+      match:
+        paths:
+          - /anything
+      upstreams:
+        - name: httpbin-external-domain
+      plugins:
+        # highlight-start
+        - name: serverless-pre-function
+          config:
+            phase: rewrite
+            functions:
+              - |
+                return function()
+                  ngx.log(ngx.ERR, "serverless pre function")
+                end
+        - name: serverless-post-function
+          config:
+            phase: rewrite
+            functions:
+              - |
+                return function(conf, ctx)
+                  ngx.log(ngx.ERR, "match uri ", ctx.curr_req_matched and 
ctx.curr_req_matched._path)
+                end
+        # highlight-end
+```
+
+</TabItem>
+
+</Tabs>
+
+Apply the configuration:
+
+```shell
+kubectl apply -f serverless-functions-ic.yaml
+```
+
+</TabItem>
+
+</Tabs>
+
+- Hook the serverless pre-function logic to the `rewrite` 
[phase](../terminology/plugin.md#plugins-execution-lifecycle).
+
+- Define a Lua function that logs a message of `serverless pre function` in 
the error log.
+
+- Hook the serverless post-function logic to the `rewrite` 
[phase](../terminology/plugin.md#plugins-execution-lifecycle).
+
+- Define a Lua function that logs the matched URI in the error log. `conf` and 
`ctx` can be passed as the first two arguments like other plugins, where `conf` 
is the plugin configurations and `ctx` is the request context.
+
+Send the request to the Route:
+
+```shell
+curl -i "http://127.0.0.1:9080/anything";
+```
+
+You should receive an `HTTP/1.1 200 OK` response and see the following entries 
in the error log:
+
+```text
+2024/05/09 15:07:09 [error] 51#51: *3963 [lua] [string "return function() 
ngx.log(ngx.ERR, "serverles..."]:1: func(): serverless pre function, client: 
172.21.0.1, server: _, request: "GET /anything HTTP/1.1", host: "127.0.0.1:9080"
+2024/05/09 15:16:58 [error] 50#50: *9343 [lua] [string "return function(conf, 
ctx) ngx.log(ngx.ERR, "..."]:1: func(): match uri /anything, client: 
172.21.0.1, server: _, request: "GET /anything HTTP/1.1", host: "127.0.0.1:9080"
+```
+
+The first entry is added by the pre-function and the second entry is added by 
the post-function.
+
+### Register Custom Variables
+
+The example below demonstrates how you can register custom built-in variables 
using the serverless plugins and use the newly created variable in logs.
+
+:::info
+
+This example cannot be completed with the Ingress Controller because it does 
not support configuring Route labels.
+
+:::
+
+Start an example rsyslog server:
+
+```shell
+docker run -d -p 514:514 --name example-rsyslog-server 
rsyslog/syslog_appliance_alpine
+```
+
+Create a [Service](../terminology/service.md) with a serverless function to 
register a custom variable `a6_route_labels`, enable a logging plugin to later 
log the custom variable, and configure an upstream:
+
+<Tabs
+groupId="api"
+defaultValue="admin-api"
+values={[
+{label: 'Admin API', value: 'admin-api'},
+{label: 'ADC', value: 'adc'}
+]}>
+
+<TabItem value="admin-api">
+
+```shell
+curl "http://127.0.0.1:9180/apisix/admin/services"; -X PUT \
+  -H "X-API-KEY: ${admin_key}" \
+  -d '{
+    "id":"srv_custom_var",
+    "plugins": {
+      # highlight-start
+      "serverless-pre-function": {
+        "phase": "rewrite",
+        "functions": [
+          "return function()
+            local core = require \"apisix.core\"
+            core.ctx.register_var(\"a6_route_labels\", function(ctx)
+              local route = ctx.matched_route and ctx.matched_route.value
+              if route and route.labels then
+                return route.labels
+              end
+              return nil
+            end);
+          end"

Review Comment:
   This Admin API example also uses a multi-line JSON string for the Lua 
function body. JSON does not allow unescaped newline characters inside string 
literals, so the example as written will produce invalid JSON and fail when 
sent to the Admin API. Please rewrite the function string to be single-line or 
use escaped newlines.
   



##########
docs/en/latest/plugins/serverless.md:
##########
@@ -87,37 +83,958 @@ admin_key=$(yq '.deployment.admin.admin_key[0].key' 
conf/config.yaml | sed 's/"/
 
 :::
 
-The following example enables `serverless-pre-function` and 
`serverless-post-function` Plugins on a Route:
+The examples below demonstrate how you can configure the 
`serverless-pre-function` and `serverless-post-function` plugins for different 
scenarios.
+
+### Log Information before and after a Phase
+
+The example below demonstrates how you can configure the serverless plugins to 
execute custom logics to log information to error logs before and after the 
`rewrite` [phase](../terminology/plugin.md#plugins-execution-lifecycle).
+
+Create a Route as such:
+
+<Tabs
+groupId="api"
+defaultValue="admin-api"
+values={[
+{label: 'Admin API', value: 'admin-api'},
+{label: 'ADC', value: 'adc'},
+{label: 'Ingress Controller', value: 'aic'}
+]}>
+
+<TabItem value="admin-api">
 
 ```shell
 curl "http://127.0.0.1:9180/apisix/admin/routes"; -X PUT \
   -H "X-API-KEY: ${admin_key}" \
   -d '{
-    "id": "serverless-route",
-    "uri": "/index.html",
+    "id": "serverless-pre-route",
+    "uri": "/anything",
     "plugins": {
+      # highlight-start
       "serverless-pre-function": {
         "phase": "rewrite",
-        "functions": ["return function() ngx.log(ngx.ERR, \"serverless pre 
function\"); end"]
+        "functions" : [
+          "return function()
+            ngx.log(ngx.ERR, \"serverless pre function\");
+          end"
+        ]

Review Comment:
   The Admin API example embeds multi-line Lua code inside a JSON string (the 
string literal spans multiple lines). Raw newlines are not valid inside JSON 
strings, so this payload will fail to parse (e.g., by lua-cjson). Please keep 
the function string on one line or escape newlines (\n) so the request body is 
valid JSON.



##########
docs/zh/latest/plugins/serverless.md:
##########
@@ -87,37 +83,252 @@ admin_key=$(yq '.deployment.admin.admin_key[0].key' 
conf/config.yaml | sed 's/"/
 
 :::
 
-以下示例在路由上启用 `serverless-pre-function` 和 `serverless-post-function` 插件:
+以下示例演示如何在不同场景中配置 `serverless-pre-function` 和 `serverless-post-function` 插件。
+
+### 在阶段前后记录信息
+
+以下示例演示如何配置 serverless 插件,在 `rewrite` 
[阶段](../terminology/plugin.md#plugins-execution-lifecycle)之前和之后执行自定义逻辑,将信息记录到错误日志中。
+
+创建如下路由:
+
+<Tabs
+groupId="api"
+defaultValue="admin-api"
+values={[
+{label: 'Admin API', value: 'admin-api'},
+{label: 'ADC', value: 'adc'},
+{label: 'Ingress Controller', value: 'aic'}
+]}>
+
+<TabItem value="admin-api">
 
 ```shell
 curl "http://127.0.0.1:9180/apisix/admin/routes"; -X PUT \
   -H "X-API-KEY: ${admin_key}" \
   -d '{
-    "id": "serverless-route",
-    "uri": "/index.html",
+    "id": "serverless-pre-route",
+    "uri": "/anything",
     "plugins": {
       "serverless-pre-function": {
         "phase": "rewrite",
-        "functions": ["return function() ngx.log(ngx.ERR, \"serverless pre 
function\"); end"]
+        "functions" : [
+          "return function()
+            ngx.log(ngx.ERR, \"serverless pre function\");
+          end"
+        ]

Review Comment:
   该 Admin API 示例在 JSON 字符串中直接换行写 Lua 函数体(字符串跨多行)。JSON 
字符串不允许包含未转义的换行符,因此该请求体不是合法 JSON,发送到 Admin API 会解析失败。建议将函数写成单行字符串,或使用 \n 
等转义字符表示换行。



##########
docs/en/latest/plugins/real-ip.md:
##########
@@ -33,9 +33,9 @@ description: The real-ip plugin allows Apache APISIX to set 
the client's real IP
 
 ## Description
 
-The `real-ip` Plugin allows APISIX to set the client's real IP by the IP 
address passed in the HTTP header or HTTP query string. This is particularly 
useful when APISIX is behind a reverse proxy since the proxy could act as the 
request-originating client otherwise.
+The `real-ip` Plugin allows APISIX to set the client's real IP by IP address 
passed in the HTTP header or HTTP query string. This is particularly useful 
when APISIX is behind a reverse proxy, since the proxy could act as the request 
originating client otherwise.
 
-The Plugin is functionally similar to NGINX's 
[ngx_http_realip_module](https://nginx.org/en/docs/http/ngx_http_realip_module.html)
 but offers more flexibility.
+The Plugin is functionally similar to NGINX's 
[ngx_http_realip_module](https://nginx.org/en/docs/http/ngx_http_realip_module.html)
 but offers more flexibilities.

Review Comment:
   There are a few grammar issues in the updated description: “set ... by IP 
address passed ...” is missing “the”, and “offers more flexibilities” should be 
“offers more flexibility”. Please adjust these sentences for correct English.



##########
docs/en/latest/plugins/serverless.md:
##########
@@ -87,37 +83,958 @@ admin_key=$(yq '.deployment.admin.admin_key[0].key' 
conf/config.yaml | sed 's/"/
 
 :::
 
-The following example enables `serverless-pre-function` and 
`serverless-post-function` Plugins on a Route:
+The examples below demonstrate how you can configure the 
`serverless-pre-function` and `serverless-post-function` plugins for different 
scenarios.
+
+### Log Information before and after a Phase
+
+The example below demonstrates how you can configure the serverless plugins to 
execute custom logics to log information to error logs before and after the 
`rewrite` [phase](../terminology/plugin.md#plugins-execution-lifecycle).
+
+Create a Route as such:
+
+<Tabs
+groupId="api"
+defaultValue="admin-api"
+values={[
+{label: 'Admin API', value: 'admin-api'},
+{label: 'ADC', value: 'adc'},
+{label: 'Ingress Controller', value: 'aic'}
+]}>
+
+<TabItem value="admin-api">
 
 ```shell
 curl "http://127.0.0.1:9180/apisix/admin/routes"; -X PUT \
   -H "X-API-KEY: ${admin_key}" \
   -d '{
-    "id": "serverless-route",
-    "uri": "/index.html",
+    "id": "serverless-pre-route",
+    "uri": "/anything",
     "plugins": {
+      # highlight-start
       "serverless-pre-function": {
         "phase": "rewrite",
-        "functions": ["return function() ngx.log(ngx.ERR, \"serverless pre 
function\"); end"]
+        "functions" : [
+          "return function()
+            ngx.log(ngx.ERR, \"serverless pre function\");
+          end"
+        ]
       },
       "serverless-post-function": {
         "phase": "rewrite",
-        "functions": ["return function(conf, ctx) ngx.log(ngx.ERR, \"match uri 
\", ctx.curr_req_matched and ctx.curr_req_matched._path); end"]
+        "functions" : [
+          "return function(conf, ctx)
+            ngx.log(ngx.ERR, \"match uri \", ctx.curr_req_matched and 
ctx.curr_req_matched._path);
+          end"
+        ]
       }
+      # highlight-end
     },
     "upstream": {
       "type": "roundrobin",
       "nodes": {
-        "127.0.0.1:1980": 1
+        "httpbin.org:80": 1
+      }
+    }
+  }'
+```
+
+</TabItem>
+
+<TabItem value="adc">
+
+```yaml title="adc.yaml"
+services:
+  - name: httpbin
+    routes:
+      - name: serverless-pre-route
+        uris:
+          - /anything
+        plugins:
+          # highlight-start
+          serverless-pre-function:
+            phase: rewrite
+            functions:
+              - |
+                return function()
+                  ngx.log(ngx.ERR, "serverless pre function")
+                end
+          serverless-post-function:
+            phase: rewrite
+            functions:
+              - |
+                return function(conf, ctx)
+                  ngx.log(ngx.ERR, "match uri ", ctx.curr_req_matched and 
ctx.curr_req_matched._path)
+                end
+          # highlight-end
+    upstream:
+      type: roundrobin
+      nodes:
+        - host: httpbin.org
+          port: 80
+          weight: 1
+```
+
+Synchronize the configuration to the gateway:
+
+```shell
+adc sync -f adc.yaml
+```
+
+</TabItem>
+
+<TabItem value="aic">
+
+<Tabs
+groupId="k8s-api"
+defaultValue="gateway-api"
+values={[
+{label: 'Gateway API', value: 'gateway-api'},
+{label: 'APISIX CRD', value: 'apisix-crd'}
+]}>
+
+<TabItem value="gateway-api">
+
+```yaml title="serverless-functions-ic.yaml"
+apiVersion: v1
+kind: Service
+metadata:
+  namespace: aic
+  name: httpbin-external-domain
+spec:
+  type: ExternalName
+  externalName: httpbin.org
+---
+apiVersion: apisix.apache.org/v1alpha1
+kind: PluginConfig
+metadata:
+  namespace: aic
+  name: serverless-functions-plugin-config
+spec:
+  plugins:
+    # highlight-start
+    - name: serverless-pre-function
+      config:
+        phase: rewrite
+        functions:
+          - |
+            return function()
+              ngx.log(ngx.ERR, "serverless pre function")
+            end
+    - name: serverless-post-function
+      config:
+        phase: rewrite
+        functions:
+          - |
+            return function(conf, ctx)
+              ngx.log(ngx.ERR, "match uri ", ctx.curr_req_matched and 
ctx.curr_req_matched._path)
+            end
+    # highlight-end
+---
+apiVersion: gateway.networking.k8s.io/v1
+kind: HTTPRoute
+metadata:
+  namespace: aic
+  name: serverless-pre-route
+spec:
+  parentRefs:
+    - name: apisix
+  rules:
+    - matches:
+        - path:
+            type: Exact
+            value: /anything
+      filters:
+        - type: ExtensionRef
+          extensionRef:
+            group: apisix.apache.org
+            kind: PluginConfig
+            name: serverless-functions-plugin-config
+      backendRefs:
+        - name: httpbin-external-domain
+          port: 80
+```
+
+</TabItem>
+
+<TabItem value="apisix-crd">
+
+```yaml title="serverless-functions-ic.yaml"
+apiVersion: apisix.apache.org/v2
+kind: ApisixUpstream
+metadata:
+  namespace: aic
+  name: httpbin-external-domain
+spec:
+  ingressClassName: apisix
+  externalNodes:
+  - type: Domain
+    name: httpbin.org
+---
+apiVersion: apisix.apache.org/v2
+kind: ApisixRoute
+metadata:
+  namespace: aic
+  name: serverless-pre-route
+spec:
+  ingressClassName: apisix
+  http:
+    - name: serverless-pre-route
+      match:
+        paths:
+          - /anything
+      upstreams:
+        - name: httpbin-external-domain
+      plugins:
+        # highlight-start
+        - name: serverless-pre-function
+          config:
+            phase: rewrite
+            functions:
+              - |
+                return function()
+                  ngx.log(ngx.ERR, "serverless pre function")
+                end
+        - name: serverless-post-function
+          config:
+            phase: rewrite
+            functions:
+              - |
+                return function(conf, ctx)
+                  ngx.log(ngx.ERR, "match uri ", ctx.curr_req_matched and 
ctx.curr_req_matched._path)
+                end
+        # highlight-end
+```
+
+</TabItem>
+
+</Tabs>
+
+Apply the configuration:
+
+```shell
+kubectl apply -f serverless-functions-ic.yaml
+```
+
+</TabItem>
+
+</Tabs>
+
+- Hook the serverless pre-function logic to the `rewrite` 
[phase](../terminology/plugin.md#plugins-execution-lifecycle).
+
+- Define a Lua function that logs a message of `serverless pre function` in 
the error log.
+
+- Hook the serverless post-function logic to the `rewrite` 
[phase](../terminology/plugin.md#plugins-execution-lifecycle).
+
+- Define a Lua function that logs the matched URI in the error log. `conf` and 
`ctx` can be passed as the first two arguments like other plugins, where `conf` 
is the plugin configurations and `ctx` is the request context.
+
+Send the request to the Route:
+
+```shell
+curl -i "http://127.0.0.1:9080/anything";
+```
+
+You should receive an `HTTP/1.1 200 OK` response and see the following entries 
in the error log:
+
+```text
+2024/05/09 15:07:09 [error] 51#51: *3963 [lua] [string "return function() 
ngx.log(ngx.ERR, "serverles..."]:1: func(): serverless pre function, client: 
172.21.0.1, server: _, request: "GET /anything HTTP/1.1", host: "127.0.0.1:9080"
+2024/05/09 15:16:58 [error] 50#50: *9343 [lua] [string "return function(conf, 
ctx) ngx.log(ngx.ERR, "..."]:1: func(): match uri /anything, client: 
172.21.0.1, server: _, request: "GET /anything HTTP/1.1", host: "127.0.0.1:9080"
+```
+
+The first entry is added by the pre-function and the second entry is added by 
the post-function.
+
+### Register Custom Variables
+
+The example below demonstrates how you can register custom built-in variables 
using the serverless plugins and use the newly created variable in logs.
+
+:::info
+
+This example cannot be completed with the Ingress Controller because it does 
not support configuring Route labels.
+
+:::
+
+Start an example rsyslog server:
+
+```shell
+docker run -d -p 514:514 --name example-rsyslog-server 
rsyslog/syslog_appliance_alpine
+```
+
+Create a [Service](../terminology/service.md) with a serverless function to 
register a custom variable `a6_route_labels`, enable a logging plugin to later 
log the custom variable, and configure an upstream:
+
+<Tabs
+groupId="api"
+defaultValue="admin-api"
+values={[
+{label: 'Admin API', value: 'admin-api'},
+{label: 'ADC', value: 'adc'}
+]}>
+
+<TabItem value="admin-api">
+
+```shell
+curl "http://127.0.0.1:9180/apisix/admin/services"; -X PUT \
+  -H "X-API-KEY: ${admin_key}" \
+  -d '{
+    "id":"srv_custom_var",
+    "plugins": {
+      # highlight-start
+      "serverless-pre-function": {
+        "phase": "rewrite",
+        "functions": [
+          "return function()
+            local core = require \"apisix.core\"
+            core.ctx.register_var(\"a6_route_labels\", function(ctx)
+              local route = ctx.matched_route and ctx.matched_route.value
+              if route and route.labels then
+                return route.labels
+              end
+              return nil
+            end);
+          end"
+        ]
+      },
+      "syslog": {
+        "host" : "172.0.0.1",
+        "port" : 514,
+        "flush_limit" : 1
+      }
+      # highlight-end
+    },
+    "upstream": {
+      "nodes": {
+        "httpbin.org:80": 1
       }
     }
   }'
 ```
 
+</TabItem>
+
+<TabItem value="adc">
+
+```yaml title="adc.yaml"
+services:
+  - name: srv-custom-var
+    plugins:
+      # highlight-start
+      serverless-pre-function:
+        phase: rewrite
+        functions:
+          - |
+            return function()
+              local core = require("apisix.core")
+              core.ctx.register_var("a6_route_labels", function(ctx)
+                local route = ctx.matched_route and ctx.matched_route.value
+                if route and route.labels then
+                  return route.labels
+                end
+                return nil
+              end)
+            end
+      syslog:
+        host: 172.0.0.1
+        port: 514
+        flush_limit: 1
+      # highlight-end
+    upstream:
+      nodes:
+        - host: httpbin.org
+          port: 80
+          weight: 1
+```
+
+Synchronize the configuration to the gateway:
+
+```shell
+adc sync -f adc.yaml
+```
+
+</TabItem>
+
+</Tabs>
+
+- `functions`: register a custom variable `a6_route_labels` and fetch the 
variable value from the matched Route's `labels` property.
+
+- `host` and `port`: replace with the address of your syslog server.
+
+- `flush_limit`: set to 1 to push log to the syslog server immediately.
+
+Next, update the log format for all `syslog` instances with the new variable 
by configuring the [Plugin metadata](../terminology/plugin.md#plugin-metadata):
+
+<Tabs
+groupId="api"
+defaultValue="admin-api"
+values={[
+{label: 'Admin API', value: 'admin-api'},
+{label: 'ADC', value: 'adc'}
+]}>
+
+<TabItem value="admin-api">
+
+```shell
+curl "http://127.0.0.1:9180/apisix/admin/plugin_metadata/syslog"; -X PUT \
+  -H "X-API-KEY: ${admin_key}" \
+  -d '{
+    "log_format": {
+      # highlight-start
+      "host": "$host",
+      "client_ip": "$remote_addr",
+      "labels": "$a6_route_labels"
+      # highlight-end
+    }
+  }'
+```
+
+</TabItem>
+
+<TabItem value="adc">
+
+```yaml title="adc.yaml"
+plugin_metadata:
+  syslog:
+    log_format:
+      # highlight-start
+      host: "$host"
+      client_ip: "$remote_addr"
+      labels: "$a6_route_labels"
+      # highlight-end
+```
+
+Synchronize the configuration to the gateway:
+
+```shell
+adc sync -f adc.yaml
+```
+
+</TabItem>
+
+</Tabs>
+
+- `$host` and `$remote_addr`: NGINX variables.
+
+- `$a6_route_labels`: custom variable.
+
+Finally, create a Route:
+
+<Tabs
+groupId="api"
+defaultValue="admin-api"
+values={[
+{label: 'Admin API', value: 'admin-api'},
+{label: 'ADC', value: 'adc'}
+]}>
+
+<TabItem value="admin-api">
+
+```shell
+curl "http://127.0.0.1:9180/apisix/admin/routes"; -X PUT \
+  -H "X-API-KEY: ${admin_key}" \
+  -d '{
+    "id":"route_custom_var",
+    "uri":"/get",
+    # highlight-start
+    "service_id": "srv_custom_var",
+    "labels": {
+      "key": "test_a6_route_labels"
+    }
+    # highlight-end
+}'
+```
+
+</TabItem>
+
+<TabItem value="adc">
+
+```yaml title="adc.yaml"
+# Other Configs
+services:
+  - name: srv-custom-var
+    routes:
+      - name: route-custom-var
+        uris:
+          - /get
+        # highlight-start
+        labels:
+          key: test_a6_route_labels
+        # highlight-end
+```
+
+Synchronize the configuration to the gateway:
+
+```shell
+adc sync -f adc.yaml
+```
+
+</TabItem>
+
+</Tabs>
+
+- In the Admin API example, set `service_id` to associate the Route with the 
existing Service. In ADC, the Route is nested under the Service definition.
+
+- Add Route `labels` so the custom variable can log them.
+
+To verify the variable registration, send a request to the Route:
+
+```shell
+curl "http://127.0.0.1:9080/get";
+```
+
+You should see a log entry in your syslog server similar to the following:
+
+```json
+{
+  "host":"127.0.0.1",
+  "route_id":"route_custom_var",
+  "client_ip":"172.19.0.1",
+  # highlight-start
+  "labels":{
+    "key":"test_a6_route_labels"
+  },
+  # highlight-end
+  "service_id":"srv_custom_var"
+}
+```
+
+This verifies the custom variable was registered and it logs the `labels` 
information in a Route successfully.
+
+### Modify a Specific Field in Response Body
+
+The example below demonstrates how you can use the serverless plugins to 
remove a specific field from a JSON response body.
+
+Before proceeding with the removal, first configure a Route as follows to see 
the unmodified response:
+
+<Tabs
+groupId="api"
+defaultValue="admin-api"
+values={[
+{label: 'Admin API', value: 'admin-api'},
+{label: 'ADC', value: 'adc'},
+{label: 'Ingress Controller', value: 'aic'}
+]}>
+
+<TabItem value="admin-api">
+
+```shell
+curl "http://127.0.0.1:9180/apisix/admin/routes"; -X PUT \
+  -H "X-API-KEY: ${admin_key}" \
+  -d '{
+    "id":"serverless-remove-body-info",
+    "uri": "/get",
+    "upstream": {
+      "type": "roundrobin",
+      "nodes": {
+        "httpbin.org:80": 1
+      }
+    }
+  }'
+```
+
+</TabItem>
+
+<TabItem value="adc">
+
+```yaml title="adc.yaml"
+services:
+  - name: httpbin
+    routes:
+      - name: serverless-remove-body-info
+        uris:
+          - /get
+    upstream:
+      type: roundrobin
+      nodes:
+        - host: httpbin.org
+          port: 80
+          weight: 1
+```
+
+Synchronize the configuration to the gateway:
+
+```shell
+adc sync -f adc.yaml
+```
+
+</TabItem>
+
+<TabItem value="aic">
+
+<Tabs
+groupId="k8s-api"
+defaultValue="gateway-api"
+values={[
+{label: 'Gateway API', value: 'gateway-api'},
+{label: 'APISIX CRD', value: 'apisix-crd'}
+]}>
+
+<TabItem value="gateway-api">
+
+```yaml title="serverless-remove-body-ic.yaml"
+apiVersion: v1
+kind: Service
+metadata:
+  namespace: aic
+  name: httpbin-external-domain
+spec:
+  type: ExternalName
+  externalName: httpbin.org
+---
+apiVersion: gateway.networking.k8s.io/v1
+kind: HTTPRoute
+metadata:
+  namespace: aic
+  name: serverless-remove-body-info
+spec:
+  parentRefs:
+    - name: apisix
+  rules:
+    - matches:
+        - path:
+            type: Exact
+            value: /get
+      backendRefs:
+        - name: httpbin-external-domain
+          port: 80
+```
+
+</TabItem>
+
+<TabItem value="apisix-crd">
+
+```yaml title="serverless-remove-body-ic.yaml"
+apiVersion: apisix.apache.org/v2
+kind: ApisixUpstream
+metadata:
+  namespace: aic
+  name: httpbin-external-domain
+spec:
+  ingressClassName: apisix
+  externalNodes:
+  - type: Domain
+    name: httpbin.org
+---
+apiVersion: apisix.apache.org/v2
+kind: ApisixRoute
+metadata:
+  namespace: aic
+  name: serverless-remove-body-info
+spec:
+  ingressClassName: apisix
+  http:
+    - name: serverless-remove-body-info
+      match:
+        paths:
+          - /get
+      upstreams:
+        - name: httpbin-external-domain
+```
+
+</TabItem>
+
+</Tabs>
+
+Apply the configuration:
+
+```shell
+kubectl apply -f serverless-remove-body-ic.yaml
+```
+
+</TabItem>
+
+</Tabs>
+
 Send a request to the Route:
 
 ```shell
-curl -i "http://127.0.0.1:9080/index.html";
+curl "http://127.0.0.1:9080/get";
+```
+
+You should see a response similar to the following with your host and proxy's 
IP information:
+
+```json
+{
+  "args": {},
+  "headers": {
+    "Accept": "*/*",
+    "Host": "127.0.0.1",
+    "User-Agent": "curl/8.4.0",
+    "X-Amzn-Trace-Id": "Root=1-663db30f-51448a1b635f2f4338a4fcfc",
+    "X-Forwarded-Host": "127.0.0.1"
+  },
+  # highlight-next-line
+  "origin": "172.19.0.1, 43.252.208.84",
+  "url": "http://127.0.0.1/get";
+}
+```
+
+To remove the `origin` field from the response, update the Route with 
serverless plugins:
+
+<Tabs
+groupId="api"
+defaultValue="admin-api"
+values={[
+{label: 'Admin API', value: 'admin-api'},
+{label: 'ADC', value: 'adc'},
+{label: 'Ingress Controller', value: 'aic'}
+]}>
+
+<TabItem value="admin-api">
+
+```shell
+curl "http://127.0.0.1:9180/apisix/admin/routes/serverless-remove-body-info"; 
-X PATCH \
+  -H "X-API-KEY: ${admin_key}" \
+  -d '{
+    "plugins": {
+      # highlight-start
+      "serverless-pre-function": {
+        "phase": "header_filter",
+        "functions" : [
+          "return function(conf, ctx)
+            local core = require(\"apisix.core\")
+            core.response.clear_header_as_body_modified()
+          end"
+        ]
+      },
+      "serverless-post-function": {
+        "phase": "body_filter",
+        "functions" : [
+          "return function(conf, ctx)
+            local cjson = require(\"cjson\")
+            local core = require(\"apisix.core\")
+            local body = core.response.hold_body_chunk(ctx)
+            if not body then
+              return
+            end
+            body = cjson.decode(body)
+            body.origin = nil
+            body = cjson.encode(body)
+            ngx.arg[1] = body
+          end"

Review Comment:
   The PATCH example includes multi-line Lua code inside JSON string values 
under "functions". Since JSON strings cannot contain raw newlines, this request 
body is invalid JSON and will not be accepted by the Admin API. Please encode 
the function as a single-line string or escape newlines.
   



##########
docs/zh/latest/plugins/authz-keycloak.md:
##########
@@ -52,26 +46,26 @@ description: authz-keycloak 插件与 Keycloak 集成,用于用户认证和授
 | token_endpoint                               | string        | 否   |         
                                      | 
https://host.domain/realms/foo/protocol/openid-connect/token       | 支持 
`urn:ietf:params:oauth:grant-type:uma-ticket` 授权类型的符合 OAuth2 
规范的令牌端点。若设置,将覆盖从发现文档中获取的值。                                                      
                                                                    |
 | resource_registration_endpoint               | string        | 否   |         
                                      | 
https://host.domain/realms/foo/authz/protection/resource_set       | 符合 UMA 
规范的资源注册端点。若设置,将覆盖从发现文档中获取的值。                                                    
                                                                                
                                                 |
 | client_id                                    | string        | 是   |         
                                      |                                         
                               | 客户端尝试访问的资源服务器的标识符。                             
                                                                                
                                                                                
                     |
-| client_secret                                | string        | 否   |         
                                      |                                         
                               | 客户端密钥(如需要)。可以使用 APISIX secret 存储和引用该值,APISIX 
目前支持[环境变量和 HashiCorp Vault](../terminology/secret.md) 两种方式。                     
                                                                                
     |
+| client_secret                                | string        | 否   |         
                                      |                                         
                               | 客户端密钥 (如需要)。可以使用 APISIX Secret 存储和引用该值。APISIX 
目前支持通过两种方式存储 secret:[环境变量和 HashiCorp Vault](../terminology/secret.md)。          
                                                                                
  |
 | grant_type                                   | string        | 否   | 
"urn:ietf:params:oauth:grant-type:uma-ticket" | 
["urn:ietf:params:oauth:grant-type:uma-ticket"]                        |        
                                                                                
                                                                                
                                                                               |
 | policy_enforcement_mode                      | string        | 否   | 
"ENFORCING"                                   | ["ENFORCING", "PERMISSIVE"]     
                                       |                                        
                                                                                
                                                                                
                                               |
 | permissions                                  | array[string] | 否   |         
                                      |                                         
                               | 字符串数组,每个字符串代表客户端请求访问的一个或多个资源和作用域的集合。           
                                                                                
                                                                                
   |
 | lazy_load_paths                              | boolean       | 否   | false   
                                      |                                         
                               | 设置为 `true` 时,使用资源注册端点将请求 URI 动态解析为资源,而非使用静态权限。 
                                                                                
                                                                                
      |
 | http_method_as_scope                         | boolean       | 否   | false   
                                      |                                         
                               | 设置为 `true` 时,将 HTTP 请求方法映射为同名作用域,并添加到所有请求的权限中。 
                                                                                
                                                                                
       |
-| timeout                                      | integer       | 否   | 3000    
                                      | [1000, ...]                             
                               | 与 Identity Server 进行 HTTP 连接的超时时间(毫秒)。         
                                                                                
                                                                                
                        |
-| access_token_expires_in                      | integer       | 否   | 300     
                                      | [1, ...]                                
                               | 访问令牌的过期时间(秒)。                                  
                                                                                
                                                                                
                          |
-| access_token_expires_leeway                  | integer       | 否   | 0       
                                      | [0, ...]                                
                               | 访问令牌续期的宽限时间(秒)。设置后,将在令牌过期前 
access_token_expires_leeway 秒进行续期,以避免访问令牌恰好在到达 OAuth 资源服务器时过期的错误。               
                                                                                
   |
-| refresh_token_expires_in                     | integer       | 否   | 3600    
                                      | [1, ...]                                
                               | 刷新令牌的过期时间(秒)。                                  
                                                                                
                                                                                
                          |
-| refresh_token_expires_leeway                 | integer       | 否   | 0       
                                      | [0, ...]                                
                               | 刷新令牌续期的宽限时间(秒)。设置后,将在令牌过期前 
refresh_token_expires_leeway 秒进行续期,以避免刷新令牌恰好在到达 OAuth 资源服务器时过期的错误。              
                                                                                
   |
+| timeout                                      | integer       | 否   | 3000    
                                      | [1000, ...]                             
                               | 与 Identity Server 进行 HTTP 连接的超时时间 (毫秒)。        
                                                                                
                                                                                
                         |
+| access_token_expires_in                      | integer       | 否   | 300     
                                      | [1, ...]                                
                               | 访问令牌的过期时间 (秒)。                                 
                                                                                
                                                                                
                           |
+| access_token_expires_leeway                  | integer       | 否   | 0       
                                      | [0, ...]                                
                               | 访问令牌续期的宽限时间 (秒)。设置后,将在令牌过期前 
access_token_expires_leeway 秒进行续期,以避免访问令牌恰好在到达 OAuth 资源服务器时过期的错误。               
                                                                                
   |
+| refresh_token_expires_in                     | integer       | 否   | 3600    
                                      | [1, ...]                                
                               | 刷新令牌的过期时间 (秒)。                                 
                                                                                
                                                                                
                           |
+| refresh_token_expires_leeway                 | integer       | 否   | 0       
                                      | [0, ...]                                
                               | 刷新令牌续期的宽限时间 (秒)。设置后,将在令牌过期前 
refresh_token_expires_leeway 秒进行续期,以避免刷新令牌恰好在到达 OAuth 资源服务器时过期的错误。              
                                                                                
   |
 | ssl_verify                                   | boolean       | 否   | true    
                                      |                                         
                               | 设置为 `true` 时,验证 TLS 证书与主机名是否匹配。                
                                                                                
                                                                                
                    |
-| cache_ttl_seconds                            | integer       | 否   | 
86400(相当于 24 小时)                       | 正整数 >= 1                               
                             | 插件缓存发现文档和用于向 Keycloak 认证的令牌的最长时间(秒)。             
                                                                                
                                                                                
           |
+| cache_ttl_seconds                            | integer       | 否   | 
86400(相当于 24 小时)                       | 正整数 >= 1                               
                             | 插件缓存发现文档和用于向 Keycloak 认证的令牌的最长时间 (秒)。            
                                                                                
                                                                                
            |
 | keepalive                                    | boolean       | 否   | true    
                                      |                                         
                               | 设置为 `true` 时,启用 HTTP 
keep-alive,保持连接在使用后不关闭。如果预期有大量请求发往 Keycloak,建议设为 `true`。                        
                                                                                
                            |
 | keepalive_timeout                            | integer       | 否   | 60000   
                                      | 正整数 >= 1000                             
                            | 已建立的 HTTP 连接在空闲多久后关闭。                             
                                                                                
                                                                                
                     |
 | keepalive_pool                               | integer       | 否   | 5       
                                      | 正整数 >= 1                                
                            | 连接池中的最大连接数。                                       
                                                                                
                                                                                
                         |
 | access_denied_redirect_uri                   | string        | 否   |         
                                      | [1, 2048]                               
                               | 用于替代返回 `"error_description":"not_authorized"` 
错误信息而重定向用户的 URI。                                                                
                                                                                
                      |
 | password_grant_token_generation_incoming_uri | string        | 否   |         
                                      | /api/token                              
                               | 设置此项以使用密码授权类型生成令牌。插件会将传入请求的 URI 与此值进行比较。       
                                                                                
                                                                                
    |
 
-注意:schema 中还定义了 `encrypt_fields = {"client_secret"}`,这意味着该字段将以加密方式存储在 etcd 
中。请参阅[加密存储字段](../../../en/latest/plugin-develop.md#encrypted-storage-fields)。
+注意:schema 中还定义了 `encrypt_fields = {"client_secret"}`,这意味着该字段将以加密方式存储在 etcd 
中。请参阅[加密存储字段](../plugin-develop.md#encrypted-storage-fields)。

Review Comment:
   The link target in this note uses the anchor `#encrypted-storage-fields`, 
but the referenced Chinese `plugin-develop.md` section header is `## 加密存储字段` 
(and other zh docs link to that anchor). This will produce a broken intra-site 
link; update the anchor to match the Chinese heading.
   



##########
docs/en/latest/plugins/real-ip.md:
##########
@@ -69,9 +69,20 @@ admin_key=$(yq '.deployment.admin.admin_key[0].key' 
conf/config.yaml | sed 's/"/
 
 ### Obtain Real Client Address From URI Parameter
 
-The following example demonstrates how to update the client IP address with a 
URI parameter.
+The following example demonstrates how to update client IP address with an URI 
parameter.

Review Comment:
   Grammar: “an URI parameter” should be “a URI parameter”.
   



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


Reply via email to