内容简介:http://nginx.org/en/docs/http/ngx_http_stub_status_module.htmlngx_http_stub_status_module 是一个 Nginx 的内置 HTTP 模块,该模块可以提供 Nginx 的状态信息。默认情况下这个模块是不被编译进来的,所以在编译 Nginx 时要指定加载该模块:为什么拿它做例子?因为它也是个足够短小精悍的模块,是一个典型 handler 模块。那么以后我们讲解模块的过程,都是:
1 Background
http://nginx.org/en/docs/http/ngx_http_stub_status_module.html
ngx_http_stub_status_module 是一个 Nginx 的内置 HTTP 模块,该模块可以提供 Nginx 的状态信息。默认情况下这个模块是不被编译进来的,所以在编译 Nginx 时要指定加载该模块:
--with-http_stub_status_module
为什么拿它做例子?因为它也是个足够短小精悍的模块,是一个典型 handler 模块。那么以后我们讲解模块的过程,都是:
- 简要的介绍
- 使用的实例
- 指令介绍
- 源码分析
2 Simple example
location /nginx_status { stub_status on; access_log off;
access_log
/
usr
/
local
/
nginx
/
logs
/
status.log;
#日志
allow SOME.IP.ADD.RESS; deny all; }
我们假设你是在本机上实验,并且开启的是 80 端口,那么在浏览器中输入:
http://localhost/nginx_status
会看到这样的信息:
Active connections: 291 server accepts handled requests 16630948 16630948 31070465 Reading: 6 Writing: 179 Waiting: 106
其含义很容易理解:
-
第一行
- 当前的活跃连接数:291
-
第二行
- 服务器已接受的连接数:16630948(accepted connection #)
- 服务器已处理的连接数:16630948(handled connection #)
- 服务器已处理的请求:31070465(可以算出,平均每个连接有 1.8 个请求)(handled connection #)
-
第三行
- Reading – Nginx 读取的请求头次数为 6;
- Writting – Nginx 读取请求体、处理请求并发送响应给客户端的次数为 179;
- Waiting – 当前活动的长连接数:106。
Nginx 官方的解释如下:
active connections server accepts handled requests reading writing waiting
3 Directives
这个模块中的唯一一个指令,是:
stub_status
stub_status on
4 Source analysis
先看完整代码:
/* * Copyright (C) Igor Sysoev * Copyright (C) Nginx, Inc. */ #include <ngx_config.h> #include <ngx_core.h> #include <ngx_http.h> static char *ngx_http_set_status(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static ngx_command_t ngx_http_status_commands[] = { { ngx_string("stub_status"), NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, ngx_http_set_status, 0, 0, NULL }, ngx_null_command }; static ngx_http_module_t ngx_http_stub_status_module_ctx = { NULL, /* preconfiguration */ NULL, /* postconfiguration */ NULL, /* create main configuration */ NULL, /* init main configuration */ NULL, /* create server configuration */ NULL, /* merge server configuration */ NULL, /* create location configuration */ NULL /* merge location configuration */ }; ngx_module_t ngx_http_stub_status_module = { NGX_MODULE_V1, &ngx_http_stub_status_module_ctx, /* module context */ ngx_http_status_commands, /* module directives */ NGX_HTTP_MODULE, /* module type */ NULL, /* init master */ NULL, /* init module */ NULL, /* init process */ NULL, /* init thread */ NULL, /* exit thread */ NULL, /* exit process */ NULL, /* exit master */ NGX_MODULE_V1_PADDING }; static ngx_int_t ngx_http_status_handler(ngx_http_request_t *r) { size_t size; ngx_int_t rc; ngx_buf_t *b; ngx_chain_t out; ngx_atomic_int_t ap, hn, ac, rq, rd, wr; if (r->method != NGX_HTTP_GET && r->method != NGX_HTTP_HEAD) { return NGX_HTTP_NOT_ALLOWED; } rc = ngx_http_discard_request_body(r); if (rc != NGX_OK) { return rc; } ngx_str_set(&r->headers_out.content_type, "text/plain"); if (r->method == NGX_HTTP_HEAD) { r->headers_out.status = NGX_HTTP_OK; rc = ngx_http_send_header(r); if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { return rc; } } size = sizeof("Active connections: \n") + NGX_ATOMIC_T_LEN + sizeof("server accepts handled requests\n") - 1 + 6 + 3 * NGX_ATOMIC_T_LEN + sizeof("Reading: Writing: Waiting: \n") + 3 * NGX_ATOMIC_T_LEN; b = ngx_create_temp_buf(r->pool, size); if (b == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } out.buf = b; out.next = NULL; ap = *ngx_stat_accepted; hn = *ngx_stat_handled; ac = *ngx_stat_active; rq = *ngx_stat_requests; rd = *ngx_stat_reading; wr = *ngx_stat_writing; b->last = ngx_sprintf(b->last, "Active connections: %uA \n", ac); b->last = ngx_cpymem(b->last, "server accepts handled requests\n", sizeof("server accepts handled requests\n") - 1); b->last = ngx_sprintf(b->last, " %uA %uA %uA \n", ap, hn, rq); b->last = ngx_sprintf(b->last, "Reading: %uA Writing: %uA Waiting: %uA \n", rd, wr, ac - (rd + wr)); r->headers_out.status = NGX_HTTP_OK; r->headers_out.content_length_n = b->last - b->pos; b->last_buf = 1; rc = ngx_http_send_header(r); if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { return rc; } return ngx_http_output_filter(r, &out); } static char *ngx_http_set_status(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_http_core_loc_conf_t *clcf; clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); clcf->handler = ngx_http_status_handler; return NGX_CONF_OK; }
的确够短小精悍吧?关键在于 Nginx 提供的模块扩展方式比较好,让你可以少写一些代码(NDK 可以让你写的更少,这是后话)。
4.1 模块定义 ngx_http_stub_status_module
ngx_module_t ngx_http_stub_status_module = { NGX_MODULE_V1, &ngx_http_stub_status_module_ctx, /* module context */ ngx_http_status_commands, /* module directives */ NGX_HTTP_MODULE, /* module type */ NULL, /* init master */ NULL, /* init module */ NULL, /* init process */ NULL, /* init thread */ NULL, /* exit thread */ NULL, /* exit process */ NULL, /* exit master */ NGX_MODULE_V1_PADDING };
与此前介绍的 ngx_http_hello_world_module 并无本质区别。
4.2 命令集定义 ngx_http_status_commands
static ngx_command_t ngx_http_status_commands[] = { { ngx_string("stub_status"), NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, ngx_http_set_status, 0, 0, NULL }, ngx_null_command };
命令集定义如上,得到如下信息:
- name:stub_status
-
type:server conf、location conf、conf flag,其中最后一个比较陌生,相似的取值有:
#define NGX_CONF_ARGS_NUMBER 0x000000ff #define NGX_CONF_BLOCK 0x00000100 #define NGX_CONF_FLAG 0x00000200 #define NGX_CONF_ANY 0x00000400 #define NGX_CONF_1MORE 0x00000800 #define NGX_CONF_2MORE 0x00001000 #define NGX_CONF_MULTI 0x00002000
- set:ngx_http_set_status
下面解释下一些 types:
4.2.1 NGX_CONF_XXX
以下宏定义来自 ngx_conf_file.h:
#define NGX_CONF_NOARGS 0x00000001 // 命令不接受参数 #define NGX_CONF_TAKE1 0x00000002 // 命令携带1个参数 #define NGX_CONF_TAKE2 0x00000004 // 命令携带2个参数 #define NGX_CONF_TAKE3 0x00000008 // 命令携带3个参数 #define NGX_CONF_TAKE4 0x00000010 // 命令携带4个参数 #define NGX_CONF_TAKE5 0x00000020 // 命令携带5个参数 #define NGX_CONF_TAKE6 0x00000040 // 命令携带6个参数 #define NGX_CONF_TAKE7 0x00000080 // 命令携带7个参数 #define NGX_CONF_TAKE12 (NGX_CONF_TAKE1|NGX_CONF_TAKE2) // 命令携带1个或2个参数 #define NGX_CONF_TAKE13 (NGX_CONF_TAKE1|NGX_CONF_TAKE3) // 命令携带1个或3个参数 #define NGX_CONF_TAKE23 (NGX_CONF_TAKE2|NGX_CONF_TAKE3) // 命令携带2个或3个参数 #define NGX_CONF_TAKE123 (NGX_CONF_TAKE1|NGX_CONF_TAKE2|NGX_CONF_TAKE3) // 命令携带1个、2个或3个参数 #define NGX_CONF_TAKE1234 (NGX_CONF_TAKE1|NGX_CONF_TAKE2|NGX_CONF_TAKE3|NGX_CONF_TAKE4) // 命令携带1个、2个、3个或4个参数 #define NGX_CONF_ARGS_NUMBER 0x000000ff // 命令 #define NGX_CONF_BLOCK 0x00000100 // 块域,后面跟 {…},比如 server {...} #define NGX_CONF_FLAG 0x00000200 // 命令接受“on|off”参数 #define NGX_CONF_ANY 0x00000400 #define NGX_CONF_1MORE 0x00000800 // 命令携带至少1个参数 #define NGX_CONF_2MORE 0x00001000 // 命令携带至少2个参数 #define NGX_CONF_MULTI 0x00002000 // 命令携带多个参数
4.3 上下文定义 ngx_http_stub_status_module_ctx
static ngx_http_module_t ngx_http_stub_status_module_ctx = { NULL, /* preconfiguration */ NULL, /* postconfiguration */ NULL, /* create main configuration */ NULL, /* init main configuration */ NULL, /* create server configuration */ NULL, /* merge server configuration */ NULL, /* create location configuration */ NULL /* merge location configuration */ };
这个都是 NULL,够简单,无话可说了⋯⋯
4.4 命令设置函数 ngx_http_set_status
static char *ngx_http_set_status(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_http_core_loc_conf_t *clcf; clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); clcf->handler = ngx_http_status_handler; return NGX_CONF_OK; }
和 ngx_http_hello_world_module 对比下:
static char* ngx_http_hello_world(ngx_conf_t* cf, ngx_command_t* cmd, void* conf) { ngx_http_core_loc_conf_t* clcf; clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); clcf->handler = ngx_http_hello_world_handler; ngx_conf_set_str_slot(cf, cmd, conf); return NGX_CONF_OK; }
唯一的区别,就是 ngx_http_hello_world_module 多了一句 ngx_conf_set_str_slot。这个先留做一个问题,后面会介绍,暂时与关键主题无关。
4.5 命令处理函数 ngx_http_status_handler
static ngx_int_t ngx_http_status_handler(ngx_http_request_t *r) { size_t size; ngx_int_t rc; ngx_buf_t *b; ngx_chain_t out; ngx_atomic_int_t ap, hn, ac, rq, rd, wr;
这个模块要求接受的请求类是 GET、HEAD,其他类型的请求会被拒绝。
if (r->method != NGX_HTTP_GET && r->method != NGX_HTTP_HEAD) { return NGX_HTTP_NOT_ALLOWED; }
放弃请求体,因为这个模块用不上。
rc = ngx_http_discard_request_body(r); if (rc != NGX_OK) { return rc; }
如果请求是 HEAD 类型的,则直接设置响应头的 content_type、status 字段,并发送响应头。
ngx_str_set(&r->headers_out.content_type, "text/plain"); if (r->method == NGX_HTTP_HEAD) { r->headers_out.status = NGX_HTTP_OK; rc = ngx_http_send_header(r); if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { return rc; } }
创建一个缓冲区,向缓冲区写入我们上面在浏览器中看到的东西。
size = sizeof("Active connections: \n") + NGX_ATOMIC_T_LEN + sizeof("server accepts handled requests\n") - 1 + 6 + 3 * NGX_ATOMIC_T_LEN + sizeof("Reading: Writing: Waiting: \n") + 3 * NGX_ATOMIC_T_LEN; b = ngx_create_temp_buf(r->pool, size); if (b == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } out.buf = b; out.next = NULL; ap = *ngx_stat_accepted; hn = *ngx_stat_handled; ac = *ngx_stat_active; rq = *ngx_stat_requests; rd = *ngx_stat_reading; wr = *ngx_stat_writing; // 封装了 sprintf b->last = ngx_sprintf(b->last, "Active connections: %uA \n", ac); // 封装了 memcpy b->last = ngx_cpymem(b->last, "server accepts handled requests\n", sizeof("server accepts handled requests\n") - 1); b->last = ngx_sprintf(b->last, " %uA %uA %uA \n", ap, hn, rq); b->last = ngx_sprintf(b->last, "Reading: %uA Writing: %uA Waiting: %uA \n", rd, wr, ac - (rd + wr));
缓冲区写完了。然后设置下响应头的 status、content_length_n(还记得吗?b->last - b->pos 刚好是缓冲区的第二个区域,是已写入数据部分。)
r->headers_out.status = NGX_HTTP_OK; r->headers_out.content_length_n = b->last - b->pos; b->last_buf = 1;
发送响应头。
rc = ngx_http_send_header(r); if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { return rc; }
filter。
return ngx_http_output_filter(r, &out); }
Linux公社的RSS地址 : https://www.linuxidc.com/rssFeed.aspx
本文永久更新链接地址: https://www.linuxidc.com/Linux/2018-10/154672.htm
以上所述就是小编给大家介绍的《Nginx解读内置非默认模块 ngx_http_stub_status_module》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- Python3内置模块之json编解码方法小结
- Python3内置模块之pprint让打印比print更美观
- Python3内置模块之Pickle和cPickle数据持久化方法小结
- Nginx 的内置变量
- Python内置方法详解
- JSP 内置对象(一)
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
The Effective Engineer
Edmond Lau / The Effective Bookshelf, Palo Alto, CA. / 2015-3-19 / USD 39.00
Introducing The Effective Engineer — the only book designed specifically for today's software engineers, based on extensive interviews with engineering leaders at top tech companies, and packed with h......一起来看看 《The Effective Engineer》 这本书的介绍吧!