Sublime Text 不支持 Lua 真实调试,只能靠日志打点、debug.sethook 钩子或逆向查调用链;Ctrl+B 无交互上下文,print 输出混乱且不可靠;OpenResty 中禁用 debug.sethook,需优先确认运行环境就绪。

Sublime Text 本身不提供 Lua 调试器(如断点、单步、变量监视),所谓“调试函数参数与返回值”只能靠日志打点 + 快速重跑 + 语法辅助来逼近真实调试效果。别指望它像 VS Code 那样 attach 到 luajit 进程。
为什么不能直接用 Sublime 的 Ctrl+B 查看函数入参和返回值
因为 Ctrl+B 只是调用系统 lua 命令执行脚本,运行完就退出,没有交互式上下文;print() 输出会刷屏、无结构、难定位,且无法看到闭包捕获的变量或栈帧信息。更关键的是:Lua 的 debug.sethook 在普通脚本中启用后,Sublime 构建系统不会捕获钩子输出,除非你手动把 hook 日志重定向到文件并 tail -f 监听。
常见错误现象:print("args:", a, b) 在复杂嵌套调用里输出位置错乱、漏打、或被缓冲卡住;用了 debug.traceback() 却只看到顶层堆栈,看不到每次调用时的实际参数。
实操建议:
- 在函数入口第一行加
print(("[DEBUG %s] args: %s"):format(debug.getinfo(1,"n").name or "anonymous", table.concat({a,b}, ", "))),比裸 print 更易识别来源 - 避免在循环内高频 print,改用
ngx.log(ngx.DEBUG, ...)(OpenResty 场景)或写入临时文件:io.open("/tmp/lua-debug.log", "a"):write(os.date("%H:%M:%S"), " ", tostring(...) , "\n"):close() - 如果用
luacheck,它不检查运行时参数,但能提前发现形参未使用、变量遮蔽等静态问题——这反而能减少“传了却没用”的假象
用 debug.sethook 捕获函数调用与返回(仅限本地脚本)
debug.sethook 是唯一能在不改业务代码前提下观察参数/返回值的机制,但它必须在脚本最顶部启用,且对性能影响显著(尤其 l 或 crl 掩码)。OpenResty 环境中禁用该函数(会被 ngx_lua 模块拦截并报错)。
实操建议:
- 只在纯本地调试脚本(非 Nginx/Redis 嵌入场景)中使用,例如验证一个工具函数逻辑
- 用
c掩码 +debug.getinfo(2)获取被调函数名,再用debug.getlocal提取前几个局部变量(即形参):debug.sethook(function() local d = debug.getinfo(2) if d and d.what == "Lua" then local _, v = debug.getlocal(2, 1) print(d.name, "called with", tostring(v)) end end, "c")
- 不要设
count参数为小数值(如 1),否则每条指令都触发,脚本几乎无法完成执行 - 注意:hook 函数内不能再调用
print或io.write,容易引发递归崩溃;改用os.execute('echo ... >> /tmp/hook.log')更稳妥
Sublime 中快速查看函数定义与调用位置(替代参数推导)
当无法实时看参数时,逆向查调用链是最实用的替代方案。Sublime 的 Ctrl+R 和 Ctrl+P 能大幅缩短定位时间,但默认不支持匿名函数和表方法赋值写法(如 A.fn = function(...) ...)。
实操建议:
- 手动修改
Lua.tmLanguage文件中的正则,把function\s+([a-zA-Z_.:]+[.:])?([a-zA-Z_]\w*)\s*\(\)扩展为匹配[a-zA-Z_.:]+[.:]?\s*=\s*function形式(需删掉缓存文件并重启 Sublime) - 对 OpenResty 场景,
ngx.var、ngx.req.*等变量名在lua-enhanced插件中已有补全,但ngx.http.*异步接口需自己加 snippet,否则Ctrl+R找不到定义 - 用
Ctrl+Shift+F全局搜索your_func_name((括号要紧跟函数名),比依赖跳转更可靠——尤其当函数被赋值给局部变量或 table key 时 - 在函数开头加一行注释
-- @param a string @return number,配合 DocBlockr 插件可生成结构化文档,间接固化参数契约
真正卡住的不是怎么打日志,而是忘记 ngx.req.read_body() 导致 POST 参数为空,或在 init_by_lua* 里调用需要请求上下文的 API。这些错误不会出现在函数参数调试里,但会直接让所有参数打印都变成 nil——先确认运行环境是否就绪,再谈看参数。


















