很多Nginx Lua程序员入门的过程中会遇到一个问题就是选择编辑器IDE,其实Lua编辑器IDE过去流行的也有几种,但大多数都被人遗忘了,如果只是做纯Lua代码的语法检查,代码补全,很多的IDE都可以做到,VIM安了特定的支持插件也可以。
而可以在线调试Nginx程序,设置断点的可视化IDE,那应该ZeroBraneStudio这个编辑器,低层利用Lua Socket进行通信,可以可视化的在IDE中,某句Lua代码,比如ngx.say("https://lua.ren")上设置断点,然后Nginx程序执行到此地会停下,在IDE的Output窗口有对应的字样的输出。
ZeroBraneStudio这种可视化的调试,Nginx服务和ZeroStuido在一台机器,需要有XWindow,首先用ZeroBraneStudio的人就不多,而用ZeroBraneStuido给Nginx/OpenResty下断点进行调试的人也不会太多,环境配置就比较麻烦,而且生产环境上的Linux服务器,部署XWindow的意义不大,更多的是本地调试,远程同步代码,现在找还可以找到之前我在网上写的这个调试过程教程。
经过了将近5年左右的时间,国内用ZeroBraneStudio的人就更少应该,而且多数的情况,调试服务找问题,不是下断点分析内存等相关资源,设断点这种方法效率不是很高。更高级的方法是春哥的做法,直接用火焰图可视化Lua的执行过程,用 Xray可视化跟踪OpenResty服务,用 Ylang辅助产生新功能,进行综合各种指标数据的分析,那就进入了另外的一种全新的视角。
ZeroBraneStudio作为一个开源编辑器IDE没有发展起来,但以VSC这种要统一宇宙IDE的节奏,是可以做到OpenRest/Nginx服务的运程调试的。通过VSC插件就可以做到这一点。对个人OpenResty服务开发的便利性来说,还是很有意义,所以引用了T婶(tweyseo)下面的文章内容,如何在本地Windows上通过VSC的SSH插件去远程调试服务器上的OpenResty程序,全网原创首发,供大家参考,如下:
背景
我们公司的测试和生成环境使用的Linux版本均为Red Hat Enterprise Linux Server release 7.3(Maipo),对应到云商的CentOS 7.3(1161),而本人的电脑/笔记本的操作系统均为Windows 10,为了更加方便的开发和调试Linux上的Openresty程序(ngx-lua模块),这里在Windows上使用VSCode(通过Remote-SSH扩展和C/C 扩展)进行远程开发和调试Linux上的Openresty程序(ngx-lua模块):
远程开发
首先,在Windows上通过PowerShell(确认OpenSSH客户端的可选功能开启,也可以通过git-bash生成)生成用于SSH登录的公私钥:
把生成的公钥(test.pub)中的内容,复制到要进行远程开发和调试的Linux机器上对应用户的.ssh/authorized_keys文件中(没有则新建)。可以在PowerShell中使用SSH登录,测试上述是否成功:
然后,在VSCode上搜索和安装Remote-SSH扩展(包含Remote-SSH: Editing Configuration Files的扩展包),接下来配置用于SSH登录的配置(CTRL SHIFT P选择Remote-SSH: Open Configuration Files):
保存后,在左边侧边栏的远程资源管理器中,就会生成对应的SSH远程会话(这里是test(tweyseo))。成功登录到test(tweyseo)后(登录过程比较简单),选择test(tweyseo)对应的远端Linux中相应的工作目录映射到VSCode的资源管理器中,这样就可以直接在本地读写该工作目录里的文件了,并且完成映射后,VSCode会在远程资源管理器中为test(tweyseo)生成对应到该工作目录的子会话(同个SSH远程会话),后续直接通过该子会话就可以在VSCode的资源管理器中映射出该工作目录。最后,新建终端(自动)映射到该工作目录。到这里,就完成了通过Windows上的VSCode远程开发Linux上的程序的通用工作。
你可以通过配置Remote-SSH扩展,设置remote.SSH.showLoginTerminal为true,来更好的定位登录中出现的问题。
因为我们这里主要是要开发Linux上的Openresty程序(ngx-lua模块),所以,还需要安装和配置VSCode的C/C 扩展以完成开发过程中的IntelliSense。这里需要注意的是,因为我们是远程开发,所以这里的C/C 扩展是需要通过SSH-Remote扩展安装在test(tweyseo)这个SSH远程会话对应的远端Linux上的VSCode Server中的,而不是安装在本地,并且就算你两边都安装了C/C 扩展,扩展也只会在本地或者远端的一端被启用。安装完成后,在工作目录对应的工作区中直接配置“settings”字段的C/C 扩展对应的属性(其中includePath里用到的**表示递归目录下的所有文件夹):
代码语言:javascript复制"settings": { "C_Cpp.default.includePath": [ "${default}", "${workspaceFolder}/../**" ], "C_Cpp.default.defines": [], "C_Cpp.default.compilerPath": "/usr/bin/gcc", "C_Cpp.default.cppStandard": "c 14", "C_Cpp.default.cStandard": "c11", "C_Cpp.default.intelliSenseMode": "gcc-x64"},
这样,就完成了通过Windows上的VSCode远程开发Linux上的Openresty程序(ngx-lua模块)的准备工作(工作区的选定以及includePath的选定,将在下面详细介绍)。
远程调试
这里主要是使用VSCode自身的debuggee来完成远程调试的工作。
因为我们这里主要是要开发Linux上的Openresty程序(ngx-lua模块),所以,首先要保证远端的Linux上要有调试C程序不可或缺的glibc-debuginfo-common-xxx和glibc-debuginfo-xxx(glibc的详细版本号可以通过rpm -qa | grep glibc指令查看,然后去debuginfo.centos.org下载对应的rpm包,当然也可以直接通过debuginfo-install安装)。
然后是编译debug版本的Openresty程序。这里需要在./configure时添加--with-debug,并且在make前修改nginx的Makefile文件,把优化级别改为-O0。
编译完成后,在/path/to/your/openresty/下建立工作区(*.code-workspace),这是因为Openresty(nginx)所启用的模块的源码(包括nginx自身的源码)基本上都在此该路径的build目录下,无论你是开发和调试ngx-lua模块,还是其他模块,甚至nginx自身,随时都可以添加build目录下对应的文件夹到该工作区的path属性中(该文件夹相应地也会展示到VSCode的资源管理器中),而且这些被添加到该工作区的文件夹可以共用(当然也可以独立的配置给指定的文件夹)该工作区的所有配置(这些配置不仅包含VSCode自身的配置,还包含了各种已安装的扩展的配置),这样就可以很好的把这些繁杂多样的配置在用户(本地)、远程、工作区以及不同的文件夹中简单有效的隔离开来。
同样的,todo:
值得一提的是,这里建议大家把我们的Openresty程序的工作目录也添加到该工作区中,这样我们可以直接在VSCode的资源管理器中调整Openresty程序的业务代码,从而使得我们可以更方便更直观的对特定业务场景下的ngx-lua甚至nginx本身进行调试:
接下来需要对VSCode的debuggee进行配置,在对应的工作区的launch属性中直接配置即可。在实际工作中,我们可以针对不同的调试模式使用不同的debuggee配置。我们可以对正在运行的Openresty程序的master进程或者worker进程进行调试,如功能测试阶段,这种调试模式对应launch属性的request类型是attach:
代码语言:javascript复制"configurations": [ { "name": "(gdb) Attach-nginx", "type": "cppdbg", "request": "attach", "program": "/path/to/your/openresty-debug/nginx/sbin/nginx", "processId": "${command:pickProcess}", "MIMode": "gdb", "setupCommands": [ { "description": "Enable pretty-printing for gdb", "text": "-enable-pretty-printing", "ignoreFailures": true } ] }]
选定该调试模式后,F5启动,然后选定Openresty程序的masrer进程或者worker进程的PID(可用PID列表由VSCode内置的${command:pickProcess}命令提供),即可开始调试工作:
我们也可以直接调试以单进程模式工作在前台的Openresty程序,如功能开发阶段,当然这个时候需要修改Openresty(nginx)的配置:
代码语言:javascript复制aemon off;
master_process off;
而这种调试模式对应launch属性的request类型是launch:
代码语言:javascript复制"configurations": [
{
"name": "(gdb) Launch-nginx",
"type": "cppdbg",
"request": "launch",
"program": "/path/to/your/openresty-debug/nginx/sbin/nginx",
"args": ["-c", "/path/to/your/nginx.conf"],
"stopAtEntry": false,
"cwd": "/path/to/your/project",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
]
}
]
选定该调试模式后,F5启动,即可开始调试工作:
最后,两种模式下,都可以通过调试控制台输入-exec和debuggee(这里实际是gdb)进行交互,如通过-exec info registers(等同于gdb info registers)查看寄存器内容(更多的可用命令见man gdb)。
扩展
远程编译
todo
attach模式自动选择对应pid
当我们使用attach的调试模式的时候,可能需要频繁的重复F5和输入pid这2个操作,而且每次操作的pid可能都不一样,也就意味着,每次attach调试的时候,可能都需要先通过在终端上敲shell命令查找出对应的pid,再attach到该pid进行调试,这样的工作效率是着实难以接受。
由于launch中的prelaunchTask配置是在input之后执行,而且processId使用的${command:pickProcess}也属于input,所以通过配置prelaunchTask无法实现。
由于input中的command只支持内置的或者已经安装的扩展提供的命令,所以也无法实现。
带研究。
launch模式结束后的清理工作
由于我们在Openresty(ngx)的配置中开启了reuseport选项,这样是可以在当前工作目录下启动多个Openresty程序的,但是这个是我们需要极力避免的情况,所以在我们Openresty程序的启动脚本中会判断nginx.pid文件是否存在,以限制在当前工作目录下只能启动一个Openresty程序。但是,当我们使用launch的调试模式,在调试结束的时候,nginx.pid文件并没被删除掉。
这里在launch模式对应的配置中,配置postDebugTask属性配合VSCode的task功能,完成launch调试模式结束后,删除nginx.pid的工作。