Skip to main content
Version: Next

elasticsearch-logger

描述#

elasticsearch-logger 插件将请求和响应日志批量推送到 Elasticsearch,并支持自定义日志格式。启用后,插件会将请求上下文信息序列化为 Elasticsearch Bulk 格式 并将其添加到队列中,然后再推送到 Elasticsearch。有关更多详细信息,请参阅 批处理器

属性#

名称类型必选项默认值描述
endup_addrsarray[string]Elasticsearch API 端点地址。如果配置了多个端点,则会随机写入。
fieldobjectElasticsearch field 配置。
field.indexstringElasticsearch _index 字段
field.typestringElasticsearch 默认值Elasticsearch _type 字段
log_formatobjectJSON 格式的键值对中的自定义日志格式。值中支持 APISIXNGINX 变量
autharrayElasticsearch 身份验证 配置。
auth.usernamestringElasticsearch 身份验证 用户名​​。
auth.passwordstringElasticsearch 身份验证 密码。
ssl_verifybooleantrue如果为 true,则执行 SSL 验证。
timeoutinteger10Elasticsearch 发送数据超时(秒)。
include_req_bodybooleanfalse如果为 true,则将请求主体包含在日志中。请注意,如果请求主体太大而无法保存在内存中,则由于 NGINX 的限制而无法记录。
include_req_body_exprarray[array]一个或多个条件的数组,形式为 lua-resty-expr。在 include_req_body 为 true 时使用。仅当此处配置的表达式计算结果为 true 时,才会记录请求主体。
include_resp_bodybooleanfalse如果为 true,则将响应主体包含在日志中。
include_resp_body_exprarray[array]一个或多个条件的数组,形式为 lua-resty-expr。在 include_resp_body 为 true 时使用。仅当此处配置的表达式计算结果为 true 时,才会记录响应主体。

注意:schema 中还定义了 encrypt_fields = {"auth.password"},这意味着该字段将会被加密存储在 etcd 中。具体参考 加密存储字段

本插件支持使用批处理器来聚合并批量处理条目(日志和数据)。这样可以避免插件频繁地提交数据,默认设置情况下批处理器会每 5 秒钟或队列中的数据达到 1000 条时提交数据,如需了解或自定义批处理器相关参数设置,请参考 Batch-Processor 配置部分。

Plugin Metadata#

NameTypeRequiredDefaultDescription
log_formatobject自定义日志格式为 JSON 格式的键值对。值中支持 APISIX 变量NGINX 变量

示例#

以下示例演示了如何为不同场景配置 elasticsearch-logger 插件。

要遵循示例,请在 Docker 中启动 Elasticsearch 实例:

docker run -d \
--name elasticsearch \
--network apisix-quickstart-net \
-v elasticsearch_vol:/usr/share/elasticsearch/data/ \
-p 9200:9200 \
-p 9300:9300 \
-e ES_JAVA_OPTS="-Xms512m -Xmx512m" \
-e discovery.type=single-node \
-e xpack.security.enabled=false \
docker.elastic.co/elasticsearch/elasticsearch:7.17.1

在 Docker 中启动 Kibana 实例,以可视化 Elasticsearch 中的索引数据:

docker run -d \
--name kibana \
--network apisix-quickstart-net \
-p 5601:5601 \
-e ELASTICSEARCH_HOSTS="http://elasticsearch:9200" \
docker.elastic.co/kibana/kibana:7.17.1

如果成功,您应该在 localhost:5601 上看到 Kibana 仪表板。

note

您可以这样从 config.yaml 中获取 admin_key 并存入环境变量:

admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')

以默认日志格式记录#

以下示例演示如何在路由上启用 elasticsearch-logger 插件,该插件记录客户端对路由的请求和响应,并将日志推送到 Elasticsearch。

使用 elasticsearch-logger 创建路由,将 index 字段配置为 gateway,将 type 字段配置为 logs

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "elasticsearch-logger-route",
"uri": "/anything",
"plugins": {
"elasticsearch-logger": {
"endpoint_addrs": ["http://elasticsearch:9200"],
"field": {
"index": "gateway",
"type": "logs"
}
}
},
"upstream": {
"nodes": {
"httpbin.org:80": 1
},
"type": "roundrobin"
}
}'

