http-logger
The http-logger plugin sends APISIX and API7 Gateway request and response logs as JSON objects to HTTP or HTTPS endpoints in batches. It supports authentication headers, TLS verification, and customizable log formats.
Examples
The examples show how to send gateway logs to an HTTP endpoint, add fields with plugin metadata, and include request bodies conditionally.
To follow the examples, go to Mockbin, create a bin, and keep its detail page open so you can inspect received requests. Replace https://your-bin-id.api.mockbin.io/ in the examples with the endpoint shown on that page. Create a dedicated bin because anyone with its detail-page URL can inspect captured request data.
Send Logs in the Default Format
The following example sends logs for matching requests in the default JSON format.
Create a route with the http-logger plugin and configure the Mockbin endpoint:
- Admin API
- ADC
- Ingress Controller
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "http-logger-route",
"uri": "/anything",
"plugins": {
"http-logger": {
"uri": "https://your-bin-id.api.mockbin.io/",
"batch_max_size": 1
}
},
"upstream": {
"nodes": {
"httpbin.org:80": 1
},
"type": "roundrobin"
}
}'
services:
- name: httpbin
labels:
docs-example: http-logger
routes:
- uris:
- /anything
name: http-logger-route
plugins:
http-logger:
uri: "https://your-bin-id.api.mockbin.io/"
batch_max_size: 1
upstream:
type: roundrobin
nodes:
- host: httpbin.org
port: 80
weight: 1
Preview changes to services with the example label:
adc diff -f adc.yaml \
--include-resource-type service \
--label-selector docs-example=http-logger
Synchronize the reviewed changes:
adc sync -f adc.yaml \
--include-resource-type service \
--label-selector docs-example=http-logger
- Gateway API
- APISIX CRD
apiVersion: v1
kind: Service
metadata:
namespace: aic
name: httpbin-external-domain
spec:
type: ExternalName
externalName: httpbin.org
ports:
- name: http
port: 80
targetPort: 80
---
apiVersion: apisix.apache.org/v1alpha1
kind: PluginConfig
metadata:
namespace: aic
name: http-logger-plugin-config
spec:
plugins:
- name: http-logger
config:
uri: "https://your-bin-id.api.mockbin.io/"
batch_max_size: 1
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
namespace: aic
name: http-logger-route
spec:
parentRefs:
- name: apisix
rules:
- matches:
- path:
type: Exact
value: /anything
filters:
- type: ExtensionRef
extensionRef:
group: apisix.apache.org
kind: PluginConfig
name: http-logger-plugin-config
backendRefs:
- name: httpbin-external-domain
port: 80
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: http-logger-route
spec:
ingressClassName: apisix
http:
- name: http-logger-route
match:
paths:
- /anything
methods:
- GET
upstreams:
- name: httpbin-external-domain
plugins:
- name: http-logger
config:
uri: "https://your-bin-id.api.mockbin.io/"
batch_max_size: 1
Apply the configuration:
kubectl apply -f http-logger-ic.yaml
The example sends each log entry immediately for verification.
Send a request to the route:
curl "http://127.0.0.1:9080/anything"
You should receive an HTTP/1.1 200 OK response. On the Mockbin detail page, the captured request body should contain fields similar to the following:
{
"request": {
"method": "GET",
"uri": "/anything",
"url": "http://127.0.0.1:9080/anything"
},
"response": {
"status": 200
},
"server": {
"version": "3.18.0"
}
}
Add Fields With Plugin Metadata
The following example uses plugin metadata to add selected request and response fields to every http-logger instance. The metadata values reference built-in variables, so one configuration applies across multiple routes and services.
First, create a route with the http-logger plugin and configure the plugin with your server URI:
- Admin API
- ADC
- Ingress Controller
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "http-logger-route",
"uri": "/anything",
"plugins": {
"http-logger": {
"uri": "https://your-bin-id.api.mockbin.io/",
"batch_max_size": 1
}
},
"upstream": {
"nodes": {
"httpbin.org:80": 1
},
"type": "roundrobin"
}
}'
services:
- name: httpbin
labels:
docs-example: http-logger
routes:
- uris:
- /anything
name: http-logger-route
plugins:
http-logger:
uri: "https://your-bin-id.api.mockbin.io/"
batch_max_size: 1
upstream:
type: roundrobin
nodes:
- host: httpbin.org
port: 80
weight: 1
Preview changes to services with the example label:
adc diff -f adc.yaml \
--include-resource-type service \
--label-selector docs-example=http-logger
Synchronize the reviewed changes:
adc sync -f adc.yaml \
--include-resource-type service \
--label-selector docs-example=http-logger
- Gateway API
- APISIX CRD
apiVersion: v1
kind: Service
metadata:
namespace: aic
name: httpbin-external-domain
spec:
type: ExternalName
externalName: httpbin.org
ports:
- name: http
port: 80
targetPort: 80
---
apiVersion: apisix.apache.org/v1alpha1
kind: PluginConfig
metadata:
namespace: aic
name: http-logger-plugin-config
spec:
plugins:
- name: http-logger
config:
uri: "https://your-bin-id.api.mockbin.io/"
batch_max_size: 1
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
namespace: aic
name: http-logger-route
spec:
parentRefs:
- name: apisix
rules:
- matches:
- path:
type: Exact
value: /anything
filters:
- type: ExtensionRef
extensionRef:
group: apisix.apache.org
kind: PluginConfig
name: http-logger-plugin-config
backendRefs:
- name: httpbin-external-domain
port: 80
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: http-logger-route
spec:
ingressClassName: apisix
http:
- name: http-logger-route
match:
paths:
- /anything
methods:
- GET
upstreams:
- name: httpbin-external-domain
plugins:
- name: http-logger
config:
uri: "https://your-bin-id.api.mockbin.io/"
batch_max_size: 1
Apply the configuration:
kubectl apply -f http-logger-ic.yaml
Next, configure the plugin metadata for http-logger:
- Admin API
- ADC
- Ingress Controller
curl "http://127.0.0.1:9180/apisix/admin/plugin_metadata/http-logger" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"log_format_extra": {
"env": "$http_env",
"resp_content_type": "$sent_http_Content_Type"
}
}'
Plugin metadata is a global collection and cannot be isolated with a label selector. Export the complete collection before changing this entry:
adc dump -o adc-metadata.yaml --with-id \
--include-resource-type plugin_metadata
Add or update the http-logger entry while preserving every other entry in adc-metadata.yaml:
plugin_metadata:
# Keep all other plugin metadata entries from the exported file.
http-logger:
log_format_extra:
env: "$http_env"
resp_content_type: "$sent_http_Content_Type"
Preview the complete metadata change and confirm that it contains no unintended updates or deletions:
adc diff -f adc-metadata.yaml \
--include-resource-type plugin_metadata
Synchronize the reviewed plugin metadata collection:
adc sync -f adc-metadata.yaml \
--include-resource-type plugin_metadata
Add the following entry under spec.pluginMetadata in the complete GatewayProxy manifest used by the deployment:
http-logger:
log_format_extra:
env: "$http_env"
resp_content_type: "$sent_http_Content_Type"
Apply the updated complete manifest through the deployment's normal Kubernetes or GitOps workflow.
❶ Add the custom request header env to each default log entry.
❷ Add the upstream response header Content-Type to each default log entry.
Send a request to the route with the env header:
curl "http://127.0.0.1:9080/anything" -H "env: dev"
You should receive an HTTP/1.1 200 OK response. On the Mockbin detail page, the captured request body should include fields similar to the following:
{
"env": "dev",
"resp_content_type": "application/json"
}
Log Request Bodies Conditionally
The following example demonstrates how you can conditionally log request body.
Create a route with the http-logger plugin as follows:
- Admin API
- ADC
- Ingress Controller
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "http-logger-route",
"uri": "/anything",
"plugins": {
"http-logger": {
"uri": "https://your-bin-id.api.mockbin.io/",
"include_req_body": true,
"include_req_body_expr": [["arg_log_body", "==", "yes"]],
"batch_max_size": 1
}
},
"upstream": {
"nodes": {
"httpbin.org:80": 1
},
"type": "roundrobin"
}
}'
services:
- name: httpbin
labels:
docs-example: http-logger
routes:
- uris:
- /anything
name: http-logger-route
plugins:
http-logger:
uri: "https://your-bin-id.api.mockbin.io/"
include_req_body: true
include_req_body_expr:
- - "arg_log_body"
- "=="
- "yes"
batch_max_size: 1
upstream:
type: roundrobin
nodes:
- host: httpbin.org
port: 80
weight: 1
Preview changes to services with the example label:
adc diff -f adc.yaml \
--include-resource-type service \
--label-selector docs-example=http-logger
Synchronize the reviewed changes:
adc sync -f adc.yaml \
--include-resource-type service \
--label-selector docs-example=http-logger
- Gateway API
- APISIX CRD
apiVersion: v1
kind: Service
metadata:
namespace: aic
name: httpbin-external-domain
spec:
type: ExternalName
externalName: httpbin.org
ports:
- name: http
port: 80
targetPort: 80
---
apiVersion: apisix.apache.org/v1alpha1
kind: PluginConfig
metadata:
namespace: aic
name: http-logger-plugin-config
spec:
plugins:
- name: http-logger
config:
uri: "https://your-bin-id.api.mockbin.io/"
include_req_body: true
include_req_body_expr:
- - "arg_log_body"
- "=="
- "yes"
batch_max_size: 1
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
namespace: aic
name: http-logger-route
spec:
parentRefs:
- name: apisix
rules:
- matches:
- path:
type: Exact
value: /anything
filters:
- type: ExtensionRef
extensionRef:
group: apisix.apache.org
kind: PluginConfig
name: http-logger-plugin-config
backendRefs:
- name: httpbin-external-domain
port: 80
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: http-logger-route
spec:
ingressClassName: apisix
http:
- name: http-logger-route
match:
paths:
- /anything
methods:
- GET
- POST
upstreams:
- name: httpbin-external-domain
plugins:
- name: http-logger
config:
uri: "https://your-bin-id.api.mockbin.io/"
include_req_body: true
include_req_body_expr:
- - "arg_log_body"
- "=="
- "yes"
batch_max_size: 1
Apply the configuration:
kubectl apply -f http-logger-ic.yaml
❶ include_req_body: set to true to include request body.
❷ include_req_body_expr: only include request body if the URL query string log_body is yes.
Send a request to the route with a URL query string satisfying the condition:
curl -i "http://127.0.0.1:9080/anything?log_body=yes" -X POST -d '{"env": "dev"}'
You should see the request body logged:
{
"request": {
"querystring": {
"log_body": "yes"
},
"body": "{\"env\": \"dev\"}"
}
}
Send a request to the route without any URL query string:
curl -i "http://127.0.0.1:9080/anything" -X POST -d '{"env": "dev"}'
You should not observe the request body in the log.
The default log entry includes request and response bodies collected by the plugin. If you configure log_format, include the corresponding variables explicitly:
{
"include_req_body": true,
"include_resp_body": true,
"log_format": {
"request_body": "$request_body",
"response_body": "$resp_body"
}
}
Body size limits still apply. Use log_format_extra to add custom fields without replacing the default log entry.