使用DTrace pid提供程序调试nginx

本文假定读者具有nginx内部知识和DTrace的一般知识 。pDs码友部落

尽管使用--with-debug 选项构建的nginx已经提供了许多有关请求处理的信息,但有时还是希望更彻底地跟踪代码路径的特定部分,同时省略其余的调试输出。DTrace pid提供程序(可在Solaris和macOS上使用)是一种有用的工具,可用于探索Userland程序的内部,因为它不需要任何代码更改,并且可以帮助完成任务。一个简单的DTrace脚本可以跟踪和打印nginx函数调用,如下所示:pDs码友部落

#pragma D选项flowindent

pid $ target:nginx :: entry {
}

pid $ target:nginx :: return {
}

 pDs码友部落

但是,用于函数调用跟踪的DTrace功能仅提供有限的有用信息。函数参数的实时检查通常更有趣,但也有些复杂。以下示例旨在帮助读者更加熟悉DTrace以及使用DTrace分析nginx行为的过程。pDs码友部落

以下是将DTrace与nginx一起使用的常见方案之一:附加到nginx工作进程以记录请求行和请求开始时间。要附加的对应函数是 ngx_http_process_request(),所讨论的参数是指向该ngx_http_request_t结构的指针用于此类请求日志记录的DTrace脚本可以很简单:pDs码友部落

pid $ target :: * ngx_http_process_request:entry
{
    this-> request =(ngx_http_request_t *)copyin(arg0,sizeof(ngx_http_request_t));
    this-> request_line = stringof(copyin((uintptr_t)this-> request-> request_line.data,
                                         this-> request-> request_line.len));
    printf(“ request line =%s  n”,this-> request_line);
    printf(“ request start sec =%d  n”,this-> request-> start_sec);
}

 pDs码友部落

应当注意,在上面的示例中,DTrace需要一些有关ngx_http_process_request结构的知识不幸的是,虽然可以#include 在DTrace脚本中使用特定的指令,然后将其传递给C预处理器(带有-C标志),但这实际上是行不通的。由于存在很多交叉依赖性,因此几乎必须包含所有的Nginx头文件。反过来,基于configure脚本设置,nginx头将包括PCRE,OpenSSL和各种系统头文件。理论上,与特定nginx构建相关的所有头文件都可能包含在DTrace脚本的预处理和编译中,但实际上,由于某些头文件中的语法未知,DTrace脚本极有可能无法编译。pDs码友部落

可以通过在DTrace脚本中仅包含相关且必要的结构和类型定义来解决上述问题。DTrace必须知道结构,类型和字段偏移量的大小。因此,可以通过手动优化与DTrace一起使用的结构定义来进一步减少依赖性。pDs码友部落

让我们使用上面的DTrace脚本示例,看看它需要什么结构定义才能正常工作。pDs码友部落

首先objs/ngx_auto_config.h应包括由configure生成的文件,因为它定义了许多影响各种的常数#ifdef在此之后,一些基本的类型和定义一样ngx_str_tngx_table_elt_t, ngx_uint_t等应在DTrace脚本的开始付诸表决。这些定义是紧凑的,常用的,不太可能经常更改。pDs码友部落

然后ngx_http_process_request_t是包含大量指向其他结构的指针的结构。因为这些指针确实与该脚本无关,并且它们的大小相同,所以可以将它们替换为空指针。不过,最好是添加适当的typedef而不是更改定义:pDs码友部落

typedef ngx_http_upstream_t void;
typedef ngx_http_request_body_t void;

最后但并非最不重要,有必要增加两个成员结构的定义(ngx_http_headers_in_t, ngx_http_headers_out_t),回调函数和常量的定义声明。pDs码友部落

可以从此处下载最终的DTrace脚本 。pDs码友部落

以下示例显示了运行此脚本的输出:pDs码友部落

#dtrace -C -I ./objs -s trace_process_request.d -p 4848
dtrace:脚本'trace_process_request.d'匹配1个探针
CPU ID功能:NAME
  1 4 .XAbmO.ngx_http_process_request:输入请求行= GET / HTTP / 1.1
请求开始秒= 1349162898

  0 4 .XAbmO.ngx_http_process_request:输入请求行= GET /zh-CN/docs/nginx_dtrace_pid_provider.html HTTP / 1.1
请求开始秒= 1349162899

 pDs码友部落

使用类似的技术,读者应该能够跟踪其他nginx函数调用。pDs码友部落