向路由发送请求以生成日志条目:

curl -i "http://127.0.0.1:9080/anything"

您应该会收到 HTTP/1.1 200 OK 响应。

导航到 localhost:5601 上的 Kibana 仪表板,并在 Discover 选项卡下创建一个新的索引模式 gateway 以从 Elasticsearch 获取数据。配置完成后,导航回 Discover 选项卡,您应该会看到生成的日志,类似于以下内容:

{
"_index": "gateway",
"_type": "logs",
"_id": "CE-JL5QBOkdYRG7kEjTJ",
"_version": 1,
"_score": 1,
"_source": {
"request": {
"headers": {
"host": "127.0.0.1:9080",
"accept": "*/*",
"user-agent": "curl/8.6.0"
},
"size": 85,
"querystring": {},
"method": "GET",
"url": "http://127.0.0.1:9080/anything",
"uri": "/anything"
},
"response": {
"headers": {
"content-type": "application/json",
"access-control-allow-credentials": "true",
"server": "APISIX/3.11.0",
"content-length": "390",
"access-control-allow-origin": "*",
"connection": "close",
"date": "Mon, 13 Jan 2025 10:18:14 GMT"
},
"status": 200,
"size": 618
},
"route_id": "elasticsearch-logger-route",
"latency": 585.00003814697,
"apisix_latency": 18.000038146973,
"upstream_latency": 567,
"upstream": "50.19.58.113:80",
"server": {
"hostname": "0b9a772e68f8",
"version": "3.11.0"
},
"service_id": "",
"client_ip": "192.168.65.1"
},
"fields": {
...
}
}

使用 Plugin Metadata 记录请求和响应标头#

以下示例演示了如何使用 Plugin MetadataNGINX 变量 自定义日志格式,以记录请求和响应中的特定标头。

在 APISIX 中,Plugin Metadata 用于配置同一插件的所有插件实例的通用元数据字段。当插件在多个资源中启用并需要对其元数据字段进行通用更新时,它很有用。

首先,使用 elasticsearch-logger 创建路由,如下所示:

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "elasticsearch-logger-route",
"uri": "/anything",
"plugins": {
"elasticsearch-logger": {
"endpoint_addrs": ["http://elasticsearch:9200"],
"field": {
"index": "gateway",
"type": "logs"
}
},
"upstream": {
"nodes": {
"httpbin.org:80": 1
},
"type": "roundrobin"
}
}'

接下来,配置 elasticsearch-logger 的 Plugin Metadata:

curl "http://127.0.0.1:9180/apisix/admin/plugin_metadata/elasticsearch-logger" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"log_format": {
"host": "$host",
"@timestamp": "$time_iso8601",
"client_ip": "$remote_addr",
"env": "$http_env",
"resp_content_type": "$sent_http_Content_Type"
}
}'

使用 env 标头向路由发送请求:

curl -i "http://127.0.0.1:9080/anything" -H "env: dev"

您应该会收到 HTTP/1.1 200 OK 响应。

导航到 localhost:5601 上的 Kibana 仪表板,并在 Discover 选项卡下创建一个新的索引模式 gateway 以从 Elasticsearch 获取数据(如果您尚未这样做)。配置完成后,导航回 Discover 选项卡,您应该会看到生成的日志,类似于以下内容:

{
"_index": "gateway",
"_type": "logs",
"_id": "Ck-WL5QBOkdYRG7kODS0",
"_version": 1,
"_score": 1,
"_source": {
"client_ip": "192.168.65.1",
"route_id": "elasticsearch-logger-route",
"@timestamp": "2025-01-06T10:32:36+00:00",
"host": "127.0.0.1",
"resp_content_type": "application/json"
},
"fields": {
...
}
}

有条件地记录请求主体#

以下示例演示了如何有条件地记录请求主体。

