发布时间:2020-03-05 19:50:16来源:阅读:
有些时候,我们需要通过 Lua 代码操作 Nginx 里面的某些状态,但是想要的 API 并不存在于 OpenResty 之内。这时候,可以选择编写一个 Nginx C 模块,然后暴露出可供 Lua 调用的接口。
本文中,我们会分别探讨,如何通过 Nginx 变量或 FFI 的方式去提供 Lua 调用得到的接口。
文中的示例代码可以在 ngx_http_example_or_module 找到。
ngx.var.variable= 在调用的时候,会先查找变量 variable 对应的 handler(一个在 Nginx 内注册的 C 函数),如果 handler 存在,会去调用该 handler。
这意味着,如果我们定义了一个 Nginx 变量和对应的 handler,我们就可以通过在 Lua 代码里调用 ngx.var.variable= 来触发该 handler。
空说无益,先上示例。
在 Nginx 里面我们可以通过 limit_rate 和 limit_rate_after 两个指令来限制响应给客户端的速率。前者决定了限速的多少,后者决定了从什么时候开始限速。当然更多的时候我们需要动态去调整这两个指标。
limit_rate 对应有一个 Nginx 内置的变量, $limit_rate,我们可以修改该变量来达到动态调整的目的。相关的 Lua 代码是 ngx.var.limit_rate = limit_rate。但是并不存在 $limit_rate_after 这样一个变量。
不用担心。因为我们可以自己加上。
// ngx_http_example_or_module.c
// 定义变量和它的 getter/setter
static ngx_http_variable_t ngx_http_example_or_variables[] = {
{ ngx_string("limit_rate_after"), ngx_http_variable_request_set_size,
ngx_http_variable_request_get_limit_rate_after,
offsetof(ngx_http_request_t, limit_rate_after),
NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE, 0 },
{ ngx_null_string, NULL, NULL, 0, 0, 0 }
};
// getter 和 setter 的实现在 GitHub 上的示例代码里有,这里就不贴上了。
不过在大多数情况下,我们并不需要借助变量来间接调用 Nginx C 函数。我们完全可以借助 LuaJIT 的 FFI,直接调用 Nginx C 函数。
lua-resty-murmurhash2 就是一个现成的例子。
下面让我们再看另外一个例子,通过 Lua 代码来获取当前的 Nginx 错误日志等级。
在开发中,我们有时需要在测试环境中通过日志来记录某个 table 的值,比如 ngx.log(ngx.INFO, cjson.encode(res))。
在生产环境里,我们会设置日志等级为 error,这样就不会输出 table 的值。但是日志等级无论是多少,cjson.encode 都是必然会被调用的。
不幸的是,这行代码所在的路径非常热,我们需要避免无谓的 json encode 操作。如果能获取实际的日志等级,判断是否为 error,来决定是否调用 cjson.encode,就能省下这一笔开销。
要实现这一功能,仅需加个获取当前配置的日志等级的 Nginx C 函数和对应的 Lua 接口。
我们可以像这样提供一个 Lua 接口:
-- lib/example_or.lua
...
if not pcall(ffi.typeof, "ngx_http_request_t") then
ffi.cdef[[
struct ngx_http_request_s;
typedef struct ngx_http_request_s ngx_http_request_t;
]]
end
ffi.cdef[[
int ngx_http_example_or_ffi_get_error_log_level(ngx_http_request_t *r);
]]
function _M.get_error_log_level()
local r = getfenv(0).__ngx_req
return tonumber(C.ngx_http_example_or_ffi_get_error_log_level(r))
end
对应的 Nginx C 函数很简单:
int
ngx_http_example_or_ffi_get_error_log_level(ngx_http_request_t *r)
{
ngx_log_t *log;
int log_level;
if (r && r->connection && r->connection->log) {
log = r->connection->log;
} else {
log = ngx_cycle->log;
}
log_level = log->log_level;
if (log_level == NGX_LOG_DEBUG_ALL) {
log_level = NGX_LOG_DEBUG;
}
return log_level;
}
使用时直接拿它跟特定的 Nginx 日志等级常量比较即可:
-- config.lua
-- 目前 Nginx 不支持动态变更日志等级,所以可以把日志等级缓存起来
local example_or = require "lib.example_or"
_M.log_leve = example_or.get_error_log_level()
-- in other file
local config = require "common.config"
local log_level = config.log_level
if log_level >= ngx.WARN then
-- 错误日志等级是 warn 或者 info 一类
ngx.log(ngx.WARN, "log a warning event")
else
-- 错误日志等级是 error 一类
ngx.log(ngx.WARN, "do not log another warning event")
end
考无忧2018职称计算机模块-AutoCAD2004 v18.1
51.66 MB
考无忧2018职称计算机模块-PhotoShop CS v18.1.0
64.3 MB
Sublime Text 3(程序代码编写软件) v3.21 中文版
52MB
子美建筑工地管理系统(工地施工项目管理系统) v2021.07.01 官方版
57.8M
考无忧2018职称计算机模块
62.3 MB
考无忧2018职称计算机模块-FrontPage2000 v18.1
57.47 MB
考无忧2018职称计算机模块-Word 2003模块 v18.2
75.53 MB
考无忧2018职称计算机模块-Word 2007模块 v18.2
73.9 MB
7CMenuEditor
188KB
aCmeCadConverter(CAD文件处理软件)v2021 绿色版
8.92MB
Cool edit pro 2.1(音频处理软件)v2.1 免费版
16.2M
MagiCMouseTrails下载
388K
Teambition下载
44.6M
UltraSnap Pro抓图软件
13.68 MB
aCtivesynC(电脑数据同步工具) v6.1 免费版
22.72MB
dreamweaver Cs5下载
405.98 MB
easyreCovery pro(硬盘数据恢复工具) v14.0.0.4 官方版
87.8M
fastCopy下载
1.5M
flash Cs4(动画制作软件)V10.0.0.544 破解版
164.2M
ipCamera(网络摄像机搜索工具)V2.53 免费版
3.1M
2020-02-26
AnyMP4 Video Editor安装教程附破解补丁
电源管理3.0快捷键使用显示界面说明
英特尔® Optane™ 内存(Optane memory)介绍及使用方法
Linux ar建立或修改备存文件命令详解
笔记本一键恢复7.0如何进行系统备份
Docker命令行参考(11) – docker load从tar归档文件或STDIN导入镜像
《乐高漫威复仇者联盟》游戏截图
对CentOS-7使用xfs文件系统的LVM进行扩容
Lenovo C560一体机BIOS模拟器