Skip to content

Commit 1b4b87a

Browse files
authored
Merge branch 'apache:master' into master
2 parents 3b788c7 + d520a84 commit 1b4b87a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+698
-189
lines changed

.github/workflows/build.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,10 @@ jobs:
8181
run: |
8282
bash ./ci/free_disk_space.sh
8383
84+
- name: Set hostname
85+
run: |
86+
sudo sh -c 'echo "127.0.1.1 httpbin.local" >> /etc/hosts'
87+
8488
- name: Linux Before install
8589
run: sudo ./ci/${{ matrix.os_name }}_runner.sh before_install
8690

.github/workflows/push-dev-image-on-commit.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ jobs:
6868
"uri": "/get",
6969
"upstream": {
7070
"type": "roundrobin",
71-
"nodes": { "httpbin.org:80": 1 }
71+
"nodes": { "httpbin:8080": 1 }
7272
}
7373
}'
7474

apisix/discovery/nacos/init.lua

Lines changed: 98 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ local core = require('apisix.core')
2222
local ipairs = ipairs
2323
local pairs = pairs
2424
local type = type
25-
local math = math
2625
local math_random = math.random
2726
local ngx = ngx
2827
local ngx_re = require('ngx.re')
@@ -164,10 +163,7 @@ local function get_signed_param(group_name, service_name)
164163
end
165164

166165

