This is an automated email from the ASF dual-hosted git repository.

bzp2010 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix-website.git


The following commit(s) were added to refs/heads/master by this push:
     new 0243b19  docs: add file-logger plugin blog (#882)
0243b19 is described below

commit 0243b1932fc3c970d5c9a0bc66cdfb697633a64c
Author: yilinzeng <[email protected]>
AuthorDate: Wed Feb 16 20:25:11 2022 +0800

    docs: add file-logger plugin blog (#882)
---
 website/blog/2022/02/16/file-logger.md             | 363 +++++++++++++++++++++
 .../2022/02/16/file-logger.md                      | 363 +++++++++++++++++++++
 2 files changed, 726 insertions(+)

diff --git a/website/blog/2022/02/16/file-logger.md 
b/website/blog/2022/02/16/file-logger.md
new file mode 100644
index 0000000..6562c1e
--- /dev/null
+++ b/website/blog/2022/02/16/file-logger.md
@@ -0,0 +1,363 @@
+---
+title: "How did a Beginner Build an Apache APISIX Plugin from 0 to 1"
+authors:
+  - name: "Qi Guo"
+    title: "Author"
+    url: "https://github.com/guoqqqi";
+    image_url: "https://avatars.githubusercontent.com/u/72343596?v=4";
+  - name: "Yilin Zeng"
+    title: "Technical Writer"
+    url: "https://github.com/yzeng25";
+    image_url: "https://avatars.githubusercontent.com/u/36651058?v=4";
+keywords: 
+- Apache APISIX
+- Logging
+- Ecosystem
+- Developer
+- Guide
+description: This article documents the process of developing the 
`file-logger` plugin by a front-end engineer with no back-end experience.
+tags: [Technology,Logging]
+---
+
+> This article documents the process of developing the `file-logger` plugin by 
a front-end engineer with no back-end experience.
+
+<!--truncate-->
+
+Over the past few months, community users have added many plugins to Apache 
APISIX, enriching the Apache APISIX ecosystem. From the user's point of view, 
the emergence of more diverse plugins is certainly a good thing, as they 
fulfill more of the user's expectations for a gateway that is "one-stop" and 
"multi-functional" processor on top of perfecting the high performance and low 
latency of Apache APISIX.
+
+None of the articles on the Apache APISIX blog seem to go into detail about 
the process of developing plugins. So let's take a look at the process from the 
perspective of a plugin developer and see how a plugin is born!
+
+This article documents the process of developing the `file-logger` plugin by 
**a front-end engineer with no back-end experience**. Before digging into the 
details of the implementation process, we will briefly introduce the 
functionality of `file-logger`.
+
+## Introduction of file-logger plugin
+
+`file-logger` supports generating custom log formats using Apache APISIX 
plugin metadata. Users can append request and response data in JSON format to 
log files via the `file-logger` plugin, or push the log data stream to a 
specified location.
+
+Imagine this: when monitoring the access log of a route, we not only care 
about the value of certain request and response data, but also want to write 
the log data to a specified file. This is where the `file-logger` plugin can be 
used to help achieve these goals.
+
+![how it 
works](https://static.apiseven.com/202108/1644996258131-a0e32942-dcc5-4129-873f-0a7551532e77.png)
+
+We can use `file-logger` to write log data to a specific log file to simplify 
the process of monitoring and debugging.
+
+## How to implement a plugin?
+
+After introducing the features of file-logger, you will have a better 
understanding of this plugin. The following is a detailed explanation of how I, 
a front-end developer with no server-side experience, develop the plugin for 
Apache APISIX and add the corresponding tests for it.
+
+### Confirm the name and priority of the plugin
+
+Open the [Apache APISIX Plugin Development 
Guide](https://apisix.apache.org/docs/apisix/plugin-develop/#name-priority-and-the-others)
 and in order of priority you need to determine the following two things:
+
+1. Determine the plugin category.
+2. prioritize the plugins and update the `conf/config-default.yaml` file.
+
+Since this development of `file-logger` is a logging type plugin, I refer to 
the name and ordering of the existing logging plugins for Apache APISIX and 
place `file-logger` here.
+
+![file-logger's 
position](https://static.apiseven.com/202108/1644996436166-58305d35-3798-4df2-b8df-1874f3e0cb01.png)
+
+After consulting with other plugin authors and enthusiastic members of the 
community, the name `file-logger` and priority `399` of the plugin were finally 
confirmed.
+
+> Note that the priority of the plugin is related to the order of execution; 
the higher the value of the priority, the more forward the execution. And the 
ordering of plugin names is not related to the order of execution.
+
+### Create a minimum executable plugin file
+
+After confirming the plugin name and priority, you can create our plugin code 
file in `apisix/plugins/` directory . There are two points to note here:
+
+- If the plugin code file is created directly in the `apisix/plugins/` 
directory, there is no need to change the `Makefile` file.
+- If your plugin has its own code directory, you need to update the `Makefile` 
file, please refer to the [Apache APISIX Plugin Development 
Guide](https://apisix.apache.org/docs/apisix/plugin-develop/#name-priority-and-the-others)
 for detailed steps.
+
+1. Here we create the `file-logger.lua` file in the `apisix/plugins/ 
directory`.
+2. Then we will complete an initialized version based on the `example-plugin`.
+
+```lua
+-- Introduce the module we need in the header
+local core         =   require("apisix.core")
+local plugin       =   require("apisix.plugin")
+local ngx          =   ngx
+
+-- Declare the plugin's name
+local plugin_name = "file-logger"
+
+-- Define the plugin schema format
+local schema = {
+    type = "object",
+    properties = {
+        path = {
+            type = "string"
+        },
+    },
+    required = {"path"}
+}
+
+-- Plugin metadata schema
+local metadata_schema = {
+    type = "object",
+    properties = {
+        log_format = log_util.metadata_schema_log_format
+    }
+}
+
+
+local _M = {
+    version = 0.1,
+    priority = 399,
+    name = plugin_name,
+    schema = schema,
+    metadata_schema = metadata_schema
+}
+
+-- Check if the plugin configuration is correct
+function _M.check_schema(conf, schema_type)
+    if schema_type == core.schema.TYPE_METADATA then
+        return core.schema.check(metadata_schema, conf)
+    end
+    return core.schema.check(schema, conf)
+end
+
+-- Log phase
+function _M.log(conf, ctx)
+    core.log.warn("conf: ", core.json.encode(conf))
+    core.log.warn("ctx: ", core.json.encode(ctx, true))
+end
+
+
+return _M
+```
+
+Once the minimal available plugin file is ready, the plugin's configuration 
data and request-related data can be output to the `error.log` file via 
`core.log.warn(core.json.encode(conf))` and `core.log.warn("ctx: ", 
core.json.encode(ctx, true))`.
+
+### Enable and test the plugin
+
+The following are a couple of steps for testing. In order to test whether the 
plugin can successfully print the plugin data and request-related data 
information we configured for it to the error log file, we need to enable the 
plugin and create a test route.
+
+1. Prepare a test upstream locally (the test upstream used in this article is 
`127.0.0.1:3030/api/hello`, which I created locally).
+2. Create a route via `curl` command and enable our new plugin.
+
+   ```shell
+    curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: 
edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
+    {
+    "plugins": {
+        "file-logger": {
+        "path": "logs/file.log"
+        }
+    },
+    "upstream": {
+        "type": "roundrobin",
+        "nodes": {
+        "127.0.0.1:3030": 1
+        }
+    },
+    "uri": "/api/hello"
+    }'
+   ```
+
+   You will then see a status code `200`, indicating that the route was 
successfully created.
+3. Run the `curl` command to send a request to the route to test whether the 
`file-logger` plugin has been started.
+
+   ```shell
+   curl -i http://127.0.0.1:9080/api/hello
+   HTTP/1.1 200 OK
+   ...
+   hello, world
+   ```
+
+4. In the `logs/error.log` file there will be a record:
+
+   ![record in 
logs/error.log](https://static.apiseven.com/202108/1644996952020-7a79d5df-e679-42f1-94f3-40a913db790c.png)
+
+   As you can see, the `path: logs/file.log` that we configured for the plugin 
in the conf parameter has been successfully saved. At this point we have 
successfully created a minimally usable plugin that prints the `conf` and `ctx` 
parameters in the logging phase.
+
+   After that, we can write the core functionality for the `file-logger.lua` 
plugin directly in its code file. Here we can directly run the `apisix reload` 
command to reload the latest plugin code without restarting Apache APISIX.
+
+### Write core function for the file-logger plugin
+
+The main function of the file-logger plugin is to write log data. After asking 
other people from the community and checking the information, I learned about 
Lua's IO library, and confirmed that the logic of the plugin's function is 
roughly the following steps.
+
+1. After each accepted request, output the log data to the `path` configured 
by the plugin.
+   1. First, get the value of `path` in `file-logger` through `conf` in the 
logging phase.
+   2. Then, the Lua IO library is used to create, open, write, refresh the 
cache, and close the file.
+2. Handle errors such as open file failure, create file failure, etc.
+
+   ```lua
+    local function write_file_data(conf, log_message)
+        local msg, err = core.json.encode(log_message)
+        if err then
+            return core.log.error("message json serialization failed, error 
info : ", err)
+        end
+
+        local file, err = io_open(conf.path, 'a+')
+
+        if not file then
+            core.log.error("failed to open file: ", conf.path, ", error info: 
", err)
+        else
+            local ok, err = file:write(msg, '\n')
+            if not ok then
+                core.log.error("failed to write file: ", conf.path, ", error 
info: ", err)
+            else
+                file:flush()
+            end
+            file:close()
+        end
+    end
+   ```
+
+3. Referring to the source code of `http-logger` plugin, I finished the method 
of passing the log data to the write log data and some judgment and processing 
of the metadata.
+
+   ```lua
+    function _M.log(conf, ctx)
+        local metadata = plugin.plugin_metadata(plugin_name)
+        local entry
+
+        if metadata and metadata.value.log_format
+            and core.table.nkeys(metadata.value.log_format) > 0
+        then
+            entry = log_util.get_custom_format_log(ctx, 
metadata.value.log_format)
+        else
+            entry = log_util.get_full_log(ngx, conf)
+        end
+
+        write_file_data(conf, entry)
+    end
+   ```
+
+## Validate and add tests
+
+### Validate the log records
+
+Since the `file-logger` plugin was enabled when the test route was created and 
the path was configured as `logs/file.log`, we can simply send a request to the 
test route to verify the results of the log collection at this point.
+
+```shell
+curl -i http://127.0.0.1:9080/api/hello
+```
+
+In the corresponding logs/file.log we can see that each record is saved in 
JSON format. After formatting one of the data, it looks like this.
+
+```json
+{
+    "server":{
+        "hostname":"....",
+        "version":"2.11.0"
+    },
+    "client_ip":"127.0.0.1",
+    "upstream":"127.0.0.1:3030",
+    "route_id":"1",
+    "start_time":1641285122961,
+    "latency":13.999938964844,
+    "response":{
+        "status":200,
+        "size":252,
+        "headers":{
+            "server":"APISIX\/2.11.0",
+            "content-type":"application\/json; charset=utf-8",
+            "date":"Tue, 04 Jan 2022 08:32:02 GMT",
+            "vary":"Accept-Encoding",
+            "content-length":"19",
+            "connection":"close",
+            "etag":"\"13-5j0ZZR0tI549fSRsYxl8c9vAU78\""
+        }
+    },
+    "service_id":"",
+    "request":{
+        "querystring":{
+
+        },
+        "size":87,
+        "method":"GET",
+        "headers":{
+            "host":"127.0.0.1:9080",
+            "accept":"*\/*",
+            "user-agent":"curl\/7.77.0"
+        },
+        "url":"http:\/\/127.0.0.1:9080\/api\/hello",
+        "uri":"\/api\/hello"
+    }
+}
+```
+
+This concludes the verification of the collection of log records . The 
verification results indicate that the plugin was successfully launched and 
returned the appropriate data.
+
+### Add more tests for the plugin
+
+For the `add_block_preprocessor` part of the code, I was confused when I first 
started writing it because I had no previous experience with Perl. After 
researching, I realized the correct way to use it: if we don't write `request` 
assertions and `no_error_log` assertions in the data section, then the default 
assertion is as follows.
+
+```lua
+--- request
+GET /t
+--- no_error_log
+[error]
+```
+
+After taking some other logging test files into account, I created the file 
`file-logger.t` in the `t/plugin/` directory.
+
+Each test file is divided by `__DATA__` into a preamble section and a data 
section. Since there is no clear classification of test-related documents on 
the official website, you can refer to the related materials at the end of the 
article for more details. Here is one of the test cases that I have completed 
after referring to the relevant materials.
+
+```perl
+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->no_error_log && ! $block->error_log) {
+        $block->set_value("no_error_log", "[error]");
+    }
+});
+
+
+run_tests;
+
+__DATA__
+
+=== TEST 1: sanity
+--- config
+    location /t {
+        content_by_lua_block {
+            local configs = {
+                -- full configuration
+                {
+                    path = "file.log"
+                },
+                -- property "path" is required
+                {
+                    path = nil
+                }
+            }
+
+            local plugin = require("apisix.plugins.file-logger")
+
+            for i = 1, #configs do
+                ok, err = plugin.check_schema(configs[i])
+                if err then
+                    ngx.say(err)
+                else
+                    ngx.say("done")
+                end
+            end
+        }
+    }
+--- response_body_like
+done
+property "path" is required
+```
+
+This concludes the plugin addition test session.
+
+## Summary
+
+The above is the whole process of implementing an Apache APISIX plugin from 0 
as a newbie in the backend. I did encounter a lot of pitfalls in the process of 
developing the plugin, but luckily there are many enthusiastic brothers in the 
Apache APISIX community to help me solve the problems, which made the 
development and testing of the file-logger plugin relatively smooth throughout. 
If you are interested in this plugin, or want to see the details of the plugin, 
you can refer to the [off [...]
+
+Apache APISIX is also currently working on other plugins to support more 
integration services, so if you're interested, feel free to start a discussion 
in the [GitHub Discussion](https://github.com/apache/apisix/discussions), or 
via the [mailing list](https://apisix.apache.org/docs/general/subscribe-guide).
+
+## References
+
+- [Apache APISIX Plugin Development 
Guide](https://apisix.apache.org/docs/apisix/plugin-develop/)
+- [Lua - File I/O Usage 
Guide](https://www.tutorialspoint.com/lua/lua_file_io.htm)
+- [How to run Apache APISIX test 
cases](https://apisix.apache.org/docs/apisix/how-to-build/#step-4-run-test-cases)
+- [How to Write Test 
Cases](https://apisix.apache.org/docs/apisix/plugin-develop/#write-test-case)
+- [Introduction to the Apache APISIX testing 
framework](https://apisix.apache.org/docs/apisix/internal/testing-framework/)
+- [Introduction to some APIs related to 
test-nginx](https://metacpan.org/pod/Test%3A%3ANginx%3A%3ASocket)
diff --git 
a/website/i18n/zh/docusaurus-plugin-content-blog/2022/02/16/file-logger.md 
b/website/i18n/zh/docusaurus-plugin-content-blog/2022/02/16/file-logger.md
new file mode 100644
index 0000000..c701576
--- /dev/null
+++ b/website/i18n/zh/docusaurus-plugin-content-blog/2022/02/16/file-logger.md
@@ -0,0 +1,363 @@
+---
+title: "后端新手如何从 0 到 1 打造一款 Apache APISIX 插件"
+authors:
+  - name: "郭奇"
+    title: "Author"
+    url: "https://github.com/guoqqqi";
+    image_url: "https://avatars.githubusercontent.com/u/72343596?v=4";
+  - name: "曾奕霖"
+    title: "Technical Writer"
+    url: "https://github.com/yzeng25";
+    image_url: "https://avatars.githubusercontent.com/u/36651058?v=4";
+keywords: 
+- Apache APISIX
+- Logging
+- Ecosystem
+- Developer
+- Guide
+description: 本篇文章记录了一个没有后端经验的前端工程师开发 `file-logger` 插件的过程。
+tags: [Technology,Logging]
+---
+
+> 本篇文章记录了一个没有后端经验的前端工程师开发 `file-logger` 插件的过程。
+
+<!--truncate-->
+
+在过去的几个月,社区用户为 Apache APISIX 添加了许多插件,丰富了 Apache APISIX 
的生态。从使用者的角度而言,更多样化的插件出现无疑是一件好事,它们在完善 Apache APISIX 
高性能和低延迟的基础之上,满足了使用者对于网关的更多期望,即“一站式”和“多功能”。
+
+社区的贡献者们是如何为 Apache APISIX 开发插件的呢?Apache APISIX 
博客上的文章似乎都没有详细讲述过开发插件的流程。那么这次我们换一个视角,从插件开发者的角度出发,一起来看看一款插件诞生的全过程吧!
+
+本篇文章记录了一个**没有后端经验的前端工程师**开发 `file-logger` 插件的过程。在详细说明实现过程之前,先向大家简单介绍下 
`file-logger` 的功能。
+
+## 功能介绍
+
+`file-logger` 支持使用 Apache APISIX 插件元数据生成自定义的日志格式,用户可以通过 `file-logger` 插件将 JSON 
格式的请求和响应数据附加到日志文件中,也可以将 Log 数据流推送到指定位置。
+
+试想,在监控某一个路由的访问日志时,很多时候我们关注的不仅是某些请求和响应数据的值,还希望将日志数据单独写入到指定的文件中。这时就可以使用 
`file-logger` 插件来帮忙实现这些需求。
+
+![功能介绍](https://static.apiseven.com/202108/1644996258131-a0e32942-dcc5-4129-873f-0a7551532e77.png)
+
+具体实现过程中我们可以通过 `file-logger` 将日志数据单独写入指定的日志文件,简化监控和调试的过程。
+
+## 开发实现过程
+
+介绍完 `file-logger` 的功能之后,大家也算对这个插件有了更多的认识。下面为大家详细讲解一下,**没有服务端经验**的我是如何从 0 开始为 
Apache APISIX 完成该插件并添加相应测试的。
+
+### 确定插件名称及优先级
+
+打开 [Apache APISIX 
插件开发指南](https://apisix.apache.org/zh/docs/apisix/plugin-develop/#%E6%8F%92%E4%BB%B6%E5%91%BD%E5%90%8D%EF%BC%8C%E4%BC%98%E5%85%88%E7%BA%A7%E5%92%8C%E5%85%B6%E4%BB%96),按照先后顺序需要确定以下几项:
+
+1. 确定插件分类。
+2. 确定插件优先级,并更新 `conf/config-default.yaml` 文件。
+
+因为此次开发的 `file-logger` 属于日志类型的插件,所以我参考了 Apache APISIX 已有的日志插件的名称和排序,将 
`file-logger` 放到了这里:
+
+![确认 file-logger 
插件名称和优先级](https://static.apiseven.com/202108/1644996436166-58305d35-3798-4df2-b8df-1874f3e0cb01.png)
+
+咨询了其他插件的作者和社区的热心成员之后,最终确认了该插件的名称 `file-logger` 和优先级 `399`。
+
+> 需要注意的是,插件的优先级与执行顺序有关,优先级的值越大,执行越靠前。而插件名称的排序与执行顺序无关。
+
+### 创建最小可执行插件文件
+
+确认好插件名称和优先级后,便可在 `apisix/plugins/` 目录下创建我们的插件代码文件,这里有两点需要注意:
+
+- 如果是直接在 `apisix/plugins/` 目录下直接创建插件代码文件,就无需更改 `Makefile` 文件。
+- 如果你的插件有新建自己的代码目录,那么就需要更新 `Makefile 文件`,详细步骤可参考 [Apache APISIX 
插件开发指南](https://apisix.apache.org/zh/docs/apisix/plugin-develop/#%E6%8F%92%E4%BB%B6%E5%91%BD%E5%90%8D%EF%BC%8C%E4%BC%98%E5%85%88%E7%BA%A7%E5%92%8C%E5%85%B6%E4%BB%96)。
+  
+1. 下面我们在 `apisix/plugins/` 目录下创建 `file-logger.lua` 文件。
+2. 然后根据官方给出的 `example-plugin` 的例子做参考,来完成一个初始化版本。
+
+```lua
+-- 在头部引入我们所需要的模块
+local core         =   require("apisix.core")
+local plugin       =   require("apisix.plugin")
+local ngx          =   ngx
+
+-- 声明插件名称
+local plugin_name = "file-logger"
+
+-- 定义插件 schema 格式
+local schema = {
+    type = "object",
+    properties = {
+        path = {
+            type = "string"
+        },
+    },
+    required = {"path"}
+}
+
+-- 插件元数据 schema
+local metadata_schema = {
+    type = "object",
+    properties = {
+        log_format = log_util.metadata_schema_log_format
+    }
+}
+
+
+local _M = {
+    version = 0.1,
+    priority = 399,
+    name = plugin_name,
+    schema = schema,
+    metadata_schema = metadata_schema
+}
+
+-- 检查插件配置是否正确
+function _M.check_schema(conf, schema_type)
+    if schema_type == core.schema.TYPE_METADATA then
+        return core.schema.check(metadata_schema, conf)
+    end
+    return core.schema.check(schema, conf)
+end
+
+-- 日志阶段
+function _M.log(conf, ctx)
+    core.log.warn("conf: ", core.json.encode(conf))
+    core.log.warn("ctx: ", core.json.encode(ctx, true))
+end
+
+
+return _M
+```
+
+通过 `example-plugin` 的例子完成了一个最小的可用插件文件后,便可通过 
`core.log.warn(core.json.encode(conf))` 和 `core.log.warn("ctx: ", 
core.json.encode(ctx, true))` 将插件的配置数据和请求相关的数据信息输出到 `error.log` 文件中去。
+
+### 启用插件并测试
+
+下面通过创建一条测试路由,来测试插件是否能成功将我们为其配置的插件数据和请求相关的数据信息,打印到错误日志文件中去。
+
+1. 在本地准备一个测试上游(本文中使用的测试上游是我在本地创建的 `127.0.0.1:3030/api/hello`)。
+2. 通过 `curl` 命令创建一条路由并启用我们新增的插件。
+
+   ```shell
+    curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: 
edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
+    {
+    "plugins": {
+        "file-logger": {
+        "path": "logs/file.log"
+        }
+    },
+    "upstream": {
+        "type": "roundrobin",
+        "nodes": {
+        "127.0.0.1:3030": 1
+        }
+    },
+    "uri": "/api/hello"
+    }'
+   ```
+
+   接着就会看到一个 `200` 的状态码,表明已成功创建了路由。
+3. 运行 `curl` 命令向该路由发送请求,测试 `file-logger` 插件是否已经启动。
+
+   ```shell
+   curl -i http://127.0.0.1:9080/api/hello
+   HTTP/1.1 200 OK
+   ...
+   hello, world
+   ```
+
+4. 在 `logs/error.log` 文件中会有一条这样的记录:
+
+   ![logs/error.log 
记录](https://static.apiseven.com/202108/1644996952020-7a79d5df-e679-42f1-94f3-40a913db790c.png)
+
+   可以看到, 在 `conf` 参数中我们为插件配置的 `path: logs/file.log` 
已经成功地保存了。到此我们已经成功创建了一个最小可用的插件,在日志阶段打印了 `conf` 和 `ctx` 参数的数据。
+
+   之后,我们可以直接在该 `file-logger.lua` 插件代码文件中,为它编写核心功能。这里我们可以直接运行 `apisix reload` 
命令来重新加载最新的插件代码,而无需重启 Apache APISIX。
+
+### 为 file-logger 插件编写核心功能
+
+`file-logger` 插件的主要功能是写日志数据。在经过询问和查阅资料后,我了解到 [Lua 的 IO 
库](https://www.tutorialspoint.com/lua/lua_file_io.htm),于是确认了该插件的功能逻辑大致为以下几步:
+
+1. 每次接受请求之后,将日志数据输出到插件配置的 `path` 中去。
+   1. 首先,在日志阶段通过 `conf` 拿到 `file-logger` 中 `path` 的值。
+   2. 然后,通过 Lua IO 库来完成文件「创建」、「打开」、「写」、「刷新缓存」、「关闭」的操作。
+2. 处理「文件打开」失败、「文件创建」失败等错误。
+
+   ```lua
+    local function write_file_data(conf, log_message)
+        local msg, err = core.json.encode(log_message)
+        if err then
+            return core.log.error("message json serialization failed, error 
info : ", err)
+        end
+
+        local file, err = io_open(conf.path, 'a+')
+
+        if not file then
+            core.log.error("failed to open file: ", conf.path, ", error info: 
", err)
+        else
+            local ok, err = file:write(msg, '\n')
+            if not ok then
+                core.log.error("failed to write file: ", conf.path, ", error 
info: ", err)
+            else
+                file:flush()
+            end
+            file:close()
+        end
+    end
+   ```
+
+3. 参考 `http-logger` 插件源码,完成了将日记数据传给写日志数据的方法和 metadata 的一些判断和处理。
+
+   ```lua
+    function _M.log(conf, ctx)
+        local metadata = plugin.plugin_metadata(plugin_name)
+        local entry
+
+        if metadata and metadata.value.log_format
+            and core.table.nkeys(metadata.value.log_format) > 0
+        then
+            entry = log_util.get_custom_format_log(ctx, 
metadata.value.log_format)
+        else
+            entry = log_util.get_full_log(ngx, conf)
+        end
+
+        write_file_data(conf, entry)
+    end
+   ```
+
+## 验证及添加测试
+
+### 验证收集日志记录
+
+因为在创建测试路由时已经启用了 `file-logger` 插件,并且配置了 `path` 为 
`logs/file.log`,所以此时我们只需给测试路由发送请求,以验证日志收集的结果:
+
+```shell
+curl -i http://127.0.0.1:9080/api/hello
+```
+
+在对应的 `logs/file.log` 中我们可以看到每条记录都是以 JSON 的格式保存下来。将其中一条数据格式化之后如下所示:
+
+```json
+{
+    "server":{
+        "hostname":"....",
+        "version":"2.11.0"
+    },
+    "client_ip":"127.0.0.1",
+    "upstream":"127.0.0.1:3030",
+    "route_id":"1",
+    "start_time":1641285122961,
+    "latency":13.999938964844,
+    "response":{
+        "status":200,
+        "size":252,
+        "headers":{
+            "server":"APISIX\/2.11.0",
+            "content-type":"application\/json; charset=utf-8",
+            "date":"Tue, 04 Jan 2022 08:32:02 GMT",
+            "vary":"Accept-Encoding",
+            "content-length":"19",
+            "connection":"close",
+            "etag":"\"13-5j0ZZR0tI549fSRsYxl8c9vAU78\""
+        }
+    },
+    "service_id":"",
+    "request":{
+        "querystring":{
+
+        },
+        "size":87,
+        "method":"GET",
+        "headers":{
+            "host":"127.0.0.1:9080",
+            "accept":"*\/*",
+            "user-agent":"curl\/7.77.0"
+        },
+        "url":"http:\/\/127.0.0.1:9080\/api\/hello",
+        "uri":"\/api\/hello"
+    }
+}
+```
+
+至此验证收集日志记录的环节结束了,验证结果说明插件成功启动并返回了应有的数据。
+
+### 为插件添加测试
+
+对于 `add_block_preprocessor` 部分的代码,由于我没有学过 Perl 
,所以在刚开始编写时比较困惑。在询问之后才了解到它的正确使用方式:如果我们在数据部分没有编写相关的 `request` 断言和 `no_error_log` 
断言时,那么默认断言如下:
+
+```lua
+--- request
+GET /t
+--- no_error_log
+[error]
+```
+
+综合参考了一些其他的日志测试文件以后,我在 `t/plugin/` 目录下创建 `file-logger.t` 文件。
+
+每一份测试文件都由 `__DATA__` 
分为序言部分和数据部分。由于目前官网测试相关文档没有明确归档分类,更多具体内容可参考文末的相关资料。下面我为大家列出参考相关资料后完成的其中一个测试用例:
+
+```perl
+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->no_error_log && ! $block->error_log) {
+        $block->set_value("no_error_log", "[error]");
+    }
+});
+
+
+run_tests;
+
+__DATA__
+
+=== TEST 1: sanity
+--- config
+    location /t {
+        content_by_lua_block {
+            local configs = {
+                -- full configuration
+                {
+                    path = "file.log"
+                },
+                -- property "path" is required
+                {
+                    path = nil
+                }
+            }
+
+            local plugin = require("apisix.plugins.file-logger")
+
+            for i = 1, #configs do
+                ok, err = plugin.check_schema(configs[i])
+                if err then
+                    ngx.say(err)
+                else
+                    ngx.say("done")
+                end
+            end
+        }
+    }
+--- response_body_like
+done
+property "path" is required
+```
+
+至此插件添加测试环节结束。
+
+## 总结
+
+以上就是我作为一个后端新手,从 0 开始实现一款 Apache APISIX 插件的全过程。在开发插件的过程中确实碰到了很多坑,比较幸运的是 Apache 
APISIX 社区里面有很多热心的大佬帮我解惑,使得 `file-logger` 
插件的开发和测试全程都比较顺畅。如果你对这个插件感兴趣,或想要查看插件详情,可以参考 [Apache APISIX 
官方文档](https://apisix.apache.org/zh/docs/apisix/next/plugins/file-logger/)。
+
+目前,Apache APISIX 也在开发其他插件以支持集成更多服务,如果您对此感兴趣,欢迎随时在 [GitHub 
Discussion](https://github.com/apache/apisix/discussions) 
中发起讨论,也可通过[邮件列表](https://apisix.apache.org/docs/general/subscribe-guide)进行交流讨论。
+
+## 参考资料
+
+- [Apache APISIX 
插件开发指南](https://apisix.apache.org/zh/docs/apisix/plugin-develop/)
+- [Lua - File I/O 使用指南](https://www.tutorialspoint.com/lua/lua_file_io.htm)
+- [如何运行 Apache APISIX 
测试案例](https://apisix.apache.org/zh/docs/apisix/how-to-build/#%E6%AD%A5%E9%AA%A44%EF%BC%9A%E8%BF%90%E8%A1%8C%E6%B5%8B%E8%AF%95%E6%A1%88%E4%BE%8B)
+- 
[如何编写测试用例](https://apisix.apache.org/zh/docs/apisix/plugin-develop/#%E7%BC%96%E5%86%99%E6%B5%8B%E8%AF%95%E7%94%A8%E4%BE%8B)
+- [Apache APISIX 
测试框架介绍](https://apisix.apache.org/zh/docs/apisix/internal/testing-framework/)
+- [test-nginx 相关的一些 API 
介绍](https://metacpan.org/pod/Test%3A%3ANginx%3A%3ASocket)

Reply via email to