在访问日志中包含消费者标签
消费者标签是关联到消费者和凭证的键值对,可用于表示部门、组织或服务等级等元数据。默认情况下,访问日志仅包含消费者用户名。本指南介绍如何在网关访问日志中包含消费者标签,以便进行更精细的流量分析。
工作原理
该方案使用以下三个组件:
- 自定义 NGINX 变量:在网关配置中声明变量(例如
$consumer_company)并设置默认值。 serverless-pre-function:全局插件在运行时读取消费者标签并将其赋值给该变量。- 访问日志格式:在日志输出中包含自定义变量。
前置条件
- 正在运行的 API7 网关部署。
- 可以访问网关的
config.yaml配置文件。 - 从控制台获取令牌。
步骤一:声明自定义变量
在网关的 config.yaml 中声明自定义 NGINX 变量并设置默认值。可以为不同的标签声明多个变量:
nginx_config:
http_server_location_configuration_snippet: |
set $consumer_company "-";
步骤二:更新访问日志格式
在同一配置文件中,将自定义变量添加到访问日志格式中:
nginx_config:
http:
access_log_format: >-
$remote_addr - $remote_user [$time_local] $http_host
"$request" $status $body_bytes_sent $request_time
"$http_referer" "$http_user_agent"
$upstream_addr $upstream_status $upstream_response_time
"$consumer_company"
重新加载或重启网关使配置生效。
步骤三:使用 Serverless Function 赋值
将 serverless-pre-function 配置为全局插件,以读取消费者标签并将其赋值给自定义变量:
- Admin API
- ADC
curl -k "https://localhost:7443/apisix/admin/global_rules/serverless-pre-function?gateway_group_id={gateway_group_id}" -X PUT \
-H "X-API-KEY: ${API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"plugins": {
"serverless-pre-function": {
"phase": "rewrite",
"functions": [
"return function (conf, ctx) ngx.var.consumer_company = ctx.consumer and ctx.consumer.labels and ctx.consumer.labels[\"company\"] or \"unknown\" end"
]
}
}
}'
global_rules:
serverless-pre-function:
phase: rewrite
functions:
- >-
return function (conf, ctx)
ngx.var.consumer_company = ctx.consumer
and ctx.consumer.labels
and ctx.consumer.labels["company"]
or "unknown"
end
adc sync -f adc.yaml
该函数读取消费者的 company 标签。如果消费者没有该标签,或未识别出消费者(例如未经身份认证的请求),变量值默认为 "unknown"。
步骤四:配置消费者和受保护路由
创建带有 company 标签和 Key 身份认证凭证的消费者,然后创建受 key-auth 保护的路由:
- Admin API
- ADC
# 创建带标签的消费者
curl -k "https://localhost:7443/apisix/admin/consumers/john?gateway_group_id={gateway_group_id}" -X PUT \
-H "X-API-KEY: ${API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"username": "john",
"labels": {
"company": "smart-technology"
}
}'
# 添加 key-auth 凭证
curl -k "https://localhost:7443/apisix/admin/consumers/john/credentials/primary-key?gateway_group_id={gateway_group_id}" -X PUT \
-H "X-API-KEY: ${API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"name": "primary-key",
"plugins": {
"key-auth": {
"key": "john-key"
}
}
}'
# 创建带上游的服务
curl -k "https://localhost:7443/apisix/admin/services/consumer-label-demo?gateway_group_id={gateway_group_id}" -X PUT \
-H "X-API-KEY: ${API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"name": "consumer-label-demo",
"upstream": {
"type": "roundrobin",
"nodes": [
{ "host": "httpbin.org", "port": 80, "weight": 1 }
]
}
}'
# 创建受 key-auth 保护的路由
curl -k "https://localhost:7443/apisix/admin/routes/consumer-label-demo?gateway_group_id={gateway_group_id}" -X PUT \
-H "X-API-KEY: ${API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"name": "consumer-label-demo",
"paths": ["/anything"],
"service_id": "consumer-label-demo",
"plugins": {
"key-auth": {}
}
}'
consumers:
- username: john
labels:
company: smart-technology
credentials:
- name: primary-key
type: key-auth
config:
key: john-key
services:
- name: consumer-label-demo
routes:
- name: consumer-label-demo
uris:
- /anything
plugins:
key-auth: {}
upstream:
type: roundrobin
nodes:
- host: httpbin.org
port: 80
weight: 1
adc sync -f adc.yaml
步骤五:验证
使用有效的消费者密钥发送请求:
curl -i "http://127.0.0.1:9080/anything" -H "apikey: john-key"
响应应为 HTTP/1.1 200 OK。访问日志条目中包含消费者标签:
192.168.1.1 - - [18/Mar/2025:09:17:28 +0000] 127.0.0.1:9080 "GET /anything HTTP/1.1" 200 508 1.260 "-" "curl/8.6.0" 13.210.43.76:80 200 1.153 "smart-technology"
发送不带密钥的请求:
curl -i "http://127.0.0.1:9080/anything"
访问日志显示默认值:
192.168.1.1 - - [18/Mar/2025:09:18:27 +0000] 127.0.0.1:9080 "GET /anything HTTP/1.1" 401 52 0.000 "-" "curl/8.6.0" - - - "unknown"
替代方案:通过请求头转发标签
如果希望 http-logger、kafka-logger 等日志插件的结构化日志条目包含消费者标签,请使用 attach-consumer-label 插件将消费者标签映射到上游请求头。这些请求头随后可用作 NGINX 变量(例如 $http_x_consumer_company),供任意日志插件的 log_format 引用。
更新步骤四中的路由,在 key-auth 旁添加这两个插件。以下示例使用日志端点 http://log-collector:8080/logs:
- Admin API
- ADC
curl -k "https://localhost:7443/apisix/admin/routes/consumer-label-demo?gateway_group_id={gateway_group_id}" -X PUT \
-H "X-API-KEY: ${API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"name": "consumer-label-demo",
"paths": ["/anything"],
"service_id": "consumer-label-demo",
"plugins": {
"key-auth": {},
"attach-consumer-label": {
"headers": {
"X-Consumer-Company": "$company"
}
},
"http-logger": {
"uri": "http://log-collector:8080/logs",
"log_format": {
"consumer_company": "$http_x_consumer_company"
}
}
}
}'
services:
- name: consumer-label-demo
routes:
- name: consumer-label-demo
uris:
- /anything
plugins:
key-auth: {}
attach-consumer-label:
headers:
X-Consumer-Company: "$company"
http-logger:
uri: http://log-collector:8080/logs
log_format:
consumer_company: "$http_x_consumer_company"
upstream:
type: roundrobin
nodes:
- host: httpbin.org
port: 80
weight: 1
adc sync -f adc.yaml
attach-consumer-label 中的 $ 前缀引用消费者标签键。来自已通过身份认证的消费者的请求会在到达上游和日志插件之前注入相应的请求头。