167-
local function get_base_uri()
168-
local host = local_conf.discovery.nacos.host
169-
-- TODO Add health check to get healthy nodes.
170-
local url = host[math_random(#host)]
166+
local function build_base_uri(url)
171167
local auth_idx = core.string.rfind_char(url, '@')
172168
local username, password
173169
if auth_idx then
@@ -195,6 +191,18 @@ local function get_base_uri()
195191
end
196192

197193

194+
local function get_base_uri_by_index(index)
195+
local host = local_conf.discovery.nacos.host
196+
197+
local url = host[index]
198+
if not url then
199+
return nil
200+
end
201+
202+
return build_base_uri(url)
203+
end
204+
205+
198206
local function de_duplication(services, namespace_id, group_name, service_name, scheme)
199207
for _, service in ipairs(services) do
200208
if service.namespace_id == namespace_id and service.group_name == group_name
@@ -277,69 +285,114 @@ local function is_grpc(scheme)
277285
end
278286

279287
local curr_service_in_use = {}
280-
local function fetch_full_registry(premature)
281-
if premature then
282-
return
283-
end
284288

285-
local base_uri, username, password = get_base_uri()
289+
290+
local function fetch_from_host(base_uri, username, password, services)
286291
local token_param, err = get_token_param(base_uri, username, password)
287292
if err then
288-
log.error('get_token_param error:', err)
289-
return
293+
return false, err
290294
end
291295

292-
local infos = get_nacos_services()
293-
if #infos == 0 then
294-
return
295-
end
296296
local service_names = {}
297-
for _, service_info in ipairs(infos) do
298-
local data, err
297+
local nodes_cache = {}
298+
local had_success = false
299+
300+
for _, service_info in ipairs(services) do
299301
local namespace_id = service_info.namespace_id
300302
local group_name = service_info.group_name
301303
local scheme = service_info.scheme or ''
302-
local namespace_param = get_namespace_param(service_info.namespace_id)
303-
local group_name_param = get_group_name_param(service_info.group_name)
304-
local signature_param = get_signed_param(service_info.group_name, service_info.service_name)
304+
local namespace_param = get_namespace_param(namespace_id)
305+
local group_name_param = get_group_name_param(group_name)
306+
local signature_param = get_signed_param(group_name, service_info.service_name)
305307
local query_path = instance_list_path .. service_info.service_name
306308
.. token_param .. namespace_param .. group_name_param
307309
.. signature_param
308-
data, err = get_url(base_uri, query_path)
309-
if err then
310-
log.error('get_url:', query_path, ' err:', err)
311-
goto CONTINUE
312-
end
310+
local data, req_err = get_url(base_uri, query_path)
311+
if req_err then
312+
log.error('failed to fetch instances for service [', service_info.service_name,
313+
'] from ', base_uri, ', error: ', req_err)
314+
else
315+
had_success = true
316+
317+
local key = get_key(namespace_id, group_name, service_info.service_name)
318+
service_names[key] = true
313319

314-
local nodes = {}
315-
local key = get_key(namespace_id, group_name, service_info.service_name)
316-
service_names[key] = true
317-
for _, host in ipairs(data.hosts) do
318-
local node = {
319-
host = host.ip,
320-
port = host.port,
321-
weight = host.weight or default_weight,
322-
}
323-
-- docs: https://github.com/yidongnan/grpc-spring-boot-starter/pull/496
324-
if is_grpc(scheme) and host.metadata and host.metadata.gRPC_port then
325-
node.port = host.metadata.gRPC_port
320+
local hosts = data.hosts
321+
if type(hosts) ~= 'table' then
322+
hosts = {}
326323
end
327324

328-
core.table.insert(nodes, node)
329-
end
330-
if #nodes > 0 then
331-
local content = core.json.encode(nodes)
332-
nacos_dict:set(key, content)
325+
local nodes = {}
326+
for _, host in ipairs(hosts) do
327+
local node = {
328+
host = host.ip,
329+
port = host.port,
330+
weight = host.weight or default_weight,
331+
}
332+
-- docs: https://github.com/yidongnan/grpc-spring-boot-starter/pull/496
333+
if is_grpc(scheme) and host.metadata and host.metadata.gRPC_port then
334+
node.port = host.metadata.gRPC_port
335+
end
336+
337+
core.table.insert(nodes, node)
338+
end
339+
340+
if #nodes > 0 then
341+
nodes_cache[key] = nodes
342+
end
333343
end
334-
::CONTINUE::
335344
end
336-
-- remove services that are not in use anymore
345+
346+
if not had_success then
347+
return false, 'all nacos services fetch failed'
348+
end
349+
350+
for key, nodes in pairs(nodes_cache) do
351+
local content = core.json.encode(nodes)
352+
nacos_dict:set(key, content)
353+
end
354+
337355
for key, _ in pairs(curr_service_in_use) do
338356
if not service_names[key] then
339357
nacos_dict:delete(key)
340358
end
341359
end
360+
342361
curr_service_in_use = service_names
362+
return true
363+
end
364+
365+
366+
local function fetch_full_registry(premature)
367+
if premature then
368+
return
369+
end
370+
371+
local infos = get_nacos_services()
372+
if #infos == 0 then
373+
return
374+
end
375+
376+
local host_list = local_conf.discovery.nacos.host
377+
local host_count = #host_list
378+
local start = math_random(host_count)
379+
380+
for i = 0, host_count - 1 do
381+
local idx = (start + i - 1) % host_count + 1
382+
local base_uri, username, password = get_base_uri_by_index(idx)
383+
384+
if not base_uri then
385+
log.warn('nacos host at index ', idx, ' is invalid, skip')
386+
else
387+
local ok, err = fetch_from_host(base_uri, username, password, infos)
388+
if ok then
389+
return
390+
end
391+
log.error('fetch_from_host: ', base_uri, ' err:', err)
392+
end
393+
end
394+
395+
log.error('failed to fetch nacos registry from all hosts')
343396
end
344397

345398

apisix/utils/log-util.lua

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ local expr = require("resty.expr.v1")
2020
local content_decode = require("apisix.utils.content-decode")
2121
local ngx = ngx
2222
local pairs = pairs
23+
local type = type
2324
local ngx_now = ngx.now
2425
local ngx_header = ngx.header
2526
local os_date = os.date
@@ -32,6 +33,7 @@ local is_http = ngx.config.subsystem == "http"
3233
local req_get_body_file = ngx.req.get_body_file
3334
local MAX_REQ_BODY = 524288 -- 512 KiB
3435
local MAX_RESP_BODY = 524288 -- 512 KiB
36+
local MAX_LOG_FORMAT_DEPTH = 5
3537
local io = io
3638

3739
local lru_log_format = core.lrucache.new({
@@ -69,22 +71,35 @@ local function get_request_body(max_bytes)
6971
end
7072

7173

72-
local function gen_log_format(format)
74+
local function do_gen_log_format(format, depth)
7375
local log_format = {}
7476
for k, var_name in pairs(format) do
75-
if var_name:byte(1, 1) == str_byte("$") then
77+
if type(var_name) == "table" then
78+
if depth >= MAX_LOG_FORMAT_DEPTH then
79+
core.log.warn("log_format nesting exceeds max depth ",
80+
MAX_LOG_FORMAT_DEPTH, ", truncating")
81+
log_format[k] = {false, {}}
82+
else
83+
local nested_format = do_gen_log_format(var_name, depth + 1)
84+
log_format[k] = {false, nested_format}
85+
end
86+
elseif type(var_name) == "string" and var_name:byte(1, 1) == str_byte("$") then
7687
log_format[k] = {true, var_name:sub(2)}
7788
else
7889
log_format[k] = {false, var_name}
7990
end
8091
end
92+
return log_format
93+
end
94+
95+
local function gen_log_format(format)
96+
local log_format = do_gen_log_format(format, 1)
8197
core.log.info("log_format: ", core.json.delay_encode(log_format))
8298
return log_format
8399
end
84100

85101

86-
local function get_custom_format_log(ctx, format, max_req_body_bytes)
87-
local log_format = lru_log_format(format or "", nil, gen_log_format, format)
102+
local function build_log_entry(ctx, log_format, max_req_body_bytes)
88103
local entry = core.table.new(0, core.table.nkeys(log_format))
89104
for k, var_attr in pairs(log_format) do
90105
if var_attr[1] then
@@ -100,10 +115,19 @@ local function get_custom_format_log(ctx, format, max_req_body_bytes)
100115
else
101116
entry[k] = ctx.var[var_attr[2]]
102117
end
118+
elseif type(var_attr[2]) == "table" then
119+
entry[k] = build_log_entry(ctx, var_attr[2], max_req_body_bytes)
103120
else
104121
entry[k] = var_attr[2]
105122
end
106123
end
124+
return entry
125+
end
126+
127+
128+
local function get_custom_format_log(ctx, format, max_req_body_bytes)
129+
local log_format = lru_log_format(format or "", nil, gen_log_format, format)
130+
local entry = build_log_entry(ctx, log_format, max_req_body_bytes)
107131

108132
local matched_route = ctx.matched_route and ctx.matched_route.value
109133
if matched_route then

ci/pod/docker-compose.common.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,3 +111,12 @@ services:
111111
restart: unless-stopped
112112
ports:
113113
- "127.0.0.1:4566:4566" # LocalStack Gateway
114+
115+
116+
## httpbin - HTTP Request & Response Service
117+
httpbin:
118+
image: kennethreitz/httpbin
119+
container_name: httpbin
120+
restart: unless-stopped
121+
ports:
122+
- "8280:80"

docker/compose/docker-compose-master.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,14 @@ services:
4747
networks:
4848
- apisix
4949

50+
httpbin:
51+
image: ghcr.io/mccutchen/go-httpbin
52+
restart: always
53+
ports:
54+
- "8280:8080/tcp"
55+
networks:
56+
- apisix
57+
5058
networks:
5159
apisix:
5260
driver: bridge

docs/en/latest/plugins/clickhouse-logger.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ The `clickhouse-logger` Plugin is used to push logs to [ClickHouse](https://clic
4444
| timeout | integer | False | 3 | [1,...] | Time to keep the connection alive for after sending a request. |
4545
| name | string | False | "clickhouse logger" | | Unique identifier for the logger. If you use Prometheus to monitor APISIX metrics, the name is exported in `apisix_batch_process_entries`. |
4646
| ssl_verify | boolean | False | true | [true,false] | When set to `true`, verifies SSL. |
47-
| log_format | object | False | | | Log format declared as key value pairs in JSON format. Values only support strings. [APISIX](../apisix-variable.md) or [Nginx](http://nginx.org/en/docs/varindex.html) variables can be used by prefixing the string with `$`. |
47+
| log_format | object | False | | | Log format declared as key-value pairs in JSON. Values support strings and nested objects (up to five levels deep; deeper fields are truncated). Within strings, [APISIX](../apisix-variable.md) or [NGINX](http://nginx.org/en/docs/varindex.html) variables can be referenced by prefixing with `$`. |
4848
| include_req_body | boolean | False | false | [false, true] | When set to `true` includes the request body in the log. If the request body is too big to be kept in the memory, it can't be logged due to Nginx's limitations. |
4949
| include_req_body_expr | array | False | | | Filter for when the `include_req_body` attribute is set to `true`. Request body is only logged when the expression set here evaluates to `true`. See [lua-resty-expr](https://github.com/api7/lua-resty-expr) for more. |
5050
| include_resp_body | boolean | False | false | [false, true] | When set to `true` includes the response body in the log. |
@@ -103,7 +103,7 @@ You can also set the format of the logs by configuring the Plugin metadata. The
103103

104104
| Name | Type | Required | Default | Description |
105105
| ---------- | ------ | -------- | ----------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
106-
| log_format | object | False | | Log format declared as key value pairs in JSON format. Values only support strings. [APISIX](../apisix-variable.md) or [Nginx](http://nginx.org/en/docs/varindex.html) variables can be used by prefixing the string with `$`. |
106+
| log_format | object | False | | Log format declared as key-value pairs in JSON. Values support strings and nested objects (up to five levels deep; deeper fields are truncated). Within strings, [APISIX](../apisix-variable.md) or [NGINX](http://nginx.org/en/docs/varindex.html) variables can be referenced by prefixing with `$`. |
107107
| max_pending_entries | integer | False | | Maximum number of pending entries that can be buffered in batch processor before it starts dropping them. |
108108

109109
:::info IMPORTANT

docs/en/latest/plugins/elasticsearch-logger.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ The `elasticsearch-logger` Plugin pushes request and response logs in batches to
4242
| endpoint_addrs | array[string] | True | | Elasticsearch API endpoint addresses. If multiple endpoints are configured, they will be written randomly. |
4343
| field | object | True | | Elasticsearch `field` configuration. |
4444
| field.index | string | True | | Elasticsearch [_index field](https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-index-field.html#mapping-index-field). |
45-
| log_format | object | False | | Custom log format in key-value pairs in JSON format. Support [APISIX](../apisix-variable.md) or [NGINX variables](http://nginx.org/en/docs/varindex.html) in values. |
45+
| log_format | object | False | | Custom log format as key-value pairs in JSON. Values support strings and nested objects (up to five levels deep; deeper fields are truncated). Within strings, [APISIX](../apisix-variable.md) or [NGINX variables](http://nginx.org/en/docs/varindex.html) can be referenced by prefixing with `$`. |
4646
| auth | array | False | | Elasticsearch [authentication](https://www.elastic.co/guide/en/elasticsearch/reference/current/setting-up-authentication.html) configuration. |
4747
| auth.username | string | True | | Elasticsearch [authentication](https://www.elastic.co/guide/en/elasticsearch/reference/current/setting-up-authentication.html) username. |
4848
| auth.password | string | True | | Elasticsearch [authentication](https://www.elastic.co/guide/en/elasticsearch/reference/current/setting-up-authentication.html) password. |
@@ -61,7 +61,7 @@ This Plugin supports using batch processors to aggregate and process entries (lo
6161

6262
| Name | Type | Required | Default | Description |
6363
|------|------|----------|---------|-------------|
64-
| log_format | object | False | | Custom log format in key-value pairs in JSON format. Support [APISIX variables](../apisix-variable.md) and [NGINX variables](http://nginx.org/en/docs/varindex.html) in values. |
64+
| log_format | object | False | | Log format declared as key-value pairs in JSON. Values support strings and nested objects (up to five levels deep; deeper fields are truncated). Within strings, [APISIX](../apisix-variable.md) or [NGINX](http://nginx.org/en/docs/varindex.html) variables can be referenced by prefixing with `$`. |
6565
| max_pending_entries | integer | False | | Maximum number of pending entries that can be buffered in batch processor before it starts dropping them. |
6666

6767
## Examples

0 commit comments

Comments
 (0)