如何调试OpenResty的Lua代码

在适当位置打印输出

使用print

使用print(),相当于ngx.log(ngx.NOTICE, ...),适用于所有阶段.

nginx.conf

# 设置为notice级别
error_log  logs/error.log  notice;  
-- 在lua代码中需要调试的位置添加:
print(var)

通过在error.log中查看相关输出

注意:

print无法处理lua的table对象,需要先序列化。

print无法处理函数对象。

使用nxg.say或ngx.print

使用ngx.say()ngx.print(),这俩区别是在内容输出时前一个比后一个多一个换行符.

-- 注意:
-- 这两个api只能用于rewrite、access、content三个阶段。
-- 直接在前端输出内容。
-- 该api用于rewrite阶段时,将跳过其他2个阶段,同理用于access阶段时,将跳过content阶段,但剩余其他阶段不会跳过。
-- 不能处理输出函数对象。
-- 如果输出的变量是lua的table对象,需要对table进行序列化,如下:
json = require "cjson"
json_encode = json.encode

foo = {1, bar="2"}
ngx.say(json_encode(foo))

设置断点

函数块内代码的断点

do return end

放置在函数代码块中需要断点的位置,这样断点位置后的函数代码不会被运行,注意不会终止代码文件运行。

模块级别(文件)的断点

return

用在条件代码块时,return不论是否放在最后一行,都会最后一个执行,并会终止当前代码文件的运行。

用于循环代码块时,会在return所在位置终止当前代码文件的运行。

do return end

在代码文件级别、条件代码块、循环代码块需要设置断点的位置设置do return end,将终止当前代码文件的运行。

注意:以上说的终止代码文件执行,终止的是return所在的当前文件(模块)级别,并不会影响其他执行阶段;至于是否会终止当前执行阶段,就要看当前执行阶段的代码块中是否有return了,如果return只是出现在当前代码文件的require的模块中,或者是当前代码文件调用的外部定义的函数中,这个return也不会影响到当前执行阶段。

当前请求的断点

ngx.exit(status)   -- status >= 200 (i.e., ngx.HTTP_OK and above)

当前请求将在ngx.exit的位置给用户响应,后续代码不会执行,

注意: header_filter/body_filter/log阶段的代码还是会执行的。

当前阶段的断点

ngx.exit(0) 或者 ngx.exit(ngx.OK)

  • 当前阶段的位于ngx.exit(0)ngx.exit(ngx.OK)后的所有代码不会执行,后续阶段不受影响
  • 适用于阶段函数调用的外部函数中
  • 注意使用ngx.exit(-1)ngx.exit(ngx.ERROR)后,只有log阶段会执行,并且不会给客户端响应任何内容和响应码。

lua_code_cache指令

lua_code_cache指令默认是on状态,即会对代码和一些共享数据做缓存,大大提高性能,这个在生产环境一定是要打开的。

对于测试阶段,对于一些测试场景也需要打开,比如对模块级别变量的测试,压测等场景。

其他测试场景,在使用*_by_lua_file的方式时,为了不必频繁reload nginx来重新加载代码的麻烦,可以将该指令设置为off

syntax: lua_code_cache on | off

default: lua_code_cache on

context: http, server, location, location if