diff --git a/modules/ngx_debug_conn/README.cn b/modules/ngx_debug_conn/README.cn new file mode 100644 index 0000000000..43a403d47b --- /dev/null +++ b/modules/ngx_debug_conn/README.cn @@ -0,0 +1,130 @@ +ngx_debug_conn +============== + +该模块可以提供NGINX/Tengine连接的状态信息。 + +示例 +======= + +获取NGINX/Tengine连接的状态信息 +--------------------------------- + +``` + http { + server { + listen 80; + + location = /debug_conn { + debug_conn; + } + } + } +``` + +请求URI /debug_conn,可以获取到该NGINX/Tengine连接的使用情况统计。 +页面输出如下: + +``` +$ curl 'localhost:80/debug_conn' +pid:70568 +connections:3 +--------- [1] -------- +conns[i]: 0 + fd: 6 + addr: 0.0.0.0:80 + sent: 0 + action: (null: listening) + handler: r:000000010DAEBEC0 w:0000000000000000 +requests: 0 +poolsize: 0 +--------- [2] -------- +conns[i]: 1 + fd: 7 + addr: (null) + sent: 0 + action: (null: channel) + handler: r:000000010DAFB770 w:0000000000000000 +requests: 0 +poolsize: 0 +--------- [3] -------- +conns[i]: 2 + fd: 3 + addr: 127.0.0.1 + sent: 0 + action: (null) + handler: r:000000010DB28CA0 w:000000010DB28CA0 +requests: 1 +poolsize: 0 +********* request ****** + uri: http://localhost/debug_conn + handler: r:000000010DB26820 w:000000010DB29770 +startsec: 1542356262 +poolsize: 0 +``` + +连接的使用情况统计 +----------------------------------- + +数据说明 +==== + +每个数据段落如"[1]"包含当前标号对应连接的状态信息,数据项意义如下: + +* __conns__: 当前连接标号,用于信息统计 +* __fd__: 当前连接的句柄号 +* __addr__: 当前连接的监听地址 +* __sent__: 当前连接的已发送数据量 +* __action__: 当前连接的log action +* __handler__: 当前连接的读写事件挂载handler地址,配合addr2line来查询对应函数 +* __requests__: 当前连接上的请求量 +* __poolsize__: 当前连接的内存池大小 +* __request__: 当前连接上的请求 +* __uri__: 当前连接上的请求的请求地址 +* __handler__: 当前连接上的请求的读写事件挂载handler地址,配合addr2line来查询对应函数 +* __startsec__: 当前连接上的请求的起始时间戳 +* __poolsize__: 当前连接上的请求的内存池大小 + +NGINX兼容性 +=================== + +* 1.13.4 (stable version of 1.13.x) 及其更高版本 + +Tengine兼容性 +===================== + +* 2.1.1 (stable version of 2.1.x) 及其更高版本 + +安装说明 +======= + +源码安装,执行如下命令: + +``` +$ wget http://nginx.org/download/nginx-1.13.4.tar.gz +$ tar -xzvf nginx-1.13.4.tar.gz +$ cd nginx-1.13.4/ +$ ./configure --add-module=/path/to/ngx_debug_conn +$ make -j4 && make install +``` + + +配置指令 +========= + +语法: **debug_conn** + +默认: `none` + +位置: `server, location` + +NGINX/Tenigne的连接状态信息可以通过该location访问得到。 + +注意信息 +========= + +``` +********* request ****** +``` + +request数据段落仅在当前连接上有请求存在时展示 + diff --git a/modules/ngx_debug_conn/README.md b/modules/ngx_debug_conn/README.md new file mode 100644 index 0000000000..1a7a77b180 --- /dev/null +++ b/modules/ngx_debug_conn/README.md @@ -0,0 +1,130 @@ +ngx_debug_conn +============== + +This module provides access to information of connection usage for nginx/tengine. + +Example +======= + +Get information of connection usage. +--------------------------------- + +``` + http { + server { + listen 80; + + location = /debug_conn { + debug_conn; + } + } + } +``` + +Requesting URI /debug_conn, you will get information of connection usage for nginx/tengine. +The output page may look like as follows: + +``` +$ curl 'localhost:80/debug_conn' +pid:70568 +connections:3 +--------- [1] -------- +conns[i]: 0 + fd: 6 + addr: 0.0.0.0:80 + sent: 0 + action: (null: listening) + handler: r:000000010DAEBEC0 w:0000000000000000 +requests: 0 +poolsize: 0 +--------- [2] -------- +conns[i]: 1 + fd: 7 + addr: (null) + sent: 0 + action: (null: channel) + handler: r:000000010DAFB770 w:0000000000000000 +requests: 0 +poolsize: 0 +--------- [3] -------- +conns[i]: 2 + fd: 3 + addr: 127.0.0.1 + sent: 0 + action: (null) + handler: r:000000010DB28CA0 w:000000010DB28CA0 +requests: 1 +poolsize: 0 +********* request ****** + uri: http://localhost/debug_conn + handler: r:000000010DB26820 w:000000010DB29770 +startsec: 1542356262 +poolsize: 0 +``` + +Get information of connection usage +----------------------------------- + +Data +==== + +Every block like "[1]" except the related connection usage as follows: + +* __conns__: sequence of current connection +* __fd__: file description of current connection +* __addr__: listening address of current connection +* __sent__: data sent size of current connection +* __action__: log action of current connection +* __handler__: read/write event handler of current connection, use addr2line to find the real function +* __requests__: request numbers of current connection +* __poolsize__: memory pool size of current connection +* __request__: request of current connection +* __uri__: request uri of current connection +* __handler__: read/write event handler of the request, use addr2line to find the real function +* __startsec__: start timestamp of the request +* __poolsize__: memory pool size of the request + +Nginx Compatibility +=================== + +The latest module is compatible with the following versions of nginx: + +* 1.13.4 (stable version of 1.13.x) and later + +Tengine Compatibility +===================== + +* 2.1.1 (stable version of 2.1.x) and later + +Install +======= + +Install this module from source: + +``` +$ wget http://nginx.org/download/nginx-1.13.4.tar.gz +$ tar -xzvf nginx-1.13.4.tar.gz +$ cd nginx-1.13.4/ +$ ./configure --add-module=/path/to/ngx_debug_conn +$ make -j4 && make install +``` + +Directive +========= + +Syntax: **debug_conn** + +Default: `none` + +Context: `server, location` + +The information of nginx connection usage will be accessible from the surrounding location. + +Exception +========= + +``` +********* request ****** +``` + +The request block will only show when request exists in connection. diff --git a/modules/ngx_debug_conn/config b/modules/ngx_debug_conn/config new file mode 100644 index 0000000000..a47f4d466f --- /dev/null +++ b/modules/ngx_debug_conn/config @@ -0,0 +1,3 @@ +ngx_addon_name=ngx_http_debug_conn_module +HTTP_MODULES="$HTTP_MODULES ngx_http_debug_conn_module" +NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_debug_conn_module.c" diff --git a/modules/ngx_debug_conn/ngx_http_debug_conn_module.c b/modules/ngx_debug_conn/ngx_http_debug_conn_module.c new file mode 100644 index 0000000000..bf6e6fbe8d --- /dev/null +++ b/modules/ngx_debug_conn/ngx_http_debug_conn_module.c @@ -0,0 +1,277 @@ + +/* + * Copyright (C) 2016 Alibaba Group Holding Limited + */ + + +#include +#include +#include + + +#if (NGX_DEBUG_POOL) +extern size_t ngx_pool_size(ngx_pool_t *); +#else +#define ngx_pool_size(p) ((size_t) 0) +#endif + +#if (NGX_HTTP_SSL) +#define ngx_request_scheme(r) ((r)->connection->ssl ? "https" : "http") +#else +#define ngx_request_scheme(r) "http" +#endif + + +static char *ngx_http_debug_conn(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static ngx_int_t ngx_http_debug_conn_buf(ngx_pool_t *pool, ngx_buf_t *b); + +static ngx_command_t ngx_http_debug_conn_commands[] = { + + { ngx_string("debug_conn"), + NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS, + ngx_http_debug_conn, + 0, + 0, + NULL }, + + ngx_null_command +}; + + +static ngx_http_module_t ngx_http_debug_conn_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_debug_conn_module = { + NGX_MODULE_V1, + &ngx_http_debug_conn_module_ctx, /* module context */ + ngx_http_debug_conn_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_debug_conn_handler(ngx_http_request_t *r) +{ + ngx_int_t rc; + ngx_buf_t *b; + ngx_chain_t out; + + if (r->method != NGX_HTTP_GET) { + return NGX_HTTP_NOT_ALLOWED; + } + + rc = ngx_http_discard_request_body(r); + if (rc != NGX_OK) { + return rc; + } + + b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); + if (b == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + if (ngx_http_debug_conn_buf(r->pool, b) == NGX_ERROR) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + r->headers_out.status = NGX_HTTP_OK; + r->headers_out.content_length_n = b->last - b->pos; + + rc = ngx_http_send_header(r); + + if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { + return rc; + } + + out.buf = b; + out.next = NULL; + + return ngx_http_output_filter(r, &out); +} + + +static ngx_int_t +ngx_http_debug_conn_buf(ngx_pool_t *pool, ngx_buf_t *b) +{ + u_char *p; + size_t size; + ngx_uint_t i, k, n; + ngx_str_t addr, action, host, uri; + ngx_connection_t *c; + ngx_http_request_t *r; + +#define NGX_CONN_TITLE_SIZE (sizeof(NGX_CONN_TITLE_FORMAT) - 1 + NGX_TIME_T_LEN + NGX_INT_T_LEN) /* sizeof pid_t equals time_t */ +#define NGX_CONN_TITLE_FORMAT "pid:%P\n" \ + "connections:%ui\n" + +#define NGX_CONN_ENTRY_SIZE (sizeof(NGX_CONN_ENTRY_FORMAT) - 1 + \ + NGX_SIZE_T_LEN * 2 + NGX_SOCKADDR_STRLEN + 32 /* action */ + \ + NGX_OFF_T_LEN + NGX_INT_T_LEN * 3 + NGX_PTR_SIZE * 2 * 2) +#define NGX_CONN_ENTRY_FORMAT "--------- [%ui] --------\n"\ + "conns[i]: %ui\n" \ + " fd: %z\n" \ + " addr: %V\n" \ + " sent: %O\n" \ + " action: %V\n" \ + " handler: r:%p w:%p\n" \ + "requests: %ui\n" \ + "poolsize: %z\n" + +#define NGX_REQ_ENTRY_SIZE (sizeof(NGX_REQ_ENTRY_FORMAT) - 1 + \ + sizeof("https") - 1 + 32 /* host */ + 64 /* uri */ + \ + NGX_TIME_T_LEN + NGX_PTR_SIZE * 2 * 2 + NGX_SIZE_T_LEN) +#define NGX_REQ_ENTRY_FORMAT "********* request ******\n"\ + " uri: %s://%V%V\n" \ + " handler: r:%p w:%p\n" \ + "startsec: %T\n" \ + "poolsize: %z\n" + + n = ngx_cycle->connection_n - ngx_cycle->free_connection_n; + + size = NGX_CONN_TITLE_SIZE + n * (NGX_CONN_ENTRY_SIZE + NGX_REQ_ENTRY_SIZE); + p = ngx_palloc(pool, size); + if (p == NULL) { + return NGX_ERROR; + } + + b->pos = p; + + p = ngx_sprintf(p, NGX_CONN_TITLE_FORMAT, ngx_pid, n); + + /* lines of entry */ + + k = 0; + + for (i = 0; i < ngx_cycle->connection_n; i++) { + c = &ngx_cycle->connections[i]; + + if (c->fd <= 0) { + continue; + } + + k++; + + if (n == 0) { + break; + } + n--; + + /* addr_text */ + + if (c->addr_text.data != NULL) { + addr.data = c->addr_text.data; + addr.len = ngx_min(c->addr_text.len, NGX_SOCKADDR_STRLEN); + + } else if (c->listening && c->listening->addr_text.data != NULL) { + addr.data = c->listening->addr_text.data; + addr.len = ngx_min(c->listening->addr_text.len, NGX_SOCKADDR_STRLEN); + + } else { + ngx_str_set(&addr, "(null)"); + } + + /* action */ + + if (c->log->action != NULL) { + action.data = (u_char *) c->log->action; + action.len = ngx_min(ngx_strlen(c->log->action), 32); + +#if (NGX_SSL) + } else if (c->ssl) { + + ngx_str_set(&action, "(null: ssl)"); +#endif + + } else if (c->listening && c->listening->connection == c) { + ngx_str_set(&action, "(null: listening)"); + + } else if (c->data == NULL) { + ngx_str_set(&action, "(null: channel)"); + + } else { + ngx_str_set(&action, "(null)"); + } + + /* entry format of connection */ + + p = ngx_snprintf(p, NGX_CONN_ENTRY_SIZE, NGX_CONN_ENTRY_FORMAT, + k, i, + c->fd, + &addr, + c->sent, + &action, + c->read->handler, c->write->handler, + c->requests, + c->pool ? ngx_pool_size(c->pool) : (size_t) 0); + + /* c->data: http request */ + + if (c->data != NULL) { + r = (ngx_http_request_t *) c->data; + if (r->signature == NGX_HTTP_MODULE && r->connection == c) { + + /* request host */ + + if (r->headers_in.server.len) { + host.data = r->headers_in.server.data; + host.len = ngx_min(r->headers_in.server.len, 32); + } else { + ngx_str_set(&host, ""); + } + + /* request uri */ + + uri.data = r->unparsed_uri.data; + uri.len = ngx_min(r->unparsed_uri.len, 64); + + /* entry format of request */ + + p = ngx_snprintf(p, NGX_REQ_ENTRY_SIZE, NGX_REQ_ENTRY_FORMAT, + ngx_request_scheme(r), &host, &uri, + r->read_event_handler, r->write_event_handler, + r->start_sec, + r->pool ? ngx_pool_size(r->pool) : (size_t) 0); + } + } + + p[-1] = '\n'; /* make sure last char is newline */ + } + + b->last = p; + b->memory = 1; + b->last_buf = 1; + + return NGX_OK; +} + + +static char * +ngx_http_debug_conn(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_debug_conn_handler; + + return NGX_CONF_OK; +} diff --git a/modules/ngx_debug_conn/t/test.t b/modules/ngx_debug_conn/t/test.t new file mode 100755 index 0000000000..b355665b24 --- /dev/null +++ b/modules/ngx_debug_conn/t/test.t @@ -0,0 +1,55 @@ +#!/usr/bin/perl + +# Copyright (C) 2015 Alibaba Group Holding Limited + +use warnings; +use strict; + +use Test::More; +use File::Copy; + +BEGIN { use FindBin; chdir($FindBin::Bin); } + +use lib 'lib'; +use Test::Nginx; + +############################################################################### + +select STDERR; $| = 1; +select STDOUT; $| = 1; + +my $t = Test::Nginx->new()->plan(1) + ->write_file_expand('nginx.conf', <<'EOF'); + +master_process off; +daemon off; + +events { +} + +http { + server { + listen 127.0.0.1:8080; + + location /debug_conn { + debug_conn; + } + } +} + +EOF + +############################################################################### + +$t->run(); + +my $status = http_get("/debug_conn"); + +like($status, qr#uri: http://localhost/debug_conn#, + 'debug_conn returns information of ngx_cycle->connections[]'); + +print "--- debug for verbose mode ---\n", + "$status", + "------------------------------\n"; + +$t->stop();