一、引言

在使用 OpenResty 进行开发时,Lua 脚本调试是一个既重要又常常让人头疼的环节。OpenResty 是一个基于 Nginx 与 Lua 的高性能 Web 平台,利用 Lua 脚本能让我们在 Nginx 环境中实现复杂的业务逻辑。然而,调试 Lua 脚本并非易事,本文将详细介绍基于 ngx.log 与 OpenResty IDE 的调试技巧,帮助大家在开发过程中更高效地找出问题。


二、基于 ngx.log 的调试

1. ngx.log 介绍

ngx.log 是 OpenResty 提供的一个用于记录日志的函数。它可以将调试信息输出到 Nginx 的日志文件中,方便我们查看脚本执行过程中的各种状态。ngx.log 函数的基本语法如下:

-- ngx.log(日志级别, 要记录的信息)
-- 示例
ngx.log(ngx.ERR, "This is an error message.")

2. 日志级别

ngx.log 支持多种日志级别,常见的有:

  • ngx.DEBUG:用于输出调试信息,通常在开发环境中使用。
  • ngx.INFO:用于输出一般的信息。
  • ngx.WARN:用于输出警告信息。
  • ngx.ERR:用于输出错误信息。 OpenResty 的标准日志输出原句为 ngx.log(log_level, ...) ,几乎可以在任何 ngx_lua 阶段进行日志的输出。

请看下面的示例:

#user  nobody;
worker_processes  1;

error_log  logs/error.log error;    # 日志级别,只有等于或大于这个级别的日志才会输出
#pid        logs/nginx.pid;

events {
    worker_connections  1024;
}

http {
    server {
        listen    80;
        location / {
            content_by_lua_block {
                local num = 55
                local str = "string"
                local obj
                ngx.log(ngx.ERR, "num:", num)
                ngx.log(ngx.INFO, " string:", str)
                print([[i am print]])
                ngx.log(ngx.ERR, " object:", obj)
            }
        }
    }
}

访问网页,生成日志(logs/error.log 文件)结果如下:

2016/01/22 16:43:34 [error] 61610#0: *10 [lua] content_by_lua(nginx.conf:26):5:
 num:55, client: 127.0.0.1, server: , request: "GET /hello HTTP/1.1",
 host: "127.0.0.1"
 
2016/01/22 16:43:34 [error] 61610#0: *10 [lua] content_by_lua(nginx.conf:26):7:
 object:nil, client: 127.0.0.1, server: , request: "GET /hello HTTP/1.1",
 host: "127.0.0.1"

大家可以在单行日志中获取很多有用的信息,例如:时间、日志级别、请求ID、错误代码位置、内容、客户端 IP 、请求参数等等,这些信息都是环境信息,可以用来辅助完成更多其他操作。

需要注意日志输出级别,上面代码指定了日志输出级别是error,所以只有等于或大于这个级别的日志才会输出。

这里还有一个知识点就是 OpenResty 里面的 print 语句是 INFO 级别。 有关 Nginx 的日志级别,请看下表:

ngx.STDERR     -- 标准输出
ngx.EMERG      -- 紧急报错
ngx.ALERT      -- 报警
ngx.CRIT       -- 严重,系统故障,触发运维告警系统
ngx.ERR        -- 错误,业务不可恢复性错误
ngx.WARN       -- 告警,业务中可忽略错误
ngx.NOTICE     -- 提醒,业务比较重要信息
ngx.INFO       -- 信息,业务琐碎日志信息,包含不同情况判断等
ngx.DEBUG      -- 调试

他们是一些常量,越往上等级越高。

3. 示例代码

假设我们有一个简单的 Lua 脚本,用于验证用户请求的参数是否合法。以下是具体代码:

-- 获取请求参数
local args = ngx.req.get_uri_args()

-- 检查参数是否包含必要的字段
if not args["name"] then
    -- 如果没有 name 字段,记录错误信息并返回错误响应
    ngx.log(ngx.ERR, "Missing 'name' parameter in the request.")
    ngx.status = ngx.HTTP_BAD_REQUEST
    ngx.say("Missing 'name' parameter.")
    return
