Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: file-logger add vars #9712

Merged
merged 19 commits into from
Jul 13, 2023
17 changes: 17 additions & 0 deletions apisix/plugins/file-logger.lua
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
--
local log_util = require("apisix.utils.log-util")
local core = require("apisix.core")
local expr = require("resty.expr.v1")
local ngx = ngx
local io_open = io.open
local is_apisix_or, process = pcall(require, "resty.apisix.process")
Expand All @@ -38,6 +39,13 @@ local schema = {
items = {
type = "array"
}
},
match = {
type = "array",
maxItems = 20,
items = {
type = "array",
},
}
},
required = {"path"}
Expand Down Expand Up @@ -65,6 +73,12 @@ function _M.check_schema(conf, schema_type)
if schema_type == core.schema.TYPE_METADATA then
return core.schema.check(metadata_schema, conf)
end
if conf.match then
local ok, err = expr.new(conf.match)
if not ok then
return nil, "failed to validate the 'match' expression: " .. err
end
end
return core.schema.check(schema, conf)
end

Expand Down Expand Up @@ -150,6 +164,9 @@ end

function _M.log(conf, ctx)
local entry = log_util.get_log_entry(plugin_name, conf, ctx)
if entry == nil then
return
end
write_file_data(conf, entry)
end

Expand Down
20 changes: 20 additions & 0 deletions apisix/utils/log-util.lua
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,27 @@ function _M.inject_get_full_log(f)
end


local function is_match(match, ctx)
local match_result
for _, m in pairs(match) do
local expr, _ = expr.new(m)
match_result = expr:eval(ctx.var)
if match_result then
break
end
end

return match_result
end


function _M.get_log_entry(plugin_name, conf, ctx)
-- If the "match" configuration is set and the matching conditions are not met,
-- then do not log the message.
if conf.match and not is_match(conf.match, ctx) then
return
end

local metadata = plugin.plugin_metadata(plugin_name)
core.log.info("metadata: ", core.json.delay_encode(metadata))

Expand Down
41 changes: 41 additions & 0 deletions docs/en/latest/plugins/file-logger.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ The `file-logger` Plugin is used to push log streams to a specific location.
| 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 `$`. |
| include_resp_body | boolean | False | When set to `true` includes the response body in the log file. |
| include_resp_body_expr | array | False | When the `include_resp_body` attribute is set to `true`, use this to filter based on [lua-resty-expr](https://github.com/api7/lua-resty-expr). If present, only logs the response into file if the expression evaluates to `true`. |
| match | array[] | False | Logs will be recorded when the rule matching is successful if the option is set. See [lua-resty-expr](https://github.com/api7/lua-resty-expr#operator-list) for a list of available expressions. |

## Metadata

Expand Down Expand Up @@ -110,6 +111,46 @@ curl -i http://127.0.0.1:9080/hello

You will be able to find the `file.log` file in the configured `logs` directory.

## Filter logs

```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
"plugins": {
"file-logger": {
"path": "logs/file.log",
"match": {
{
{ "arg_name","==","jack" }
}
}
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:9001": 1
}
},
"uri": "/hello"
}'
```

Test:

```shell
curl -i http://127.0.0.1:9080/hello?name=jack
```

Log records can be seen in `logs/file.log`.

```shell
curl -i http://127.0.0.1:9080/hello?name=rose
```

Log records cannot be seen in `logs/file.log`.

## Disable Plugin

To disable the `file-logger` Plugin, you can delete the corresponding JSON configuration from the Plugin configuration. APISIX will automatically reload and you do not have to restart for this to take effect.
Expand Down
41 changes: 41 additions & 0 deletions docs/zh/latest/plugins/file-logger.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ description: API 网关 Apache APISIX file-logger 插件可用于将日志数据
| log_format | object | 否 | 以 JSON 格式的键值对来声明日志格式。对于值部分,仅支持字符串。如果是以 `$` 开头,则表明是要获取 [APISIX 变量](../apisix-variable.md) 或 [NGINX 内置变量](http://nginx.org/en/docs/varindex.html)。 |
| include_resp_body | boolean | 否 | 当设置为 `true` 时,生成的文件包含响应体。 |
| include_resp_body_expr | array | 否 | 当 `include_resp_body` 属性设置为 `true` 时,使用该属性并基于 [lua-resty-expr](https://github.com/api7/lua-resty-expr) 进行过滤。如果存在,则仅在表达式计算结果为 `true` 时记录响应。 |
| match | array[] | 否 | 当设置了这个选项后,只有匹配规则的日志才会被记录。`match` 是一个表达式列表,具体请参考 [lua-resty-expr](https://github.com/api7/lua-resty-expr#operator-list)。 |

## 插件元数据设置

Expand Down Expand Up @@ -124,6 +125,46 @@ hello, world

访问成功后,你可以在对应的 `logs` 目录下找到 `file.log` 文件。

## 过滤日志

```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
"plugins": {
"file-logger": {
"path": "logs/file.log",
"match": {
{
{ "arg_name","==","jack" }
}
}
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:9001": 1
}
},
"uri": "/hello"
}'
```

测试:

```shell
curl -i http://127.0.0.1:9080/hello?name=jack
```

在 `logs/file.log` 中可以看到日志记录

```shell
curl -i http://127.0.0.1:9080/hello?name=rose
```

在 `logs/file.log` 中看不到日志记录

## 禁用插件

当你需要禁用该插件时,可以通过如下命令删除相应的 JSON 配置,APISIX 将会自动重新加载相关配置,无需重启服务:
Expand Down
92 changes: 92 additions & 0 deletions t/plugin/file-logger2.t
Original file line number Diff line number Diff line change
Expand Up @@ -274,3 +274,95 @@ passed
}
--- response_body
write file log success



=== TEST 8: Add new configuration with match
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"plugins": {
"file-logger": {
"path": "file-with-match.log",
"match": [
[
[ "arg_name","==","jack" ]
]
],
"log_format": {
"request": "$request"
}
}
},
"upstream": {
"nodes": {
"127.0.0.1:1982": 1
},
"type": "roundrobin"
},
"uri": "/hello"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- response_body
passed



=== TEST 9: Request match
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local t = require("lib.test_admin").test
local code = t("/hello?name=jack", ngx.HTTP_GET)
local fd, err = io.open("file-with-match.log", 'r')
if not fd then
core.log.error("failed to open file: file-with-match.log, error info: ", err)
return
end
local msg = fd:read()

local new_msg = core.json.decode(msg)
if new_msg.request == 'GET /hello?name=jack HTTP/1.1'
and new_msg.route_id == '1'
then
msg = "write file log success"
ngx.status = code
ngx.say(msg)
end

os.remove("file-with-match.log")
}
}
--- response_body
write file log success



=== TEST 10: Request not match
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local t = require("lib.test_admin").test
local code = t("/hello?name=tony", ngx.HTTP_GET)
local fd, err = io.open("file-with-match.log", 'r')
if not fd then
local msg = "not write file log"
ngx.say(msg)
return
end
}
}
--- response_body
not write file log
Loading