From f363b0cfe277bd8f2da7bfdea8029e088f0ff3f4 Mon Sep 17 00:00:00 2001 From: Kirill A. Korinskiy Date: Tue, 12 May 2009 17:51:50 +0400 Subject: [PATCH 1/5] Implment a basic status API Cc: catap@catap.ru `ngx_status_add_counter' add a counter `ngx_status_fetch_add' +1 to counter `ngx_status_get_value' get counter value `ngx_status_get_counters' get list of counters --- auto/modules | 8 +++ auto/options | 6 ++ auto/sources | 4 + src/core/ngx_core.h | 4 +- src/core/ngx_status.c | 166 +++++++++++++++++++++++++++++++++++++++++++++++++ src/core/ngx_status.h | 40 ++++++++++++ 6 files changed, 227 insertions(+), 1 deletions(-) create mode 100644 src/core/ngx_status.c create mode 100644 src/core/ngx_status.h diff --git a/auto/modules b/auto/modules index 9bc2e04db161cd187841bbb039f3b00026b6ccfa..d9f3dd579dbc1c9b109052eb6b7c798990927d81 100644 --- a/auto/modules +++ b/auto/modules @@ -424,6 +424,14 @@ if [ $NGX_CPP_TEST = YES ]; then fi +if [ $NGX_STATUS = YES ]; then + have=NGX_STATUS . auto/have + modules="$modules $NGX_STATUS_MODULE" + CORE_SRCS="$CORE_SRCS $NGX_STATUS_SRCS" + CORE_DEPS="$CORE_DEPS $NGX_STATUS_DEPS" +fi + + cat << END > $NGX_MODULES_C #include diff --git a/auto/options b/auto/options index 3b3ee0fae8093fecba53d69343adf592b24217ca..b48f1fba2ad3b4ae9874996873412dbe7ca89dc6 100644 --- a/auto/options +++ b/auto/options @@ -131,6 +131,8 @@ NGX_CPP_TEST=NO NGX_CPU_CACHE_LINE= +NGX_STATUS=YES + opt= for option @@ -260,6 +262,8 @@ do --with-zlib-opt=*) ZLIB_OPT="$value" ;; --with-zlib-asm=*) ZLIB_ASM="$value" ;; + --without-status) NGX_STATUS=NO ;; + --test-build-devpoll) NGX_TEST_BUILD_DEVPOLL=YES ;; --test-build-eventport) NGX_TEST_BUILD_EVENTPORT=YES ;; --test-build-epoll) NGX_TEST_BUILD_EPOLL=YES ;; @@ -394,6 +398,8 @@ cat << END --with-openssl=DIR set path to OpenSSL library sources --with-openssl-opt=OPTIONS set additional options for OpenSSL building + --without-status disable status + --with-debug enable the debugging logging END diff --git a/auto/sources b/auto/sources index e4649b030eaa64d005f4af07435f40dfe671ebd4..eb72a0a3618118df2680df1bd07856f6ea5a3957 100644 --- a/auto/sources +++ b/auto/sources @@ -484,3 +484,7 @@ NGX_GOOGLE_PERFTOOLS_MODULE=ngx_google_perftools_module NGX_GOOGLE_PERFTOOLS_SRCS=src/misc/ngx_google_perftools_module.c NGX_CPP_TEST_SRCS=src/misc/ngx_cpp_test_module.cpp + +NGX_STATUS_MODULE=ngx_status_module +NGX_STATUS_SRCS=src/core/ngx_status.c +NGX_STATUS_DEPS=src/core/ngx_status.h diff --git a/src/core/ngx_core.h b/src/core/ngx_core.h index d5f18b84c2ac40e72aaef7d2f2429fe3aa5fac37..e4b07aadabdec7135df3a0ca3994cf7be8035c54 100644 --- a/src/core/ngx_core.h +++ b/src/core/ngx_core.h @@ -75,7 +75,9 @@ typedef void (*ngx_connection_handler_pt)(ngx_connection_t *c); #include #include #include - +#if (NGX_PCRE) +#include +#endif #define LF (u_char) 10 #define CR (u_char) 13 diff --git a/src/core/ngx_status.c b/src/core/ngx_status.c new file mode 100644 index 0000000000000000000000000000000000000000..68c6f4b0200bf70da1dad7c34b7f98be322a5f48 --- /dev/null +++ b/src/core/ngx_status.c @@ -0,0 +1,166 @@ + +/* + * Copyright (C) Kirill A. Korinskiy + */ + + +#include +#include + + +static void *ngx_status_module_create_conf(ngx_cycle_t *cycle); + +static ngx_int_t ngx_status_module_init(ngx_cycle_t *cycle); + +typedef struct { + ngx_uint_t count; + ngx_status_list_t **counters; +} ngx_status_conf_t; + +static ngx_core_module_t ngx_status_module_ctx = { + ngx_string("ngx_status"), + ngx_status_module_create_conf, + NULL +}; + + +ngx_module_t ngx_status_module = { + NGX_MODULE_V1, + &ngx_status_module_ctx, /* module context */ + NULL, /* module directives */ + NGX_CORE_MODULE, /* module type */ + NULL, /* init master */ + ngx_status_module_init, /* init module */ + NULL, /* init process */ + NULL, /* init thread */ + NULL, /* exit thread */ + NULL, /* exit process */ + NULL, /* exit master */ + NGX_MODULE_V1_PADDING +}; + + +ngx_int_t +ngx_status_add_counter(ngx_cycle_t *cycle, ngx_module_t *module, + ngx_status_counter_t *counter) +{ + ngx_status_conf_t *conf; + ngx_status_list_t *c, *cc; + + conf = (ngx_status_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_status_module); + + c = ngx_palloc(cycle->pool, sizeof(ngx_status_list_t)); + if (c == NULL) { + return NGX_ERROR; + } + + c->counter = counter; + c->next = NULL; + + if (conf->counters[module->index] == NULL) { + conf->counters[module->index] = c; + } else { + cc = conf->counters[module->index]; + + for (; cc->next; cc = cc->next); + + cc->next = c; + } + + conf->count++; + + return NGX_OK; +} + + +ngx_int_t +ngx_status_fetch_add(ngx_status_counter_t *counter) +{ + ngx_atomic_fetch_add(counter->value, 1); + + return NGX_OK; +} + + +ngx_int_t +ngx_status_get_value(ngx_status_counter_t *counter) +{ + return *(counter->value); +} + + +ngx_status_list_t ** +ngx_status_get_counters(ngx_cycle_t *cycle) +{ + return ((ngx_status_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_status_module))->counters; +} + + +static void * +ngx_status_module_create_conf(ngx_cycle_t *cycle) +{ + ngx_status_conf_t *conf; + ngx_uint_t i; + + conf = ngx_pcalloc(cycle->pool, sizeof(ngx_status_conf_t)); + if (conf == NULL) { + return NULL; + } + + for (i = 0; ngx_modules[i]; i++); + + conf->counters = ngx_pcalloc(cycle->pool, sizeof(ngx_status_list_t) * i); + if (conf->counters == NULL) { + return NULL; + } + + conf->count = 0; + + return conf; +} + + +static ngx_int_t +ngx_status_module_init(ngx_cycle_t *cycle) +{ + u_char *shared; + size_t size, cl; + ngx_shm_t shm; + ngx_uint_t i, j; + ngx_status_conf_t *conf; + ngx_status_list_t *c; + + conf = (ngx_status_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_status_module); + + if (!conf->count) { + return NGX_OK; + } + + /* cl should be equal or bigger than cache line size */ + cl = 128; + + size = conf->count * cl; + + shm.size = size; + shm.name.len = sizeof("nginx_status_shared_zone"); + shm.name.data = (u_char *) "nginx_status_shared_zone"; + shm.log = cycle->log; + + if (ngx_shm_alloc(&shm) != NGX_OK) { + return NGX_ERROR; + } + + shared = shm.addr; + + for (i = 0, j = 0; ngx_modules[i]; i++) { + c = conf->counters[ngx_modules[i]->index]; + + while (c) { + c->counter->value = (ngx_atomic_t *)(shared + (j * cl)); + j++; + c = c->next; + } + } + + return NGX_OK; +} diff --git a/src/core/ngx_status.h b/src/core/ngx_status.h new file mode 100644 index 0000000000000000000000000000000000000000..2b881a36bdebae0d8e83e8a48aef939531e977df --- /dev/null +++ b/src/core/ngx_status.h @@ -0,0 +1,40 @@ + +/* + * Copyright (C) Kirill A. Korinskiy + */ + + +#ifndef _NGX_STATUS_H_INCLUDED_ +#define _NGX_STATUS_H_INCLUDED_ + + +#include +#include + + +typedef struct ngx_status_list_s ngx_status_list_t; + +typedef struct { + ngx_str_t name; + ngx_str_t caption; + ngx_atomic_t *value; +} ngx_status_counter_t; + +struct ngx_status_list_s { + ngx_status_counter_t *counter; + ngx_status_list_t *next; +}; + +extern ngx_module_t ngx_status_module; + + +ngx_int_t ngx_status_add_counter(ngx_cycle_t *cycle, ngx_module_t *module, + ngx_status_counter_t *counter); + +ngx_int_t ngx_status_fetch_add(ngx_status_counter_t *counter); +ngx_int_t ngx_status_get_value(ngx_status_counter_t *counter); + +ngx_status_list_t **ngx_status_get_counters(ngx_cycle_t *cycle); + + +#endif /* _NGX_STATUS_H_INCLUDED_ */ -- 1.6.2 From da9c9cf9dea103b3abe9870a597d6217a89c4d61 Mon Sep 17 00:00:00 2001 From: Kirill A. Korinskiy Date: Fri, 15 May 2009 20:58:05 +0400 Subject: [PATCH 2/5] Add simple implement of status_txt Cc: catap@catap.ru --- auto/modules | 7 + auto/options | 3 + auto/sources | 3 + src/http/modules/ngx_http_status_txt_module.c | 222 +++++++++++++++++++++++++ 4 files changed, 235 insertions(+), 0 deletions(-) create mode 100644 src/http/modules/ngx_http_status_txt_module.c diff --git a/auto/modules b/auto/modules index d9f3dd579dbc1c9b109052eb6b7c798990927d81..72cb16b4f3790e2f3a31ee2d1e81c8c88d8b690b 100644 --- a/auto/modules +++ b/auto/modules @@ -325,6 +325,13 @@ if [ $HTTP_STUB_STATUS = YES ]; then HTTP_SRCS="$HTTP_SRCS src/http/modules/ngx_http_stub_status_module.c" fi +if [ $NGX_STATUS = YES ]; then + if [ $HTTP_STATUS_TXT = YES ]; then + HTTP_MODULES="$HTTP_MODULES $HTTP_STATUS_TXT_MODULE" + HTTP_SRCS="$HTTP_SRCS $HTTP_STATUS_TXT_SRCS" + fi +fi + #if [ -r $NGX_OBJS/auto ]; then # . $NGX_OBJS/auto #fi diff --git a/auto/options b/auto/options index b48f1fba2ad3b4ae9874996873412dbe7ca89dc6..3c2b2b5abed383641a68b922431384c5f54de1da 100644 --- a/auto/options +++ b/auto/options @@ -132,6 +132,7 @@ NGX_CPP_TEST=NO NGX_CPU_CACHE_LINE= NGX_STATUS=YES +HTTP_STATUS_TXT=YES opt= @@ -263,6 +264,7 @@ do --with-zlib-asm=*) ZLIB_ASM="$value" ;; --without-status) NGX_STATUS=NO ;; + --without-http_status_txt) NGX_HTTP_STATUS_TXT=NO ;; --test-build-devpoll) NGX_TEST_BUILD_DEVPOLL=YES ;; --test-build-eventport) NGX_TEST_BUILD_EVENTPORT=YES ;; @@ -399,6 +401,7 @@ cat << END --with-openssl-opt=OPTIONS set additional options for OpenSSL building --without-status disable status + --without-http_status_txt disable http_status_txt --with-debug enable the debugging logging diff --git a/auto/sources b/auto/sources index eb72a0a3618118df2680df1bd07856f6ea5a3957..cd3f2ae94f20377fef751da8c262016e1c99d14c 100644 --- a/auto/sources +++ b/auto/sources @@ -488,3 +488,6 @@ NGX_CPP_TEST_SRCS=src/misc/ngx_cpp_test_module.cpp NGX_STATUS_MODULE=ngx_status_module NGX_STATUS_SRCS=src/core/ngx_status.c NGX_STATUS_DEPS=src/core/ngx_status.h + +HTTP_STATUS_TXT_MODULE=ngx_http_status_txt_module +HTTP_STATUS_TXT_SRCS=src/http/modules/ngx_http_status_txt_module.c diff --git a/src/http/modules/ngx_http_status_txt_module.c b/src/http/modules/ngx_http_status_txt_module.c new file mode 100644 index 0000000000000000000000000000000000000000..9a2486ff8c43f170cf1e0441822f80fbaa0ec16c --- /dev/null +++ b/src/http/modules/ngx_http_status_txt_module.c @@ -0,0 +1,222 @@ + +/* + * Copyright (C) Kirill A. Korinskiy + */ + + +#include +#include +#include +#include + + +static char *ngx_http_status_txt(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); + +static ngx_command_t ngx_http_status_commands[] = { + + { ngx_string("status_txt"), + NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_http_status_txt, + 0, + 0, + NULL }, + + ngx_null_command +}; + + + +static ngx_http_module_t ngx_http_status_txt_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_status_txt_module = { + NGX_MODULE_V1, + &ngx_http_status_txt_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_time_t last_configure; +static ngx_str_t last_configure_human_time; + + +static ngx_int_t ngx_http_status_txt_handler(ngx_http_request_t *r) +{ + size_t size; + ngx_int_t rc; + ngx_buf_t *b; + ngx_uint_t i; + ngx_chain_t out; + + ngx_status_list_t **counters, *c; + + ngx_http_core_srv_conf_t *cscf; + + ngx_uint_t uptime, uptime_days, uptime_hours, uptime_minutes, uptime_seconds; + + 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; + } + + cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); + if (cscf == NULL) { + return NGX_ERROR; + } + + uptime = ngx_time() - last_configure.sec; + uptime_days = uptime / 86400; + uptime -= uptime_days * 86400; + uptime_hours = uptime / 3600; + uptime -= uptime_hours * 3600; + uptime_minutes = uptime / 60; + uptime -= uptime_minutes * 60; + uptime_seconds = uptime; + uptime = ngx_time() - last_configure.sec; + + + counters = ngx_status_get_counters((ngx_cycle_t *)ngx_cycle); + + r->headers_out.content_type.len = sizeof("text/plain") - 1; + r->headers_out.content_type.data = (u_char *) "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("Server " NGINX_VER " \n") - 1 + + cscf->server_name.len + + sizeof("Last config reload: ()\n") - 1 + NGX_INT_T_LEN + + last_configure_human_time.len + + sizeof("Uptime: (d h m s)\n") - 1 + NGX_INT_T_LEN + + NGX_INT_T_LEN + NGX_INT_T_LEN + NGX_INT_T_LEN + NGX_INT_T_LEN; + + for (i = 0; ngx_modules[i]; i++) { + c = counters[ngx_modules[i]->index]; + + if (c == NULL) { + continue; + } + + size += sizeof("\n") - 1; + + while (c) { + size += c->counter->caption.len + sizeof(": \n") - 1 + NGX_INT_T_LEN; + c = c->next; + } + } + + + b = ngx_create_temp_buf(r->pool, size); + if (b == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + out.buf = b; + out.next = NULL; + + b->last = ngx_sprintf(b->last, "Server " NGINX_VER " %V\n", + &cscf->server_name); + + b->last = ngx_sprintf(b->last, "Last config reload: %uA (%V)\n", + last_configure.sec, + &last_configure_human_time); + + b->last = ngx_sprintf(b->last, "Uptime: %uA (%uAd %uAh %uAm %uAs)\n", + uptime, uptime_days, uptime_hours, + uptime_minutes, uptime_seconds); + + for (i = 0; ngx_modules[i]; i++) { + c = counters[ngx_modules[i]->index]; + + if (c == NULL) { + continue; + } + + b->last = ngx_sprintf(b->last, "\n"); + + while (c) { + b->last = ngx_sprintf(b->last, "%V: %uA\n", + &c->counter->caption, ngx_status_get_value(c->counter)); + c = c->next; + } + } + + 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 *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; + + +static char *ngx_http_status_txt(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_tm_t tm; + 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_txt_handler; + + last_configure = *ngx_cached_time; + last_configure_human_time.len = sizeof("28/Sep/1970 12:00:00 +0600") - 1; + last_configure_human_time.data = ngx_palloc(cf->pool, last_configure_human_time.len); + if (last_configure_human_time.data == NULL) { + return NGX_CONF_ERROR; + } + + ngx_gmtime(ngx_cached_time->sec + ngx_cached_time->gmtoff * 60, &tm); + + (void) ngx_sprintf(last_configure_human_time.data, + "%02d/%s/%d %02d:%02d:%02d %c%02d%02d", + tm.ngx_tm_mday, months[tm.ngx_tm_mon - 1], + tm.ngx_tm_year, tm.ngx_tm_hour, + tm.ngx_tm_min, tm.ngx_tm_sec, + ngx_cached_time->gmtoff < 0 ? '-' : '+', + ngx_abs(ngx_cached_time->gmtoff / 60), + ngx_abs(ngx_cached_time->gmtoff % 60)); + + return NGX_CONF_OK; +} -- 1.6.2 From 1c6a049c0240efccd68c58065c84990c4f671436 Mon Sep 17 00:00:00 2001 From: Kirill A. Korinskiy Date: Sat, 16 May 2009 10:17:18 +0400 Subject: [PATCH 3/5] Add information from classic nginx status to new status Cc: catap@catap.ru --- src/event/ngx_event.c | 6 +++--- src/event/ngx_event.h | 2 +- src/event/ngx_event_accept.c | 8 ++++---- src/http/modules/ngx_http_status_txt_module.c | 25 +++++++++++++++++++++++++ src/http/ngx_http_request.c | 18 +++++++++--------- src/http/ngx_http_request.h | 2 +- src/mail/ngx_mail_handler.c | 2 +- 7 files changed, 44 insertions(+), 19 deletions(-) diff --git a/src/event/ngx_event.c b/src/event/ngx_event.c index e30c5636a7201bdeb39d20414a8770b3c069b120..dac0c01f7651719e3e7ac06c3f589281b5c7d186 100644 --- a/src/event/ngx_event.c +++ b/src/event/ngx_event.c @@ -57,7 +57,7 @@ ngx_int_t ngx_accept_disabled; ngx_file_t ngx_accept_mutex_lock_file; -#if (NGX_STAT_STUB) +#if (NGX_STAT_STUB) || (NGX_STATUS) ngx_atomic_t ngx_stat_accepted0; ngx_atomic_t *ngx_stat_accepted = &ngx_stat_accepted0; @@ -494,7 +494,7 @@ ngx_event_module_init(ngx_cycle_t *cycle) size = cl /* ngx_accept_mutex */ + cl; /* ngx_connection_counter */ -#if (NGX_STAT_STUB) +#if (NGX_STAT_STUB) || (NGX_STATUS) size += cl /* ngx_stat_accepted */ + cl /* ngx_stat_handled */ @@ -526,7 +526,7 @@ ngx_event_module_init(ngx_cycle_t *cycle) ngx_connection_counter = (ngx_atomic_t *) (shared + 1 * cl); -#if (NGX_STAT_STUB) +#if (NGX_STAT_STUB) || (NGX_STATUS) ngx_stat_accepted = (ngx_atomic_t *) (shared + 2 * cl); ngx_stat_handled = (ngx_atomic_t *) (shared + 3 * cl); diff --git a/src/event/ngx_event.h b/src/event/ngx_event.h index 33c8cdc2d7d9bdac5b12228540a2467c4a61b0b9..791beaac3ebcbb368bc87f67fb72ed777131d8c2 100644 --- a/src/event/ngx_event.h +++ b/src/event/ngx_event.h @@ -477,7 +477,7 @@ extern ngx_msec_t ngx_accept_mutex_delay; extern ngx_int_t ngx_accept_disabled; -#if (NGX_STAT_STUB) +#if (NGX_STAT_STUB) || (NGX_STATUS) extern ngx_atomic_t *ngx_stat_accepted; extern ngx_atomic_t *ngx_stat_handled; diff --git a/src/event/ngx_event_accept.c b/src/event/ngx_event_accept.c index a17d6303839b33e0a7ea130043ec5dfac69bdd8a..bc75a5adaa3d3e07b55ad4cc78bc2aff0d3f9e59 100644 --- a/src/event/ngx_event_accept.c +++ b/src/event/ngx_event_accept.c @@ -74,7 +74,7 @@ ngx_event_accept(ngx_event_t *ev) return; } -#if (NGX_STAT_STUB) +#if (NGX_STAT_STUB) || (NGX_STATUS) ngx_atomic_fetch_add(ngx_stat_accepted, 1); #endif @@ -92,7 +92,7 @@ ngx_event_accept(ngx_event_t *ev) return; } -#if (NGX_STAT_STUB) +#if (NGX_STAT_STUB) || (NGX_STATUS) ngx_atomic_fetch_add(ngx_stat_active, 1); #endif @@ -187,7 +187,7 @@ ngx_event_accept(ngx_event_t *ev) c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1); -#if (NGX_STAT_STUB) +#if (NGX_STAT_STUB) || (NGX_STATUS) ngx_atomic_fetch_add(ngx_stat_handled, 1); #endif @@ -378,7 +378,7 @@ ngx_close_accepted_connection(ngx_connection_t *c) ngx_destroy_pool(c->pool); } -#if (NGX_STAT_STUB) +#if (NGX_STAT_STUB) || (NGX_STATUS) ngx_atomic_fetch_add(ngx_stat_active, -1); #endif } diff --git a/src/http/modules/ngx_http_status_txt_module.c b/src/http/modules/ngx_http_status_txt_module.c index 9a2486ff8c43f170cf1e0441822f80fbaa0ec16c..e5a37e1049ef56f27a79b2e78b0776aada50c986 100644 --- a/src/http/modules/ngx_http_status_txt_module.c +++ b/src/http/modules/ngx_http_status_txt_module.c @@ -69,6 +69,8 @@ static ngx_int_t ngx_http_status_txt_handler(ngx_http_request_t *r) ngx_uint_t i; ngx_chain_t out; + ngx_atomic_int_t ap, hn, ac, rq, rd, wr; + ngx_status_list_t **counters, *c; ngx_http_core_srv_conf_t *cscf; @@ -123,6 +125,11 @@ static ngx_int_t ngx_http_status_txt_handler(ngx_http_request_t *r) + sizeof("Uptime: (d h m s)\n") - 1 + NGX_INT_T_LEN + NGX_INT_T_LEN + NGX_INT_T_LEN + NGX_INT_T_LEN + NGX_INT_T_LEN; + size += sizeof("\nActive 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; + for (i = 0; ngx_modules[i]; i++) { c = counters[ngx_modules[i]->index]; @@ -158,6 +165,24 @@ static ngx_int_t ngx_http_status_txt_handler(ngx_http_request_t *r) uptime, uptime_days, uptime_hours, uptime_minutes, uptime_seconds); + 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, "\nActive 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)); + + for (i = 0; ngx_modules[i]; i++) { c = counters[ngx_modules[i]->index]; diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 32f120c8e9cbb349712980a8eacc94090c7a1ca0..543a434227c88e1135765c05f04cf2769899c4c7 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -197,7 +197,7 @@ ngx_http_init_connection(ngx_connection_t *c) rev->handler = ngx_http_init_request; c->write->handler = ngx_http_empty_handler; -#if (NGX_STAT_STUB) +#if (NGX_STAT_STUB) || (NGX_STATUS) ngx_atomic_fetch_add(ngx_stat_reading, 1); #endif @@ -216,7 +216,7 @@ ngx_http_init_connection(ngx_connection_t *c) ngx_add_timer(rev, c->listening->post_accept_timeout); if (ngx_handle_read_event(rev, 0) != NGX_OK) { -#if (NGX_STAT_STUB) +#if (NGX_STAT_STUB) || (NGX_STATUS) ngx_atomic_fetch_add(ngx_stat_reading, -1); #endif ngx_http_close_connection(c); @@ -246,7 +246,7 @@ ngx_http_init_request(ngx_event_t *rev) ngx_http_in6_addr_t *addr6; #endif -#if (NGX_STAT_STUB) +#if (NGX_STAT_STUB) || (NGX_STATUS) ngx_atomic_fetch_add(ngx_stat_reading, -1); #endif @@ -494,7 +494,7 @@ ngx_http_init_request(ngx_event_t *rev) ctx->current_request = r; r->log_handler = ngx_http_log_error_handler; -#if (NGX_STAT_STUB) +#if (NGX_STAT_STUB) || (NGX_STATUS) ngx_atomic_fetch_add(ngx_stat_reading, 1); r->stat_reading = 1; ngx_atomic_fetch_add(ngx_stat_requests, 1); @@ -1541,7 +1541,7 @@ ngx_http_process_request(ngx_http_request_t *r) ngx_del_timer(c->read); } -#if (NGX_STAT_STUB) +#if (NGX_STAT_STUB) || (NGX_STATUS) ngx_atomic_fetch_add(ngx_stat_reading, -1); r->stat_reading = 0; ngx_atomic_fetch_add(ngx_stat_writing, 1); @@ -2308,7 +2308,7 @@ ngx_http_set_keepalive(ngx_http_request_t *r) ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "pipelined request"); -#if (NGX_STAT_STUB) +#if (NGX_STAT_STUB) || (NGX_STATUS) ngx_atomic_fetch_add(ngx_stat_reading, 1); #endif @@ -2538,7 +2538,7 @@ ngx_http_keepalive_handler(ngx_event_t *rev) b->last += n; -#if (NGX_STAT_STUB) +#if (NGX_STAT_STUB) || (NGX_STATUS) ngx_atomic_fetch_add(ngx_stat_reading, 1); #endif @@ -2765,7 +2765,7 @@ ngx_http_request_done(ngx_http_request_t *r, ngx_int_t error) } } -#if (NGX_STAT_STUB) +#if (NGX_STAT_STUB) || (NGX_STATUS) if (r->stat_reading) { ngx_atomic_fetch_add(ngx_stat_reading, -1); @@ -2852,7 +2852,7 @@ ngx_http_close_connection(ngx_connection_t *c) #endif -#if (NGX_STAT_STUB) +#if (NGX_STAT_STUB) || (NGX_STATUS) ngx_atomic_fetch_add(ngx_stat_active, -1); #endif diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h index 4fef7c36cab74b4609407f81c32e94e9d0731b48..0d62cf9b27067fd866254c00406f9a45c56ae19f 100644 --- a/src/http/ngx_http_request.h +++ b/src/http/ngx_http_request.h @@ -496,7 +496,7 @@ struct ngx_http_request_s { unsigned filter_need_temporary:1; unsigned allow_ranges:1; -#if (NGX_STAT_STUB) +#if (NGX_STAT_STUB) || (NGX_STATUS) unsigned stat_reading:1; unsigned stat_writing:1; #endif diff --git a/src/mail/ngx_mail_handler.c b/src/mail/ngx_mail_handler.c index 44ebdede23a21ab524751779b360a776b68bb37e..a44a1035a87a473ae1d5d4d39b8d2b2b878fd7da 100644 --- a/src/mail/ngx_mail_handler.c +++ b/src/mail/ngx_mail_handler.c @@ -673,7 +673,7 @@ ngx_mail_close_connection(ngx_connection_t *c) #endif -#if (NGX_STAT_STUB) +#if (NGX_STAT_STUB) || (NGX_STATUS) ngx_atomic_fetch_add(ngx_stat_active, -1); #endif -- 1.6.2 From 7db8f438953e1a79c5062a1ac6797deba8aedde8 Mon Sep 17 00:00:00 2001 From: Kirill A. Korinskiy Date: Fri, 15 May 2009 16:50:42 +0400 Subject: [PATCH 4/5] Implement support to status API in http core module Cc: catap@catap.ru --- src/http/ngx_http_core_module.c | 126 +++++++++++++++++++++++++++++++++++++++ src/http/ngx_http_core_module.h | 8 +++ src/http/ngx_http_request.c | 5 ++ 3 files changed, 139 insertions(+), 0 deletions(-) diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c index 73d7af96934db865d855506ca53483b88ec53c39..a23882799f00d2dfccd68c333cf164767f9ec9ff 100644 --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -838,6 +838,10 @@ ngx_http_core_find_config_phase(ngx_http_request_t *r, clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); +#if (NGX_STATUS) + ngx_status_fetch_add(clcf->request_counter); +#endif + if (!r->internal && clcf->internal) { ngx_http_finalize_request(r, NGX_HTTP_NOT_FOUND); return NGX_OK; @@ -2398,6 +2402,59 @@ ngx_http_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy) *cf = pcf; +#if (NGX_STATUS) + cscf->request_counter = + ngx_pcalloc(cf->pool, sizeof(ngx_status_counter_t)); + if (cscf->request_counter == NULL) { + return NGX_CONF_ERROR; + } + + cscf->request_counter->name.len = sizeof("request_host_") - 1; + cscf->request_counter->caption.len = sizeof("Request for host ") - 1; + + if (cscf->server_name.len) { + cscf->request_counter->name.len += cscf->server_name.len; + cscf->request_counter->caption.len += cscf->server_name.len; + } else { + cscf->request_counter->name.len += sizeof("default") - 1; + cscf->request_counter->caption.len += sizeof("default") - 1; + } + + cscf->request_counter->name.data = + ngx_palloc(cf->pool, cscf->request_counter->name.len); + if (cscf->request_counter->name.data == NULL) { + return NGX_CONF_ERROR; + } + + cscf->request_counter->caption.data = + ngx_palloc(cf->pool, cscf->request_counter->caption.len); + if (cscf->request_counter->caption.data == NULL) { + return NGX_CONF_ERROR; + } + + if (cscf->server_name.len) { + ngx_sprintf(cscf->request_counter->name.data, + "request_host_%V", + &cscf->server_name); + + ngx_sprintf(cscf->request_counter->caption.data, + "Request for host %V", + &cscf->server_name); + } else { + ngx_sprintf(cscf->request_counter->name.data, + "request_host_default"); + + ngx_sprintf(cscf->request_counter->caption.data, + "Request for host default"); + } + + if (ngx_status_add_counter(cf->cycle, &ngx_http_module, + cscf->request_counter) != NGX_OK) { + return NGX_CONF_ERROR; + } + +#endif + return rv; } @@ -2414,6 +2471,9 @@ ngx_http_core_location(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy) ngx_http_module_t *module; ngx_http_conf_ctx_t *ctx, *pctx; ngx_http_core_loc_conf_t *clcf, *pclcf; +#if (NGX_STATUS) + ngx_http_core_srv_conf_t *cscf; +#endif ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t)); if (ctx == NULL) { @@ -2592,6 +2652,63 @@ ngx_http_core_location(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy) *cf = save; +#if (NGX_STATUS) + cscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_core_module); + + clcf->request_counter = + ngx_pcalloc(cf->pool, sizeof(ngx_status_counter_t)); + if (clcf->request_counter == NULL) { + return NGX_CONF_ERROR; + } + + clcf->request_counter->name.len = sizeof("request_host__location_") - 1 + + clcf->name.len; + clcf->request_counter->caption.len = sizeof("Request for host , Location ") - 1 + + clcf->name.len; + + if (cscf->server_name.len) { + clcf->request_counter->name.len += cscf->server_name.len; + clcf->request_counter->caption.len += cscf->server_name.len; + } else { + clcf->request_counter->name.len += sizeof("default") - 1; + clcf->request_counter->caption.len += sizeof("default") - 1; + } + + clcf->request_counter->name.data = + ngx_palloc(cf->pool, clcf->request_counter->name.len); + if (clcf->request_counter->name.data == NULL) { + return NGX_CONF_ERROR; + } + + clcf->request_counter->caption.data = + ngx_palloc(cf->pool, clcf->request_counter->caption.len); + if (clcf->request_counter->caption.data == NULL) { + return NGX_CONF_ERROR; + } + + if (cscf->server_name.len) { + ngx_sprintf(clcf->request_counter->name.data, + "request_host_%V_location_%V", + &cscf->server_name, &clcf->name); + + ngx_sprintf(clcf->request_counter->caption.data, + "Request for host %V, Location %V", + &cscf->server_name, &clcf->name); + } else { + ngx_sprintf(clcf->request_counter->name.data, + "request_host_default_location_%V", &clcf->name); + + ngx_sprintf(clcf->request_counter->caption.data, + "Request for host default, Location %V", &clcf->name); + } + + if (ngx_status_add_counter(cf->cycle, &ngx_http_module, + clcf->request_counter) != NGX_OK) { + return NGX_CONF_ERROR; + } + +#endif + return rv; } @@ -2946,6 +3063,7 @@ ngx_http_core_create_loc_conf(ngx_conf_t *cf) * lcf->auto_redirect = 0; * lcf->alias = 0; * lcf->gzip_proxied = 0; + * lcf->request_counter = NULL; */ lcf->client_max_body_size = NGX_CONF_UNSET; @@ -3243,6 +3361,14 @@ ngx_http_core_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) #endif +#if (NGX_STATUS) + if (prev->request_counter) { + + conf->request_counter = prev->request_counter; + + } +#endif + return NGX_CONF_OK; } diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h index 2c4e45acd2da5260654552ec05a306d9ac822fb0..cfe2e642cea1a22062f5740a09ecfd14b2b23886 100644 --- a/src/http/ngx_http_core_module.h +++ b/src/http/ngx_http_core_module.h @@ -168,6 +168,10 @@ typedef struct { ngx_flag_t underscores_in_headers; ngx_http_core_loc_conf_t **named_locations; + +#if (NGX_STATUS) + ngx_status_counter_t *request_counter; +#endif } ngx_http_core_srv_conf_t; @@ -384,6 +388,10 @@ struct ngx_http_core_loc_conf_s { ngx_queue_t *locations; +#if (NGX_STATUS) + ngx_status_counter_t *request_counter; +#endif + #if 0 ngx_http_core_loc_conf_t *prev_location; #endif diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 543a434227c88e1135765c05f04cf2769899c4c7..ccc4d82de0f4bc16ea62bc7c89ec0b46ced38f82 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -500,6 +500,11 @@ ngx_http_init_request(ngx_event_t *rev) ngx_atomic_fetch_add(ngx_stat_requests, 1); #endif +#if (NGX_STATUS) + ngx_status_fetch_add(cscf->request_counter); +#endif + + rev->handler(rev); } -- 1.6.2 From 727c25106d973ea77e11f916923a794acd377eb2 Mon Sep 17 00:00:00 2001 From: Kirill A. Korinskiy Date: Mon, 18 May 2009 00:55:54 +0400 Subject: [PATCH 5/5] Implement periodic counter Cc: catap@catap.ru Add directive `status_window' Extend formats fot directive `status_txt' --- src/core/ngx_status.c | 138 ++++++++++++++++++----- src/core/ngx_status.h | 8 +- src/http/modules/ngx_http_status_txt_module.c | 149 ++++++++++++++++++++----- 3 files changed, 234 insertions(+), 61 deletions(-) diff --git a/src/core/ngx_status.c b/src/core/ngx_status.c index 68c6f4b0200bf70da1dad7c34b7f98be322a5f48..2517cf9055c4e5714d2b35fca0b6ab3910a6e11c 100644 --- a/src/core/ngx_status.c +++ b/src/core/ngx_status.c @@ -9,25 +9,41 @@ static void *ngx_status_module_create_conf(ngx_cycle_t *cycle); +static char *ngx_status_module_init_conf(ngx_cycle_t *cycle, void *conf); static ngx_int_t ngx_status_module_init(ngx_cycle_t *cycle); typedef struct { + ngx_uint_t window; ngx_uint_t count; ngx_status_list_t **counters; } ngx_status_conf_t; + +static ngx_command_t ngx_status_commands[] = { + + { ngx_string("status_window"), + NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + 0, + offsetof(ngx_status_conf_t, window), + NULL }, + + ngx_null_command +}; + + static ngx_core_module_t ngx_status_module_ctx = { ngx_string("ngx_status"), ngx_status_module_create_conf, - NULL + ngx_status_module_init_conf }; ngx_module_t ngx_status_module = { NGX_MODULE_V1, &ngx_status_module_ctx, /* module context */ - NULL, /* module directives */ + ngx_status_commands, /* module directives */ NGX_CORE_MODULE, /* module type */ NULL, /* init master */ ngx_status_module_init, /* init module */ @@ -51,20 +67,20 @@ ngx_status_add_counter(ngx_cycle_t *cycle, ngx_module_t *module, c = ngx_palloc(cycle->pool, sizeof(ngx_status_list_t)); if (c == NULL) { - return NGX_ERROR; + return NGX_ERROR; } c->counter = counter; c->next = NULL; if (conf->counters[module->index] == NULL) { - conf->counters[module->index] = c; + conf->counters[module->index] = c; } else { - cc = conf->counters[module->index]; + cc = conf->counters[module->index]; - for (; cc->next; cc = cc->next); + for (; cc->next; cc = cc->next); - cc->next = c; + cc->next = c; } conf->count++; @@ -76,47 +92,109 @@ ngx_status_add_counter(ngx_cycle_t *cycle, ngx_module_t *module, ngx_int_t ngx_status_fetch_add(ngx_status_counter_t *counter) { - ngx_atomic_fetch_add(counter->value, 1); + ngx_atomic_t *window; + ngx_status_conf_t *conf; + + conf = (ngx_status_conf_t *) ngx_get_conf(ngx_cycle->conf_ctx, + ngx_status_module); + + window = counter->windows + (ngx_time() % (2 * conf->window)); + + ngx_atomic_fetch_add(window, 1); + + if (window - conf->window > counter->windows) { + *(window - conf->window) = 0; + } else { + *(window + conf->window) = 0; + } + + ngx_atomic_fetch_add(counter->accumulate, 1); return NGX_OK; } ngx_int_t -ngx_status_get_value(ngx_status_counter_t *counter) +ngx_status_get_accumulate_value(ngx_status_counter_t *counter) { - return *(counter->value); + return *(counter->accumulate); +} + + +ngx_int_t +ngx_status_get_periodic_value(ngx_status_counter_t *counter, ngx_uint_t period) +{ + ngx_int_t sum ; + ngx_atomic_t *start, *last; + ngx_status_conf_t *conf; + + + conf = (ngx_status_conf_t *) + ngx_get_conf(ngx_cycle->conf_ctx, ngx_status_module); + + if (period > conf->window) { + period = conf->window; + } + + sum = 0; + last = counter->windows + 2 * conf->window; + start = counter->windows + (ngx_time() % (2 * conf->window)); + + for (; period; period--) { + sum += *start; + if (start - 1 < counter->windows) { + start = last; + } else { + start--; + } + } + + return sum; } ngx_status_list_t ** ngx_status_get_counters(ngx_cycle_t *cycle) { - return ((ngx_status_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_status_module))->counters; + return ((ngx_status_conf_t *) + ngx_get_conf(cycle->conf_ctx, ngx_status_module))->counters; } static void * ngx_status_module_create_conf(ngx_cycle_t *cycle) { - ngx_status_conf_t *conf; + ngx_status_conf_t *scf; ngx_uint_t i; - conf = ngx_pcalloc(cycle->pool, sizeof(ngx_status_conf_t)); - if (conf == NULL) { - return NULL; + scf = ngx_pcalloc(cycle->pool, sizeof(ngx_status_conf_t)); + if (scf == NULL) { + return NULL; } + scf->window = NGX_CONF_UNSET_UINT; + for (i = 0; ngx_modules[i]; i++); - conf->counters = ngx_pcalloc(cycle->pool, sizeof(ngx_status_list_t) * i); - if (conf->counters == NULL) { - return NULL; + scf->counters = ngx_pcalloc(cycle->pool, sizeof(ngx_status_list_t) * i); + if (scf->counters == NULL) { + return NULL; } - conf->count = 0; + scf->count = 0; - return conf; + return scf; +} + + +static char * +ngx_status_module_init_conf(ngx_cycle_t *cycle, void *conf) +{ + ngx_status_conf_t *scf = conf; + + ngx_conf_init_uint_value(scf->window, 300); + + return NGX_CONF_OK; } @@ -133,13 +211,13 @@ ngx_status_module_init(ngx_cycle_t *cycle) conf = (ngx_status_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_status_module); if (!conf->count) { - return NGX_OK; + return NGX_OK; } /* cl should be equal or bigger than cache line size */ cl = 128; - size = conf->count * cl; + size = conf->count * cl + 2 * conf->window * conf->count * cl; shm.size = size; shm.name.len = sizeof("nginx_status_shared_zone"); @@ -153,13 +231,15 @@ ngx_status_module_init(ngx_cycle_t *cycle) shared = shm.addr; for (i = 0, j = 0; ngx_modules[i]; i++) { - c = conf->counters[ngx_modules[i]->index]; - - while (c) { - c->counter->value = (ngx_atomic_t *)(shared + (j * cl)); - j++; - c = c->next; - } + c = conf->counters[ngx_modules[i]->index]; + + while (c) { + c->counter->accumulate = (ngx_atomic_t *)(shared + (j * cl)); + c->counter->windows = (ngx_atomic_t *)(shared + (conf->count * cl) + + (2 * j * cl * conf->window)); + j++; + c = c->next; + } } return NGX_OK; diff --git a/src/core/ngx_status.h b/src/core/ngx_status.h index 2b881a36bdebae0d8e83e8a48aef939531e977df..dc2f159a244ef0f5c136f6734edb07584f92f7b6 100644 --- a/src/core/ngx_status.h +++ b/src/core/ngx_status.h @@ -17,7 +17,8 @@ typedef struct ngx_status_list_s ngx_status_list_t; typedef struct { ngx_str_t name; ngx_str_t caption; - ngx_atomic_t *value; + ngx_atomic_t *accumulate; + ngx_atomic_t *windows; } ngx_status_counter_t; struct ngx_status_list_s { @@ -32,7 +33,10 @@ ngx_int_t ngx_status_add_counter(ngx_cycle_t *cycle, ngx_module_t *module, ngx_status_counter_t *counter); ngx_int_t ngx_status_fetch_add(ngx_status_counter_t *counter); -ngx_int_t ngx_status_get_value(ngx_status_counter_t *counter); + +ngx_int_t ngx_status_get_accumulate_value(ngx_status_counter_t *counter); +ngx_int_t ngx_status_get_periodic_value(ngx_status_counter_t *counter, + ngx_uint_t period); ngx_status_list_t **ngx_status_get_counters(ngx_cycle_t *cycle); diff --git a/src/http/modules/ngx_http_status_txt_module.c b/src/http/modules/ngx_http_status_txt_module.c index e5a37e1049ef56f27a79b2e78b0776aada50c986..b4911ef0aeccfb12e272feb96b77b1683364d1e8 100644 --- a/src/http/modules/ngx_http_status_txt_module.c +++ b/src/http/modules/ngx_http_status_txt_module.c @@ -10,23 +10,31 @@ #include +typedef struct { + ngx_array_t *periods; +} ngx_http_status_txt_loc_conf_t; + + +static void *ngx_http_status_txt_create_loc_conf(ngx_conf_t *cf); +static char *ngx_http_status_txt_merge_loc_conf(ngx_conf_t *cf, + void *parent, void *child); + static char *ngx_http_status_txt(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static ngx_command_t ngx_http_status_commands[] = { { ngx_string("status_txt"), - NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, ngx_http_status_txt, - 0, - 0, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_status_txt_loc_conf_t, periods), NULL }, ngx_null_command }; - static ngx_http_module_t ngx_http_status_txt_module_ctx = { NULL, /* preconfiguration */ NULL, /* postconfiguration */ @@ -37,8 +45,8 @@ static ngx_http_module_t ngx_http_status_txt_module_ctx = { NULL, /* create server configuration */ NULL, /* merge server configuration */ - NULL, /* create location configuration */ - NULL /* merge location configuration */ + ngx_http_status_txt_create_loc_conf, /* create location configuration */ + ngx_http_status_txt_merge_loc_conf /* merge location configuration */ }; @@ -66,7 +74,7 @@ static ngx_int_t ngx_http_status_txt_handler(ngx_http_request_t *r) size_t size; ngx_int_t rc; ngx_buf_t *b; - ngx_uint_t i; + ngx_uint_t i, j; ngx_chain_t out; ngx_atomic_int_t ap, hn, ac, rq, rd, wr; @@ -77,6 +85,8 @@ static ngx_int_t ngx_http_status_txt_handler(ngx_http_request_t *r) ngx_uint_t uptime, uptime_days, uptime_hours, uptime_minutes, uptime_seconds; + ngx_http_status_txt_loc_conf_t *conf; + if (r->method != NGX_HTTP_GET && r->method != NGX_HTTP_HEAD) { return NGX_HTTP_NOT_ALLOWED; } @@ -87,6 +97,8 @@ static ngx_int_t ngx_http_status_txt_handler(ngx_http_request_t *r) return rc; } + conf = ngx_http_get_module_loc_conf(r, ngx_http_status_txt_module); + cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); if (cscf == NULL) { return NGX_ERROR; @@ -131,18 +143,21 @@ static ngx_int_t ngx_http_status_txt_handler(ngx_http_request_t *r) + sizeof("Reading: Writing: Waiting: \n") + 3 * NGX_ATOMIC_T_LEN; for (i = 0; ngx_modules[i]; i++) { - c = counters[ngx_modules[i]->index]; + c = counters[ngx_modules[i]->index]; - if (c == NULL) { - continue; - } + if (c == NULL) { + continue; + } - size += sizeof("\n") - 1; + size += sizeof("\n") - 1; - while (c) { - size += c->counter->caption.len + sizeof(": \n") - 1 + NGX_INT_T_LEN; - c = c->next; - } + while (c) { + size += c->counter->caption.len + sizeof(": \n") - 1 + NGX_INT_T_LEN; + c = c->next; + if (conf->periods) { + size += conf->periods->nelts * (sizeof(", ") - 1 + NGX_INT_T_LEN); + } + } } @@ -163,7 +178,7 @@ static ngx_int_t ngx_http_status_txt_handler(ngx_http_request_t *r) b->last = ngx_sprintf(b->last, "Uptime: %uA (%uAd %uAh %uAm %uAs)\n", uptime, uptime_days, uptime_hours, - uptime_minutes, uptime_seconds); + uptime_minutes, uptime_seconds); ap = *ngx_stat_accepted; hn = *ngx_stat_handled; @@ -184,19 +199,31 @@ static ngx_int_t ngx_http_status_txt_handler(ngx_http_request_t *r) for (i = 0; ngx_modules[i]; i++) { - c = counters[ngx_modules[i]->index]; + c = counters[ngx_modules[i]->index]; + + if (c == NULL) { + continue; + } + + b->last = ngx_sprintf(b->last, "\n"); - if (c == NULL) { - continue; - } + while (c) { + b->last = ngx_sprintf(b->last, "%V: %uA", + &c->counter->caption, + ngx_status_get_accumulate_value(c->counter)); + if (conf->periods) { + for (j = 0; j < conf->periods->nelts; j++) { + b->last = ngx_sprintf(b->last, ", %uA", + ngx_status_get_periodic_value( + c->counter, + ((ngx_int_t *)conf->periods->elts)[j])); + } + } - b->last = ngx_sprintf(b->last, "\n"); + b->last = ngx_sprintf(b->last, "\n"); - while (c) { - b->last = ngx_sprintf(b->last, "%V: %uA\n", - &c->counter->caption, ngx_status_get_value(c->counter)); - c = c->next; - } + c = c->next; + } } r->headers_out.status = NGX_HTTP_OK; @@ -213,21 +240,64 @@ static ngx_int_t ngx_http_status_txt_handler(ngx_http_request_t *r) return ngx_http_output_filter(r, &out); } + +static void * +ngx_http_status_txt_create_loc_conf(ngx_conf_t *cf) +{ + ngx_http_status_txt_loc_conf_t *conf; + + conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_status_txt_loc_conf_t)); + if (conf == NULL) { + return NGX_CONF_ERROR; + } + + return conf; +} + + +static char * +ngx_http_status_txt_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_http_status_txt_loc_conf_t *prev = parent; + ngx_http_status_txt_loc_conf_t *conf = child; + + if (conf->periods == NULL) { + conf->periods = prev->periods; + } + + return NGX_CONF_OK; +} + + static char *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; static char *ngx_http_status_txt(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { - ngx_tm_t tm; + u_char *p = conf; + ngx_tm_t tm; + ngx_str_t *value; + ngx_uint_t *period, i; + ngx_array_t **periods; + ngx_http_core_loc_conf_t *clcf; + periods = (ngx_array_t **) (p + cmd->offset); + + value = cf->args->elts; + + if (ngx_strcasecmp(value[1].data, (u_char *) "off") == 0) { + return NGX_CONF_OK; + } + clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); clcf->handler = ngx_http_status_txt_handler; last_configure = *ngx_cached_time; - last_configure_human_time.len = sizeof("28/Sep/1970 12:00:00 +0600") - 1; - last_configure_human_time.data = ngx_palloc(cf->pool, last_configure_human_time.len); + last_configure_human_time.len = sizeof("28/May/1987 17:30:00 +0400") - 1; + last_configure_human_time.data = ngx_palloc(cf->pool, + last_configure_human_time.len); if (last_configure_human_time.data == NULL) { return NGX_CONF_ERROR; } @@ -243,5 +313,24 @@ static char *ngx_http_status_txt(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_abs(ngx_cached_time->gmtoff / 60), ngx_abs(ngx_cached_time->gmtoff % 60)); + if (ngx_strcasecmp(value[1].data, (u_char *) "on") == 0) { + return NGX_CONF_OK; + } + + *periods = ngx_array_create(cf->pool, cf->args->nelts - 1, + sizeof(ngx_uint_t)); + if (*periods == NULL) { + return NGX_CONF_ERROR; + } + + for (i = 1; i < cf->args->nelts; i++) { + period = ngx_array_push(*periods); + *period = ngx_atoi(value[i].data, value[i].len); + + if ((ngx_int_t)*period == NGX_ERROR) { + return NGX_CONF_ERROR; + } + } + return NGX_CONF_OK; } -- 1.6.2