end

-- 如果参数合法,记录信息并返回成功响应
ngx.log(ngx.INFO, "Request received with name: ".. args["name"])
ngx.say("Hello, ".. args["name"].. "!")

4. 优点

  • 简单易用:不需要额外的工具,只要使用 ngx.log 函数就可以在脚本中记录信息。
  • 可靠:日志信息会被记录到 Nginx 的日志文件中,即使脚本出现崩溃也不会丢失。

5. 缺点

  • 不够直观:需要查看日志文件来获取调试信息,不能实时看到变量的值和脚本的执行流程。
  • 效率低:如果日志信息过多,查找有用信息会比较困难。

6. 注意事项

  • 合理设置日志级别:在生产环境中,建议使用 ngx.ERRngx.WARN 级别,避免输出过多的调试信息。
  • 控制日志信息的大小:避免记录过大的数据,以免占用过多的磁盘空间。

三、基于 OpenResty IDE 的调试

1. OpenResty IDE 介绍

OpenResty IDE 是专门为 OpenResty 开发设计的集成开发环境,它提供了强大的调试功能,如断点调试、变量查看等。

2. 安装与配置

首先,我们需要安装 OpenResty IDE。安装完成后,需要进行一些配置,以确保它能够正确地与 OpenResty 环境配合使用。具体配置步骤如下:

  • 打开 OpenResty IDE,进入设置界面。
  • 配置 Nginx 和 Lua 的路径,确保 IDE 能够找到相应的可执行文件。
  • 配置调试服务器的端口,以便 IDE 能够与服务器进行通信。

3. 示例代码

以下是一个使用 OpenResty IDE 调试的示例代码:

-- 定义一个函数,用于计算两个数的和
local function add_numbers(a, b)
    local result = a + b
    -- 设置断点,方便调试时查看变量的值
    -- 在 OpenResty IDE 中,在该行代码左侧点击即可设置断点
    ngx.log(ngx.DEBUG, "Result: ".. result)
    return result
end

-- 调用函数进行计算
local num1 = 10
local num2 = 20
local sum = add_numbers(num1, num2)

-- 输出计算结果
ngx.say("The sum of ".. num1.. " and ".. num2.. " is: ".. sum)

4. 调试步骤

  • 打开上述代码文件,在需要调试的位置设置断点。
  • 启动调试服务器,在 IDE 中点击调试按钮。
  • 当程序执行到断点处时,会暂停执行,此时可以查看变量的值和调用栈。
  • 可以使用单步执行、继续执行等命令,控制程序的执行流程。

5. 优点

  • 直观:可以实时查看变量的值和脚本的执行流程,方便定位问题。
  • 效率高:通过断点调试,可以快速缩小问题的范围,提高调试效率。

6. 缺点

  • 依赖外部工具:需要安装和配置 OpenResty IDE,对于一些简单的调试场景可能过于复杂。
  • 可能存在兼容性问题:在某些环境下,IDE 可能无法正常工作。

7. 注意事项

  • 确保 IDE 与 OpenResty 环境的版本兼容。
  • 调试前备份好代码,避免因调试过程中出现问题导致代码丢失。

四、应用场景分析

1. 开发阶段

在开发阶段,建议同时使用 ngx.log 和 OpenResty IDE 进行调试。对于一些简单的问题,可以使用 ngx.log 快速记录信息;对于复杂的问题,使用 OpenResty IDE 的断点调试功能可以更高效地定位问题。

2. 生产环境

在生产环境中,由于性能和安全的考虑,不建议使用 OpenResty IDE 进行调试。此时,应该使用 ngx.log 记录必要的错误和警告信息,以便在出现问题时进行排查。

五、总结

通过本文的介绍,我们了解了基于 ngx.log 与 OpenResty IDE 的 OpenResty Lua 脚本调试技巧。ngx.log 是一种简单可靠的调试方式,适用于各种场景,尤其是在生产环境中。而 OpenResty IDE 提供了更强大的调试功能,在开发阶段能够大大提高调试效率。在实际开发中,我们应该根据具体的场景选择合适的调试方式,以确保开发工作的顺利进行。