Skip to content

Commit

Permalink
feat: support file-logger plugin of response body record (apache#8414)
Browse files Browse the repository at this point in the history
  • Loading branch information
pixeldin authored Dec 9, 2022
1 parent 4694685 commit c5fc10d
Show file tree
Hide file tree
Showing 4 changed files with 198 additions and 0 deletions.
11 changes: 11 additions & 0 deletions apisix/plugins/file-logger.lua
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,14 @@ local schema = {
path = {
type = "string"
},
include_resp_body = {type = "boolean", default = false},
include_resp_body_expr = {
type = "array",
minItems = 1,
items = {
type = "array"
}
}
},
required = {"path"}
}
Expand Down Expand Up @@ -136,6 +144,9 @@ local function write_file_data(conf, log_message)
end
end

function _M.body_filter(conf, ctx)
log_util.collect_body(conf, ctx)
end

function _M.log(conf, ctx)
local metadata = plugin.plugin_metadata(plugin_name)
Expand Down
2 changes: 2 additions & 0 deletions docs/en/latest/plugins/file-logger.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ The `file-logger` Plugin is used to push log streams to a specific location.
| Name | Type | Required | Description |
| ---- | ------ | -------- | ------------- |
| path | string | True | Log file path. |
| 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`. |

## Metadata

Expand Down
2 changes: 2 additions & 0 deletions docs/zh/latest/plugins/file-logger.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ description: API 网关 Apache APISIX file-logger 插件可用于将日志数据
| 名称 | 类型 | 必选项 | 描述 |
| ---------------- | ------- | ------ | ------------------------------------------------ |
| path | string || 自定义输出文件路径。例如:`logs/file.log`|
| 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` 时记录响应。 |

## 插件元数据设置

Expand Down
183 changes: 183 additions & 0 deletions t/plugin/file-logger2.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
use t::APISIX 'no_plan';

no_long_string();
no_root_location();

add_block_preprocessor(sub {
my ($block) = @_;

if (! $block->request) {
$block->set_value("request", "GET /t");
if (!$block->response_body) {
$block->set_value("response_body", "passed\n");
}
}
});


run_tests;

__DATA__
=== TEST 1: add plugin with 'include_resp_body' setting
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
-- delete plugin metadata for response body format
t('/apisix/admin/plugin_metadata/file-logger', ngx.HTTP_DELETE)
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"plugins": {
"file-logger": {
"path": "file-with-resp-body.log",
"include_resp_body": true
}
},
"upstream": {
"nodes": {
"127.0.0.1:1982": 1
},
"type": "roundrobin"
},
"uri": "/hello"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
=== TEST 2: verify plugin for file-logger with response
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local t = require("lib.test_admin").test
local code = t("/hello", ngx.HTTP_GET)
local fd, err = io.open("file-with-resp-body.log", 'r')
local msg
if not fd then
core.log.error("failed to open file: file-resp-check.log, error info: ", err)
return
end
-- note only for first line
msg = fd:read()
local new_msg = core.json.decode(msg)
ngx.status = code
if new_msg.response ~= nil and new_msg.response.body == "hello world\n" then
ngx.status = code
ngx.say('contain with target')
end
}
}
--- response_body
contain with target
=== TEST 3: check file-logger 'include_resp_body' with 'expr'
--- 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-resp-expr-body.log",
"include_resp_body": true,
"include_resp_body_expr": [
[
"arg_foo",
"==",
"bar"
]
]
}
},
"upstream": {
"nodes": {
"127.0.0.1:1982": 1
},
"type": "roundrobin"
},
"uri": "/hello"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
=== TEST 4: verify file-logger resp with expression of concern
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local t = require("lib.test_admin").test
local code = t("/hello?foo=bar", ngx.HTTP_GET)
local fd, err = io.open("file-with-resp-expr-body.log", 'r')
local msg
if not fd then
core.log.error("failed to open file: file-with-resp-expr-body.log, error info: ", err)
return
end
-- note only for first line
msg = fd:read()
local new_msg = core.json.decode(msg)
ngx.status = code
if new_msg.response ~= nil and new_msg.response.body == "hello world\n" then
ngx.status = code
ngx.say('contain target body hits with expr')
end
--- a new request is logged
t("/hello?name=pix", ngx.HTTP_GET)
msg = fd:read("*l")
local new_msg = core.json.decode(msg)
if new_msg.response.body == nil then
ngx.say('skip unconcern body')
end
}
}
--- response_body
contain target body hits with expr
skip unconcern body

0 comments on commit c5fc10d

Please sign in to comment.