实现clickhouse-logger自定义请求头存储
需求描述
公司需要实现全链路日志采集功能,调研发现apisix的clickhouse-logger插件,但是我们的请求会有一些自定义的请求头以及对应路由的区分。因此考虑到基于clickhouse-logger结合apisix的注册自定义变量功能来实现。
因此我们调研下来通过注册一个叫做 route_label_customer_type
的变量来获取路由中 customerType
标签的值来做clickhouse中的记录区分。也可以将请求中自定义的header值存储到clickhouse中。
实现
首先在apisix的clickhouse-logger.lua中追加如下代码:
-- 获取request中的自定义header
core.ctx.register_var("x_customer_type", function(ctx)
local type = core.request.header(ctx, "x_customer_type")
if type then
return type
end
return nil
end)
-- 注册一个叫做 route_label_customer_type 的变量来获取路由中 customerType 标签的值。
core.ctx.register_var("route_label_customer_type", function(ctx)
local route = ctx.matched_route and ctx.matched_route.value
if route and route.labels then
return route.labels.customerType
end
return nil
end)
设置路由标签
"labels": {
"customerType": "测试接口"
}
通过proxy-rewrite
插件追加自定义请求header
"proxy-rewrite": {
"headers": {
"x_customer_type": "开启计费模式"
}
}
然后配置 log_format 元数据参数。log_format 的格式必须与数据库表的结构保持一致,否则会导致写入失败。
curl http://127.0.0.1:9080/apisix/admin/plugin_metadata/clickhouse-logger \
-H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
"log_format": {
"upstream_header_time": "$upstream_header_time",
"upstream_connect_time": "$upstream_connect_time",
"status": "$status",
"host": "$host",
"body_bytes_sent": "$body_bytes_sent",
"request": "$request",
"remote_user": "$remote_user",
"client_ip": "$remote_addr",
"content_length": "$content_length",
"local_time": "$fmt_ms_time_local",
"http_referer": "$http_referer",
"http_x_amz_target": "$http_x_amz_target",
"http_x_request_id": "$http_x_request_id",
"upstream_response_time": "$upstream_response_time",
"upstream_status": "$upstream_status",
"http_user_agent": "$http_user_agent",
"request_time": "$request_time",
"upstream_addr": "$upstream_addr",
"http_host": "$http_host",
"content_type": "$content_type",
"route_id": "$route_id",
"route_name": "$route_name",
"consumer_name": "$consumer_name",
"arg": "$args",
"request_body": "$request_body",
"req_timestamp": "$time_iso8601",
"request_uri": "$request_uri",
"x_customer_type": "$x_customer_type",
"route_label_customer_type": "$route_label_customer_type"
}
}'
创建 ClickHouse 写入的表格
CREATE TABLE default.record (
`upstream_header_time` Float64,
`upstream_connect_time` Float64,
`status` Int16,
`host` String,
`body_bytes_sent` String,
`request` String,
`remote_user` String,
`client_ip` String,
`content_length` Int32,
`local_time` String,
`http_referer` String,
`http_x_amz_target` String,
`http_x_request_id` String,
`upstream_response_time` Float64,
`upstream_status` String,
`http_user_agent` String,
`request_time` Float64,
`upstream_addr` String,
`http_host` String,
`content_type` String,
`route_id` String,
`route_name` String,
`consumer_name` String,
`req_timestamp` String,
`arg` String,
`request_body` String,
`request_uri` String,
`x_customer_type` String,
`route_label_customer_type` String,
PRIMARY KEY(`http_x_request_id`)
) ENGINE = MergeTree()
在 ClickHouse 上执行 select * from default.record;,将得到类似下面的数据。
┌─host──────┬─client_ip─┬─route_id─┬─route_label_customer_type───┐─x_customer_type────┐
│ 127.0.0.1 │ 127.0.0.1 │ 1 │ 测试接口 │开启计费模式 │
└───────────┴───────────┴──────────┴─────────────────────────────┘────────────────────┘