使用 elasticsearch-logger 创建路由,仅在 URL 查询字符串 log_bodytrue 时记录请求主体:

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"plugins": {
"elasticsearch-logger": {
"endpoint_addrs": ["http://elasticsearch:9200"],
"field": {
"index": "gateway",
"type": "logs"
},
"include_req_body": true,
"include_req_body_expr": [["arg_log_body", "==", "yes"]]
}
},
"upstream": {
"nodes": {
"httpbin.org:80": 1
},
"type": "roundrobin"
},
"uri": "/anything",
"id": "elasticsearch-logger-route"
}'

使用满足以下条件的 URL 查询字符串向路由发送请求:

curl -i "http://127.0.0.1:9080/anything?log_body=yes" -X POST -d '{"env": "dev"}'

您应该会收到 HTTP/1.1 200 OK 响应。

导航到 localhost:5601 上的 Kibana 仪表板,并在 Discover 选项卡下创建一个新的索引模式 gateway 以从 Elasticsearch 获取数据(如果您尚未这样做)。配置完成后,导航回 Discover 选项卡,您应该会看到生成的日志,类似于以下内容:

{
"_index": "gateway",
"_type": "logs",
"_id": "Dk-cL5QBOkdYRG7k7DSW",
"_version": 1,
"_score": 1,
"_source": {
"request": {
"headers": {
"user-agent": "curl/8.6.0",
"accept": "*/*",
"content-length": "14",
"host": "127.0.0.1:9080",
"content-type": "application/x-www-form-urlencoded"
},
"size": 182,
"querystring": {
"log_body": "yes"
},
"body": "{\"env\": \"dev\"}",
"method": "POST",
"url": "http://127.0.0.1:9080/anything?log_body=yes",
"uri": "/anything?log_body=yes"
},
"start_time": 1735965595203,
"response": {
"headers": {
"content-type": "application/json",
"server": "APISIX/3.11.0",
"access-control-allow-credentials": "true",
"content-length": "548",
"access-control-allow-origin": "*",
"connection": "close",
"date": "Mon, 13 Jan 2025 11:02:32 GMT"
},
"status": 200,
"size": 776
},
"route_id": "elasticsearch-logger-route",
"latency": 703.9999961853,
"apisix_latency": 34.999996185303,
"upstream_latency": 669,
"upstream": "34.197.122.172:80",
"server": {
"hostname": "0b9a772e68f8",
"version": "3.11.0"
},
"service_id": "",
"client_ip": "192.168.65.1"
},
"fields": {
...
}
}

向路由发送一个没有任何 URL 查询字符串的请求:

curl -i "http://127.0.0.1:9080/anything" -X POST -d '{"env": "dev"}'

导航到 Kibana 仪表板 Discover 选项卡,您应该看到生成的日志,但没有请求正文:

{
"_index": "gateway",
"_type": "logs",
"_id": "EU-eL5QBOkdYRG7kUDST",
"_version": 1,
"_score": 1,
"_source": {
"request": {
"headers": {
"content-type": "application/x-www-form-urlencoded",
"accept": "*/*",
"content-length": "14",
"host": "127.0.0.1:9080",
"user-agent": "curl/8.6.0"
},
"size": 169,
"querystring": {},
"method": "POST",
"url": "http://127.0.0.1:9080/anything",
"uri": "/anything"
},
"start_time": 1735965686363,
"response": {
"headers": {
"content-type": "application/json",
"access-control-allow-credentials": "true",
"server": "APISIX/3.11.0",
"content-length": "510",
"access-control-allow-origin": "*",
"connection": "close",
"date": "Mon, 13 Jan 2025 11:15:54 GMT"
},
"status": 200,
"size": 738
},
"route_id": "elasticsearch-logger-route",
"latency": 680.99999427795,
"apisix_latency": 4.9999942779541,
"upstream_latency": 676,
"upstream": "34.197.122.172:80",
"server": {
"hostname": "0b9a772e68f8",
"version": "3.11.0"
},
"service_id": "",
"client_ip": "192.168.65.1"
},
"fields": {
...
}
}
info

如果您除了将 include_req_bodyinclude_resp_body 设置为 true 之外还自定义了 log_format,则插件不会在日志中包含正文。

作为一种解决方法,您可以在日志格式中使用 NGINX 变量 $request_body,例如:

{
"elasticsearch-logger": {
...,
"log_format": {"body": "$request_body"}
}
}