Idea for a statistics module
Tommie Gannert
tommie at spotify.com
Fri Oct 9 11:45:53 MSD 2009
2009/10/9 zepolen <zepolen at gmail.com>:
> It doesn't seem to be tracking the request time properly, the counts
> remain at 0 for all ranges.
Oops. I never intended to include the request time counter in the patch.
Attached is an updated patch which adds the required _add_int() call.
--
Tommie
-------------- next part --------------
diff -Nru nginx-0.7.62/auto/modules nginx-0.7.62-statistics/auto/modules
--- nginx-0.7.62/auto/modules 2009-05-01 20:44:50.000000000 +0200
+++ nginx-0.7.62-statistics/auto/modules 2009-10-08 16:09:01.000000000 +0200
@@ -325,6 +325,10 @@
HTTP_SRCS="$HTTP_SRCS src/http/modules/ngx_http_stub_status_module.c"
fi
+have=NGX_STATISTICS . auto/have
+HTTP_MODULES="$HTTP_MODULES ngx_http_statistics_module"
+HTTP_SRCS="$HTTP_SRCS src/http/modules/ngx_http_statistics_module.c"
+
#if [ -r $NGX_OBJS/auto ]; then
# . $NGX_OBJS/auto
#fi
diff -Nru nginx-0.7.62/auto/sources nginx-0.7.62-statistics/auto/sources
--- nginx-0.7.62/auto/sources 2009-05-06 16:53:54.000000000 +0200
+++ nginx-0.7.62-statistics/auto/sources 2009-10-08 16:09:01.000000000 +0200
@@ -2,7 +2,7 @@
# Copyright (C) Igor Sysoev
-CORE_MODULES="ngx_core_module ngx_errlog_module ngx_conf_module"
+CORE_MODULES="ngx_core_module ngx_errlog_module ngx_conf_module ngx_statistics_module"
CORE_INCS="src/core"
@@ -31,6 +31,7 @@
src/core/ngx_shmtx.h \
src/core/ngx_connection.h \
src/core/ngx_cycle.h \
+ src/core/ngx_statistics.h \
src/core/ngx_conf_file.h \
src/core/ngx_resolver.h \
src/core/ngx_open_file_cache.h"
@@ -58,6 +59,7 @@
src/core/ngx_connection.c \
src/core/ngx_cycle.c \
src/core/ngx_spinlock.c \
+ src/core/ngx_statistics.c \
src/core/ngx_cpuinfo.c \
src/core/ngx_conf_file.c \
src/core/ngx_resolver.c \
diff -Nru nginx-0.7.62/src/core/ngx_statistics.c nginx-0.7.62-statistics/src/core/ngx_statistics.c
--- nginx-0.7.62/src/core/ngx_statistics.c 1970-01-01 01:00:00.000000000 +0100
+++ nginx-0.7.62-statistics/src/core/ngx_statistics.c 2009-10-08 16:09:01.000000000 +0200
@@ -0,0 +1,375 @@
+/*
+ * @todo implement the histogram stuff.
+ */
+#include <ngx_statistics.h>
+
+
+/* --- Macros --- */
+#define ngx_statistics_lock_entry(e) ngx_spinlock(&(e), ngx_pid, 1024)
+#define ngx_statistics_unlock_entry(e) (void) ngx_atomic_cmp_set(&(e), ngx_pid, 0)
+#define cacheline_size 128
+
+
+/* --- Types --- */
+typedef struct {
+ const ngx_statistics_descr_t *descr;
+ size_t size;
+ ngx_statistics_type_t type;
+ ngx_atomic_t lock; // Used for non-atomic types
+
+ union {
+ ngx_atomic_uint_t i;
+ ngx_str_t s;
+ ngx_atomic_uint_t *histo;
+ } value;
+
+ u_char data[0];
+} ngx_statistics_entry_t;
+
+typedef struct {
+ ngx_atomic_t create_lock; // Only used for creation
+ ngx_statistics_entry_t *end; // End of entries list
+ ngx_statistics_entry_t entries[0];
+} ngx_statistics_t;
+
+
+
+/* --- Data --- */
+static const ngx_int_t M[] = { 1, 2, 5 };
+static const ngx_int_t BASE = 10;
+
+static ngx_shm_t shm;
+static ngx_statistics_t *ngx_statistics;
+
+
+
+void ngx_statistics_add_int(ngx_stat_key_t key, ngx_int_t delta)
+{
+ ngx_statistics_entry_t *entry = (void*) (((u_char*) (ngx_statistics + 1)) + key);
+ ngx_int_t bucket;
+
+ if (!ngx_statistics || key == NGX_STAT_KEY_INVALID || entry >= ngx_statistics->end)
+ return;
+
+ if (entry->type != ngx_statistics_int)
+ return;
+
+ switch (entry->descr->histo) {
+ case ngx_statistics_invalid_histo:
+ ngx_atomic_fetch_add(&entry->value.i, delta);
+ return;
+
+ case ngx_statistics_linear:
+ if (delta < entry->descr->min) bucket = 0;
+ else if (delta >= entry->descr->max) bucket = entry->descr->num_buckets - 1;
+ else bucket = (delta - entry->descr->min) * entry->descr->num_buckets / (entry->descr->max - entry->descr->min);
+ break;
+
+ case ngx_statistics_exponential:
+ {
+ ngx_int_t k = 0;
+ ngx_int_t p = 1;
+
+ for (bucket = 0; M[k] * p < delta - entry->descr->min && bucket < entry->descr->num_buckets - 1; ++bucket) {
+ if (++k == sizeof(M) / sizeof(*M)) {
+ k = 0;
+ p *= BASE;
+ }
+ }
+ }
+
+ break;
+
+ default:
+ return;
+ }
+
+ ngx_atomic_fetch_add(&entry->value.histo[bucket], 1);
+}
+
+ngx_int_t ngx_statistics_get_int(ngx_stat_key_t key, ngx_int_t *value)
+{
+ ngx_statistics_entry_t *entry = (void*) (((u_char*) (ngx_statistics + 1)) + key);
+
+ if (!ngx_statistics || key == NGX_STAT_KEY_INVALID || entry >= ngx_statistics->end)
+ return NGX_ERROR;
+
+ if (entry->type != ngx_statistics_int)
+ return NGX_ERROR;
+
+ if (entry->descr->histo != ngx_statistics_invalid_histo)
+ return NGX_ERROR;
+
+ *value = entry->value.i;
+ return NGX_OK;
+}
+
+void ngx_statistics_set_int(ngx_stat_key_t key, ngx_int_t value)
+{
+ ngx_statistics_entry_t *entry = (void*) (((u_char*) (ngx_statistics + 1)) + key);
+
+ if (!ngx_statistics || key == NGX_STAT_KEY_INVALID || entry >= ngx_statistics->end)
+ return;
+
+ if (entry->type != ngx_statistics_int)
+ return;
+
+ switch (entry->descr->histo) {
+ case ngx_statistics_invalid_histo:
+ ngx_atomic_cmp_set(&entry->value.i, entry->value.i, value);
+ break;
+
+ case ngx_statistics_linear:
+ case ngx_statistics_exponential:
+ // For histograms, set is the same as add.
+ ngx_statistics_add_int(key, value);
+ break;
+ }
+}
+
+void ngx_statistics_set_str(ngx_stat_key_t key, ngx_str_t *value)
+{
+ ngx_statistics_entry_t *entry = (void*) (((u_char*) (ngx_statistics + 1)) + key);
+
+ if (!ngx_statistics || key == NGX_STAT_KEY_INVALID || entry >= ngx_statistics->end)
+ return;
+
+ if (entry->type != ngx_statistics_str)
+ return;
+
+ ngx_statistics_lock_entry(entry->lock);
+
+ if (value->len <= entry->size - sizeof(*entry))
+ entry->value.s.len = value->len;
+ else
+ entry->value.s.len = entry->size - sizeof(*entry);
+
+ ngx_memcpy(entry->value.s.data, value->data, entry->value.s.len);
+
+ ngx_statistics_unlock_entry(entry->lock);
+}
+
+static ngx_stat_key_t ngx_statistics_alloc(const ngx_statistics_descr_t *descr, ngx_statistics_type_t type, size_t size, ngx_statistics_entry_t **entryp)
+{
+ ngx_statistics_entry_t *entry = ngx_statistics->entries;
+
+ if (size < sizeof(*entry))
+ return NGX_STAT_KEY_INVALID;
+
+ while (entry < ngx_statistics->end) {
+ if (descr == entry->descr) {
+ if (type != entry->type || size != entry->size)
+ return NGX_STAT_KEY_INVALID;
+
+ if (entryp) *entryp = entry;
+
+ return (u_char*) ngx_statistics->entries - (u_char*) entry;
+ }
+
+ entry = (ngx_statistics_entry_t*) ((u_char*) entry + entry->size);
+ }
+
+ if (entry != ngx_statistics->end)
+ return NGX_STAT_KEY_INVALID;
+
+ entry->descr = descr;
+ entry->size = size;
+ entry->type = type;
+ entry->lock = 0;
+
+ // entry->value is initialized by _create_*()
+
+ ngx_statistics->end = (ngx_statistics_entry_t*) ((u_char*) ngx_statistics->end + size);
+
+ if (entryp) *entryp = entry;
+
+ return (u_char*) entry - (u_char*) ngx_statistics->entries;
+}
+
+ngx_stat_key_t ngx_statistics_create_int(const ngx_statistics_descr_t *descr, ngx_int_t initial)
+{
+ ngx_stat_key_t ret;
+ ngx_statistics_entry_t *entry;
+ ngx_int_t i;
+
+ if (!ngx_statistics)
+ return NGX_STAT_KEY_INVALID;
+
+ if (descr->histo == ngx_statistics_invalid_histo && descr->num_buckets != 1)
+ return NGX_STAT_KEY_INVALID;
+
+ ngx_spinlock(&ngx_statistics->create_lock, ngx_pid, 1024);
+
+ ret = ngx_statistics_alloc(descr, ngx_statistics_int, sizeof(ngx_statistics_entry_t) + sizeof(ngx_int_t) * descr->num_buckets, &entry);
+
+ if (ret == NGX_STAT_KEY_INVALID) {
+ (void) ngx_atomic_cmp_set(&ngx_statistics->create_lock, ngx_pid, 0);
+
+ return ret;
+ }
+
+ if (descr->histo != ngx_statistics_invalid_histo) {
+ entry->value.histo = (ngx_atomic_uint_t*) entry->data;
+
+ for (i = 0; i < descr->num_buckets; ++i)
+ entry->value.histo[i] = initial;
+ } else {
+ entry->value.i = initial;
+ }
+
+ (void) ngx_atomic_cmp_set(&ngx_statistics->create_lock, ngx_pid, 0);
+
+ return ret;
+}
+
+ngx_stat_key_t ngx_statistics_create_str(const ngx_statistics_descr_t *descr, ngx_int_t max_size, ngx_str_t *initial)
+{
+ ngx_stat_key_t ret;
+ ngx_statistics_entry_t *entry;
+
+ if (!ngx_statistics)
+ return NGX_STAT_KEY_INVALID;
+
+ if (descr->histo != ngx_statistics_invalid_histo)
+ return NGX_STAT_KEY_INVALID;
+
+ ngx_spinlock(&ngx_statistics->create_lock, ngx_pid, 1024);
+
+ ret = ngx_statistics_alloc(descr, ngx_statistics_str, sizeof(ngx_statistics_entry_t) + max_size + 1, &entry);
+
+ if (ret == NGX_STAT_KEY_INVALID) {
+ (void) ngx_atomic_cmp_set(&ngx_statistics->create_lock, ngx_pid, 0);
+
+ return ret;
+ }
+
+ entry->value.s.len = initial->len;
+ entry->value.s.data = entry->data;
+ ngx_memcpy(entry->value.s.data, initial->data, initial->len);
+
+ (void) ngx_atomic_cmp_set(&ngx_statistics->create_lock, ngx_pid, 0);
+
+ return ret;
+}
+
+ngx_statistics_type_t ngx_statistics_entry(ngx_stat_iter_t it, const ngx_statistics_descr_t **descr, void **value)
+{
+ ngx_statistics_entry_t *entry = (void*) (((u_char*) ngx_statistics->entries) + it);
+
+ if (!ngx_statistics_valid(it))
+ return ngx_statistics_invalid_type;
+
+ if (descr) *descr = entry->descr;
+
+ if (value) {
+ if (entry->descr->histo == ngx_statistics_invalid_histo)
+ *value = &entry->value;
+ else
+ *value = entry->value.histo;
+ }
+
+ return entry->type;
+}
+
+ngx_stat_iter_t ngx_statistics_iter(void)
+{
+ return 0;
+}
+
+ngx_stat_iter_t ngx_statistics_next(ngx_stat_iter_t it)
+{
+ ngx_statistics_entry_t *entry = (void*) (((u_char*) ngx_statistics->entries) + it);
+
+ if (!ngx_statistics_valid(it))
+ return it;
+
+ return it + entry->size;
+}
+
+ngx_int_t ngx_statistics_valid(ngx_stat_iter_t it)
+{
+ return ngx_statistics && (u_char*) ngx_statistics->entries + it < (u_char*) ngx_statistics->end;
+}
+
+static ngx_int_t powi(ngx_int_t base, ngx_int_t exp)
+{
+ ngx_int_t ret = 1;
+
+ while (exp--) ret *= base;
+
+ return ret;
+}
+
+ngx_int_t ngx_statistics_bucket_lower(const ngx_statistics_descr_t *descr, ngx_int_t bucket)
+{
+ switch (descr->histo) {
+ case ngx_statistics_invalid_histo:
+ return descr->min;
+
+ case ngx_statistics_linear:
+ return descr->min + (descr->max - descr->min) * bucket / descr->num_buckets;
+
+ case ngx_statistics_exponential:
+ if (!bucket) return descr->min;
+
+ --bucket;
+
+ return descr->min + M[bucket % (sizeof(M) / sizeof(*M))] * powi(BASE, bucket / 3);
+ }
+
+ return -1;
+}
+
+
+static ngx_int_t ngx_statistics_module_init(ngx_cycle_t *cycle)
+{
+ /* This would fit around 64 entries */
+ shm.size = 64 * cacheline_size;
+ shm.log = cycle->log;
+ shm.name.len = sizeof("ngx_statistics");
+ shm.name.data = (u_char*) "ngx_statistics";
+
+ if (ngx_shm_alloc(&shm) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
+ ngx_statistics = (ngx_statistics_t*) shm.addr;
+
+ ngx_statistics->create_lock = 0;
+ ngx_statistics->end = ngx_statistics->entries;
+
+ return NGX_OK;
+}
+
+static void ngx_statistics_module_exit_process(ngx_cycle_t *cycle)
+{
+ ngx_shm_free(&shm);
+ ngx_statistics = NULL;
+}
+
+static void ngx_statistics_module_exit(ngx_cycle_t *cycle)
+{
+ ngx_statistics_module_exit_process(cycle);
+}
+
+
+static ngx_core_module_t ngx_statistics_module_ctx = {
+ ngx_string("statistics"),
+ NULL,
+ NULL
+};
+
+ngx_module_t ngx_statistics_module = {
+ NGX_MODULE_V1,
+ &ngx_statistics_module_ctx, /* module context */
+ NULL, /* module directives */
+ NGX_CORE_MODULE, /* module type */
+ NULL, /* init master */
+ ngx_statistics_module_init, /* init module */
+ NULL, /* init process */
+ NULL, /* init thread */
+ NULL, /* exit thread */
+ ngx_statistics_module_exit_process, /* exit process */
+ ngx_statistics_module_exit, /* exit master */
+ NGX_MODULE_V1_PADDING
+};
diff -Nru nginx-0.7.62/src/core/ngx_statistics.h nginx-0.7.62-statistics/src/core/ngx_statistics.h
--- nginx-0.7.62/src/core/ngx_statistics.h 1970-01-01 01:00:00.000000000 +0100
+++ nginx-0.7.62-statistics/src/core/ngx_statistics.h 2009-10-08 16:09:01.000000000 +0200
@@ -0,0 +1,61 @@
+#ifndef _NGX_STATISTICS_H_INCLUDED_
+#define _NGX_STATISTICS_H_INCLUDED_
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+/* --- Macros --- */
+#define NGX_STAT_KEY_INVALID ((ngx_stat_key_t) -1)
+
+
+/* --- Types --- */
+typedef ngx_int_t ngx_stat_key_t;
+typedef size_t ngx_stat_iter_t;
+
+typedef enum {
+ ngx_statistics_invalid_type = 0,
+ ngx_statistics_int,
+ ngx_statistics_str
+} ngx_statistics_type_t;
+
+typedef enum {
+ ngx_statistics_invalid_histo = 0,
+ ngx_statistics_linear,
+ ngx_statistics_exponential
+} ngx_statistics_histo_t;
+
+typedef struct {
+ ngx_str_t label;
+ ngx_str_t name;
+ ngx_str_t unit;
+ float scale;
+ int num_decimals;
+ ngx_int_t min;
+ ngx_int_t max;
+ ngx_int_t num_buckets;
+ ngx_statistics_histo_t histo;
+} ngx_statistics_descr_t;
+
+
+/* --- Functions --- */
+// Creators
+ngx_stat_key_t ngx_statistics_create_int(const ngx_statistics_descr_t *descr, ngx_int_t initial);
+ngx_stat_key_t ngx_statistics_create_str(const ngx_statistics_descr_t *descr, ngx_int_t max_size, ngx_str_t *initial);
+
+// Accessors
+ngx_int_t ngx_statistics_get_int(ngx_stat_key_t key, ngx_int_t *value);
+
+// Mutators
+void ngx_statistics_add_int(ngx_stat_key_t key, ngx_int_t delta);
+void ngx_statistics_set_int(ngx_stat_key_t key, ngx_int_t value);
+void ngx_statistics_set_str(ngx_stat_key_t key, ngx_str_t *value);
+
+// Iterators
+ngx_statistics_type_t ngx_statistics_entry(ngx_stat_iter_t it, const ngx_statistics_descr_t **descr, void **value);
+ngx_stat_iter_t ngx_statistics_iter(void);
+ngx_stat_iter_t ngx_statistics_next(ngx_stat_iter_t it);
+ngx_int_t ngx_statistics_valid(ngx_stat_iter_t it);
+
+ngx_int_t ngx_statistics_bucket_lower(const ngx_statistics_descr_t *descr, ngx_int_t bucket);
+
+#endif /* _NGX_STATISTICS_H_INCLUDED_ */
diff -Nru nginx-0.7.62/src/core/ngx_string.c nginx-0.7.62-statistics/src/core/ngx_string.c
--- nginx-0.7.62/src/core/ngx_string.c 2009-09-07 13:31:20.000000000 +0200
+++ nginx-0.7.62-statistics/src/core/ngx_string.c 2009-10-08 16:09:01.000000000 +0200
@@ -201,8 +201,13 @@
case '.':
fmt++;
- while (*fmt >= '0' && *fmt <= '9') {
- frac_width = frac_width * 10 + *fmt++ - '0';
+ if (*fmt == '*') {
+ frac_width = va_arg(args, size_t);
+ fmt++;
+ } else {
+ while (*fmt >= '0' && *fmt <= '9') {
+ frac_width = frac_width * 10 + *fmt++ - '0';
+ }
}
break;
diff -Nru nginx-0.7.62/src/event/ngx_event_accept.c nginx-0.7.62-statistics/src/event/ngx_event_accept.c
--- nginx-0.7.62/src/event/ngx_event_accept.c 2009-06-22 11:31:33.000000000 +0200
+++ nginx-0.7.62-statistics/src/event/ngx_event_accept.c 2009-10-08 16:09:01.000000000 +0200
@@ -77,6 +77,9 @@
#if (NGX_STAT_STUB)
(void) ngx_atomic_fetch_add(ngx_stat_accepted, 1);
#endif
+#if (NGX_STATISTICS)
+ (void) ngx_statistics_add_int(ngx_stat_accepted_key, 1);
+#endif
ngx_accept_disabled = ngx_cycle->connection_n / 8
- ngx_cycle->free_connection_n;
@@ -95,6 +98,9 @@
#if (NGX_STAT_STUB)
(void) ngx_atomic_fetch_add(ngx_stat_active, 1);
#endif
+#if (NGX_STATISTICS)
+ (void) ngx_statistics_add_int(ngx_stat_active_key, 1);
+#endif
c->pool = ngx_create_pool(ls->pool_size, ev->log);
if (c->pool == NULL) {
@@ -190,6 +196,9 @@
#if (NGX_STAT_STUB)
(void) ngx_atomic_fetch_add(ngx_stat_handled, 1);
#endif
+#if (NGX_STATISTICS)
+ (void) ngx_statistics_add_int(ngx_stat_handled_key, 1);
+#endif
#if (NGX_THREADS)
rev->lock = &c->lock;
@@ -381,6 +390,9 @@
#if (NGX_STAT_STUB)
(void) ngx_atomic_fetch_add(ngx_stat_active, -1);
#endif
+#if (NGX_STATISTICS)
+ (void) ngx_statistics_add_int(ngx_stat_active_key, 1);
+#endif
}
diff -Nru nginx-0.7.62/src/event/ngx_event.c nginx-0.7.62-statistics/src/event/ngx_event.c
--- nginx-0.7.62/src/event/ngx_event.c 2009-04-28 22:03:59.000000000 +0200
+++ nginx-0.7.62-statistics/src/event/ngx_event.c 2009-10-08 16:09:01.000000000 +0200
@@ -74,6 +74,12 @@
#endif
+#if (NGX_STATISTICS)
+ngx_stat_key_t ngx_stat_accepted_key = NGX_STAT_KEY_INVALID;
+ngx_stat_key_t ngx_stat_active_key = NGX_STAT_KEY_INVALID;
+ngx_stat_key_t ngx_stat_handled_key = NGX_STAT_KEY_INVALID;
+#endif
+
static ngx_command_t ngx_events_commands[] = {
@@ -537,6 +543,35 @@
#endif
+#if (NGX_STATISTICS)
+ {
+ static const ngx_statistics_descr_t ACCEPTED = {
+ ngx_string("Event-Accepted"),
+ ngx_string("Accepted Connections"),
+ ngx_string("connections"),
+ 1.0f, 0,
+ 0, 0, 1, ngx_statistics_invalid_histo };
+
+ static const ngx_statistics_descr_t ACTIVE = {
+ ngx_string("Event-Active"),
+ ngx_string("Active Connections"),
+ ngx_string("connections"),
+ 1.0f, 0,
+ 0, 0, 1, ngx_statistics_invalid_histo };
+
+ static const ngx_statistics_descr_t HANDLED = {
+ ngx_string("Event-Handled"),
+ ngx_string("Handled Connections"),
+ ngx_string("connections"),
+ 1.0f, 0,
+ 0, 0, 1, ngx_statistics_invalid_histo };
+
+ ngx_stat_accepted_key = ngx_statistics_create_int(&ACCEPTED, 0);
+ ngx_stat_active_key = ngx_statistics_create_int(&ACTIVE, 0);
+ ngx_stat_handled_key = ngx_statistics_create_int(&HANDLED, 0);
+ }
+#endif
+
(void) ngx_atomic_cmp_set(ngx_connection_counter, 0, 1);
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
diff -Nru nginx-0.7.62/src/event/ngx_event.h nginx-0.7.62-statistics/src/event/ngx_event.h
--- nginx-0.7.62/src/event/ngx_event.h 2008-02-28 21:31:33.000000000 +0100
+++ nginx-0.7.62-statistics/src/event/ngx_event.h 2009-10-08 16:09:01.000000000 +0200
@@ -10,6 +10,7 @@
#include <ngx_config.h>
#include <ngx_core.h>
+#include <ngx_statistics.h>
#define NGX_INVALID_INDEX 0xd0d0d0d0
@@ -488,6 +489,12 @@
#endif
+#if (NGX_STATISTICS)
+extern ngx_stat_key_t ngx_stat_accepted_key;
+extern ngx_stat_key_t ngx_stat_active_key;
+extern ngx_stat_key_t ngx_stat_handled_key;
+#endif
+
#define NGX_UPDATE_TIME 1
#define NGX_POST_EVENTS 2
diff -Nru nginx-0.7.62/src/http/modules/ngx_http_statistics_module.c nginx-0.7.62-statistics/src/http/modules/ngx_http_statistics_module.c
--- nginx-0.7.62/src/http/modules/ngx_http_statistics_module.c 1970-01-01 01:00:00.000000000 +0100
+++ nginx-0.7.62-statistics/src/http/modules/ngx_http_statistics_module.c 2009-10-08 16:09:01.000000000 +0200
@@ -0,0 +1,315 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_http.h>
+
+
+static char *ngx_http_set_statistics(ngx_conf_t *cf, ngx_command_t *cmd,
+ void *conf);
+
+static ngx_command_t ngx_http_statistics_commands[] = {
+
+ { ngx_string("statistics"),
+ NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+ ngx_http_set_statistics,
+ 0,
+ 0,
+ NULL },
+
+ ngx_null_command
+};
+
+
+
+static ngx_http_module_t ngx_http_statistics_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_statistics_module = {
+ NGX_MODULE_V1,
+ &ngx_http_statistics_module_ctx, /* module context */
+ ngx_http_statistics_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_buf_t* ngx_http_statistics_html_handler(ngx_http_request_t *r)
+{
+ static ngx_str_t HEADER = ngx_string(
+ "<html>\r\n"
+ "\t<head>\r\n"
+ "\t\t<title>Nginx Statistics</title>\r\n"
+ "\t\t<style>\r\n"
+ "\t\t\t.int { text-align: right; }\r\n"
+ "\t\t\tTH { text-align: left; }\r\n"
+ "\t\t\tTABLE.histogram { width: 100%; }\r\n"
+ "\t\t</style>\r\n"
+ "\t</head>\r\n"
+ "\t<body>\r\n"
+ "\t\t<h1>Nginx Statistics</h1>\r\n"
+ "\t\t<table class=\"stats\" border=\"1\" cellspacing=\"0\">\r\n");
+
+ static ngx_str_t FOOTER = ngx_string(
+ "\t\t</table>\r\n"
+ "\t</body>\r\n"
+ "</html>\r\n");
+
+ ngx_buf_t *b;
+ size_t size = HEADER.len + FOOTER.len;
+ ngx_stat_iter_t it;
+
+ for (it = ngx_statistics_iter(); ngx_statistics_valid(it); it = ngx_statistics_next(it)) {
+ const ngx_statistics_descr_t *descr;
+ void *value;
+
+ switch (ngx_statistics_entry(it, &descr, &value)) {
+ case ngx_statistics_int:
+ size += 27 + 27 + (160 + NGX_ATOMIC_T_LEN * 3) * descr->num_buckets + 11;
+ break;
+
+ case ngx_statistics_str:
+ size += 13 + ((ngx_str_t*) value)->len;
+ break;
+
+ default:
+ break;
+ }
+
+ size += 11 + descr->name.len + 8 + 22 + descr->unit.len + 12;
+ }
+
+ b = ngx_create_temp_buf(r->pool, size);
+
+ if (b == NULL) return NULL;
+
+ b->last = ngx_sprintf(b->last, "%V", &HEADER);
+
+ for (it = ngx_statistics_iter(); ngx_statistics_valid(it); it = ngx_statistics_next(it)) {
+ const ngx_statistics_descr_t *descr;
+ void *value;
+ ngx_int_t i;
+ ngx_statistics_type_t type = ngx_statistics_entry(it, &descr, &value);
+
+ b->last = ngx_sprintf(b->last, "\t\t\t<tr><th>%V</th><td", &descr->name);
+
+ switch (type) {
+ case ngx_statistics_int:
+ if (descr->histo != ngx_statistics_invalid_histo) {
+ ngx_int_t sum = 0;
+
+ b->last = ngx_sprintf(b->last, " class=\"histo\" width=\"50%%\">");
+
+ for (i = 0; i < descr->num_buckets; ++i)
+ sum += ((ngx_atomic_uint_t*) value)[i];
+
+ if (sum) {
+ b->last = ngx_sprintf(b->last, "<table class=\"histogram\">\r\n");
+
+ for (i = 0; i < descr->num_buckets; ++i) {
+ b->last = ngx_sprintf(b->last, "\t\t\t\t<tr><th class=\"int\">");
+ if (i + 1 < descr->num_buckets)
+ b->last = ngx_sprintf(b->last, "<%.*f", descr->num_decimals, descr->scale * ngx_statistics_bucket_lower(descr, i + 1));
+ else
+ b->last = ngx_sprintf(b->last, "More");
+ b->last = ngx_sprintf(b->last, "</th><td width=\"100%%\"><div style=\"float:left;background:black;width:%i%%\"> </div></td><td class=\"int\">%i</td></tr>\r\n", 100 * ((ngx_atomic_uint_t*) value)[i] / sum, ((ngx_atomic_uint_t*) value)[i]);
+ }
+
+ b->last = ngx_sprintf(b->last, "\t\t\t</table>");
+ }
+ } else {
+ b->last = ngx_sprintf(b->last, " class=\"int\">%.*f", descr->num_decimals, descr->scale * *(ngx_atomic_uint_t*) value);
+ }
+
+
+ break;
+
+ case ngx_statistics_str:
+ b->last = ngx_sprintf(b->last, " class=\"str\">%V", (ngx_str_t*) value);
+ break;
+
+ default:
+ break;
+ }
+
+ b->last = ngx_sprintf(b->last, "</td><td class=\"unit\">%V</td></tr>\r\n", &descr->unit);
+ }
+
+ b->last = ngx_sprintf(b->last, "%V", &FOOTER);
+
+ return b;
+}
+
+
+static ngx_buf_t* ngx_http_statistics_plain_handler(ngx_http_request_t *r)
+{
+ ngx_buf_t *b;
+ size_t size = 0;
+ ngx_stat_iter_t it;
+
+ for (it = ngx_statistics_iter(); ngx_statistics_valid(it); it = ngx_statistics_next(it)) {
+ const ngx_statistics_descr_t *descr;
+ void *value;
+
+ switch (ngx_statistics_entry(it, &descr, &value)) {
+ case ngx_statistics_int:
+ size += (1 + NGX_ATOMIC_T_LEN + 1 + NGX_ATOMIC_T_LEN + 2) * descr->num_buckets;
+ break;
+
+ case ngx_statistics_str:
+ size += ((ngx_str_t*) value)->len;
+ break;
+
+ default:
+ break;
+ }
+
+ size += descr->label.len + 2 + 2;
+ }
+
+ b = ngx_create_temp_buf(r->pool, size);
+
+ if (b == NULL) return NULL;
+
+ for (it = ngx_statistics_iter(); ngx_statistics_valid(it); it = ngx_statistics_next(it)) {
+ const ngx_statistics_descr_t *descr;
+ void *value;
+ ngx_int_t i;
+ ngx_statistics_type_t type = ngx_statistics_entry(it, &descr, &value);
+
+ b->last = ngx_sprintf(b->last, "%V:", &descr->label);
+
+ switch (type) {
+ case ngx_statistics_int:
+ if (descr->histo != ngx_statistics_invalid_histo) {
+ b->last = ngx_sprintf(b->last, "\r\n");
+
+ for (i = 0; i < descr->num_buckets; ++i) {
+ *b->last++ = '\t';
+ if (i > 0)
+ b->last = ngx_sprintf(b->last, "%i", ngx_statistics_bucket_lower(descr, i));
+ *b->last++ = '-';
+ if (i + 1 < descr->num_buckets)
+ b->last = ngx_sprintf(b->last, "%i", ngx_statistics_bucket_lower(descr, i + 1) - 1);
+ b->last = ngx_sprintf(b->last, "=%i\r\n", ((ngx_atomic_uint_t*) value)[i]);
+ }
+ } else {
+ b->last = ngx_sprintf(b->last, " %i\r\n", *(ngx_atomic_uint_t*) value);
+ }
+
+
+ break;
+
+ case ngx_statistics_str:
+ b->last = ngx_sprintf(b->last, " %V\r\n", (ngx_str_t*) value);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ return b;
+}
+
+
+static ngx_int_t ngx_http_statistics_handler(ngx_http_request_t *r)
+{
+ ngx_int_t rc;
+ ngx_buf_t *b;
+ ngx_chain_t out;
+ ngx_str_t content_type = ngx_string("text/plain");
+ ngx_buf_t* (*handler)(ngx_http_request_t*) = ngx_http_statistics_plain_handler;
+
+ 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;
+ }
+
+ // XXX: Handle Accept in addition to ?type=
+ if (r->args.len > sizeof("type=") - 1 && !ngx_memcmp(r->args.data, "type=", sizeof("type=") - 1)) {
+ ngx_str_t TEXT_PLAIN = ngx_string("text/plain");
+ ngx_str_t TEXT_HTML = ngx_string("text/html");
+
+ if (r->args.len - (sizeof("type=") - 1) == TEXT_PLAIN.len && !ngx_memcmp(r->args.data + (sizeof("type=") - 1), TEXT_PLAIN.data, TEXT_PLAIN.len)) {
+ content_type = TEXT_PLAIN;
+ handler = ngx_http_statistics_plain_handler;
+ } else if (r->args.len - (sizeof("type=") - 1) == TEXT_HTML.len && !ngx_memcmp(r->args.data + (sizeof("type=") - 1), TEXT_HTML.data, TEXT_HTML.len)) {
+ content_type = TEXT_HTML;
+ handler = ngx_http_statistics_html_handler;
+ }
+ }
+
+ r->headers_out.content_type = content_type;
+
+ 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;
+ }
+ }
+
+ b = handler(r);
+
+ if (b == NULL) {
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ out.buf = b;
+ out.next = NULL;
+
+ 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_statistics(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_statistics_handler;
+
+ return NGX_CONF_OK;
+}
diff -Nru nginx-0.7.62/src/http/ngx_http_core_module.c nginx-0.7.62-statistics/src/http/ngx_http_core_module.c
--- nginx-0.7.62/src/http/ngx_http_core_module.c 2009-09-07 12:01:26.000000000 +0200
+++ nginx-0.7.62-statistics/src/http/ngx_http_core_module.c 2009-10-08 16:09:01.000000000 +0200
@@ -20,6 +20,8 @@
#define NGX_HTTP_REQUEST_BODY_FILE_CLEAN 2
+static ngx_int_t ngx_http_core_module_init(ngx_cycle_t *cycle);
+
static ngx_int_t ngx_http_core_find_location(ngx_http_request_t *r);
static ngx_int_t ngx_http_core_find_static_location(ngx_http_request_t *r,
ngx_http_location_tree_node_t *node);
@@ -153,6 +155,15 @@
#endif
+#if (NGX_STATISTICS)
+ngx_stat_key_t ngx_stat_http_reading_key = NGX_STAT_KEY_INVALID;
+ngx_stat_key_t ngx_stat_http_writing_key = NGX_STAT_KEY_INVALID;
+ngx_stat_key_t ngx_stat_http_requests_key = NGX_STAT_KEY_INVALID;
+ngx_stat_key_t ngx_stat_http_request_time_key = NGX_STAT_KEY_INVALID;
+ngx_stat_key_t ngx_stat_http_active_requests_key = NGX_STAT_KEY_INVALID;
+ngx_stat_key_t ngx_stat_http_writing_file_key = NGX_STAT_KEY_INVALID;
+#endif
+
static ngx_command_t ngx_http_core_commands[] = {
@@ -695,7 +706,7 @@
ngx_http_core_commands, /* module directives */
NGX_HTTP_MODULE, /* module type */
NULL, /* init master */
- NULL, /* init module */
+ ngx_http_core_module_init, /* init module */
NULL, /* init process */
NULL, /* init thread */
NULL, /* exit thread */
@@ -708,6 +719,65 @@
ngx_str_t ngx_http_core_get_method = { 3, (u_char *) "GET " };
+static ngx_int_t
+ngx_http_core_module_init(ngx_cycle_t *cycle)
+{
+#if (NGX_STATISTICS)
+ static const ngx_statistics_descr_t READING = {
+ ngx_string("Http-Requests-Reading"),
+ ngx_string("HTTP Requests Currently Reading"),
+ ngx_string("requests"),
+ 1.0f, 0,
+ 0, 0, 1, ngx_statistics_invalid_histo };
+
+ static const ngx_statistics_descr_t WRITING = {
+ ngx_string("Http-Requests-Writing"),
+ ngx_string("HTTP Requests Currently Writing"),
+ ngx_string("requests"),
+ 1.0f, 0,
+ 0, 0, 1, ngx_statistics_invalid_histo };
+
+ static const ngx_statistics_descr_t REQUESTS = {
+ ngx_string("Http-Requests-Total"),
+ ngx_string("Processed HTTP Requests Since Start"),
+ ngx_string("requests"),
+ 1.0f, 0,
+ 0, 0, 1, ngx_statistics_invalid_histo };
+
+ static const ngx_statistics_descr_t REQUEST_TIME = {
+ ngx_string("Http-Time-Request"),
+ ngx_string("Total Time of HTTP Request"),
+ ngx_string("s"),
+ 0.001f, 3,
+ 0, 0, 15, ngx_statistics_exponential };
+
+ static const ngx_statistics_descr_t ACTIVE_REQUESTS = {
+ ngx_string("Http-Requests-Active"),
+ ngx_string("HTTP Requests Currently Active"),
+ ngx_string("requests"),
+ 1.0f, 0,
+ 0, 0, 1, ngx_statistics_invalid_histo };
+
+ static const ngx_statistics_descr_t WRITING_FILE = {
+ ngx_string("Http-Requests-Writing-File"),
+ ngx_string("HTTP Requests Currently Writing File"),
+ ngx_string("requests"),
+ 1.0f, 0,
+ 0, 0, 1, ngx_statistics_invalid_histo };
+
+
+ ngx_stat_http_reading_key = ngx_statistics_create_int(&READING, 0);
+ ngx_stat_http_writing_key = ngx_statistics_create_int(&WRITING, 0);
+ ngx_stat_http_requests_key = ngx_statistics_create_int(&REQUESTS, 0);
+ ngx_stat_http_request_time_key = ngx_statistics_create_int(&REQUEST_TIME, 0);
+ ngx_stat_http_active_requests_key = ngx_statistics_create_int(&ACTIVE_REQUESTS, 0);
+ ngx_stat_http_writing_file_key = ngx_statistics_create_int(&WRITING_FILE, 0);
+#endif
+
+ return NGX_OK;
+}
+
+
void
ngx_http_handler(ngx_http_request_t *r)
{
diff -Nru nginx-0.7.62/src/http/ngx_http_core_module.h nginx-0.7.62-statistics/src/http/ngx_http_core_module.h
--- nginx-0.7.62/src/http/ngx_http_core_module.h 2009-09-07 12:01:26.000000000 +0200
+++ nginx-0.7.62-statistics/src/http/ngx_http_core_module.h 2009-10-08 16:09:01.000000000 +0200
@@ -472,6 +472,15 @@
extern ngx_str_t ngx_http_core_get_method;
+#if (NGX_STATISTICS)
+extern ngx_stat_key_t ngx_stat_http_reading_key;
+extern ngx_stat_key_t ngx_stat_http_writing_key;
+extern ngx_stat_key_t ngx_stat_http_requests_key;
+extern ngx_stat_key_t ngx_stat_http_request_time_key;
+extern ngx_stat_key_t ngx_stat_http_active_requests_key;
+extern ngx_stat_key_t ngx_stat_http_writing_file_key;
+#endif
+
#define ngx_http_clear_content_length(r) \
\
diff -Nru nginx-0.7.62/src/http/ngx_http_request_body.c nginx-0.7.62-statistics/src/http/ngx_http_request_body.c
--- nginx-0.7.62/src/http/ngx_http_request_body.c 2008-12-26 14:43:42.000000000 +0100
+++ nginx-0.7.62-statistics/src/http/ngx_http_request_body.c 2009-10-08 16:09:01.000000000 +0200
@@ -414,7 +414,13 @@
rb->temp_file = tf;
}
+#if (NGX_STATISTICS)
+ (void) ngx_statistics_add_int(ngx_stat_http_writing_file_key, 1);
+#endif
n = ngx_write_chain_to_temp_file(rb->temp_file, body);
+#if (NGX_STATISTICS)
+ (void) ngx_statistics_add_int(ngx_stat_http_writing_file_key, -1);
+#endif
/* TODO: n == 0 or not complete and level event */
diff -Nru nginx-0.7.62/src/http/ngx_http_request.c nginx-0.7.62-statistics/src/http/ngx_http_request.c
--- nginx-0.7.62/src/http/ngx_http_request.c 2009-09-07 13:11:24.000000000 +0200
+++ nginx-0.7.62-statistics/src/http/ngx_http_request.c 2009-10-09 09:39:03.000000000 +0200
@@ -200,6 +200,9 @@
#if (NGX_STAT_STUB)
(void) ngx_atomic_fetch_add(ngx_stat_reading, 1);
#endif
+#if (NGX_STATISTICS)
+ (void) ngx_statistics_add_int(ngx_stat_http_reading_key, 1);
+#endif
if (rev->ready) {
/* the deferred accept(), rtsig, aio, iocp */
@@ -219,6 +222,9 @@
#if (NGX_STAT_STUB)
(void) ngx_atomic_fetch_add(ngx_stat_reading, -1);
#endif
+#if (NGX_STATISTICS)
+ (void) ngx_statistics_add_int(ngx_stat_http_reading_key, -1);
+#endif
ngx_http_close_connection(c);
return;
}
@@ -249,6 +255,9 @@
#if (NGX_STAT_STUB)
(void) ngx_atomic_fetch_add(ngx_stat_reading, -1);
#endif
+#if (NGX_STATISTICS)
+ (void) ngx_statistics_add_int(ngx_stat_http_reading_key, -1);
+#endif
c = rev->data;
@@ -501,6 +510,12 @@
r->stat_reading = 1;
(void) ngx_atomic_fetch_add(ngx_stat_requests, 1);
#endif
+#if (NGX_STATISTICS)
+ (void) ngx_statistics_add_int(ngx_stat_http_reading_key, 1);
+ r->stat_reading = 1;
+ (void) ngx_statistics_add_int(ngx_stat_http_requests_key, 1);
+ (void) ngx_statistics_add_int(ngx_stat_http_active_requests_key, 1);
+#endif
rev->handler(rev);
}
@@ -1561,6 +1576,12 @@
(void) ngx_atomic_fetch_add(ngx_stat_writing, 1);
r->stat_writing = 1;
#endif
+#if (NGX_STATISTICS)
+ (void) ngx_statistics_add_int(ngx_stat_http_reading_key, -1);
+ r->stat_reading = 0;
+ (void) ngx_statistics_add_int(ngx_stat_http_writing_key, 1);
+ r->stat_writing = 1;
+#endif
c->read->handler = ngx_http_request_handler;
c->write->handler = ngx_http_request_handler;
@@ -2330,6 +2351,9 @@
#if (NGX_STAT_STUB)
(void) ngx_atomic_fetch_add(ngx_stat_reading, 1);
#endif
+#if (NGX_STATISTICS)
+ (void) ngx_statistics_add_int(ngx_stat_http_reading_key, 1);
+#endif
hc->pipeline = 1;
c->log->action = "reading client pipelined request line";
@@ -2560,6 +2584,9 @@
#if (NGX_STAT_STUB)
(void) ngx_atomic_fetch_add(ngx_stat_reading, 1);
#endif
+#if (NGX_STATISTICS)
+ (void) ngx_statistics_add_int(ngx_stat_http_reading_key, 1);
+#endif
c->log->handler = ngx_http_log_error;
c->log->action = "reading client request line";
@@ -2795,6 +2822,24 @@
}
#endif
+#if (NGX_STATISTICS)
+ if (r->stat_reading)
+ (void) ngx_statistics_add_int(ngx_stat_http_reading_key, -1);
+
+ if (r->stat_writing)
+ (void) ngx_statistics_add_int(ngx_stat_http_writing_key, -1);
+
+ if (r->stat_reading || r->stat_writing)
+ (void) ngx_statistics_add_int(ngx_stat_http_active_requests_key, -1);
+
+ {
+#if (NGX_HTTP_REQUEST_TIME_ALWAYS_UPDATE)
+ ngx_time_update(0, 0);
+#endif
+ ngx_time_t *tp = ngx_timeofday();
+ (void) ngx_statistics_add_int(ngx_stat_http_request_time_key, (tp->sec - r->start_sec) * 1000 + tp->msec - r->start_msec);
+ }
+#endif
if (error && r->headers_out.status == 0) {
r->headers_out.status = error;
@@ -2874,6 +2919,9 @@
#if (NGX_STAT_STUB)
(void) ngx_atomic_fetch_add(ngx_stat_active, -1);
#endif
+#if (NGX_STATISTICS)
+ (void) ngx_statistics_add_int(ngx_stat_active_key, -1);
+#endif
c->destroyed = 1;
diff -Nru nginx-0.7.62/src/http/ngx_http_request.h nginx-0.7.62-statistics/src/http/ngx_http_request.h
--- nginx-0.7.62/src/http/ngx_http_request.h 2009-05-22 13:05:26.000000000 +0200
+++ nginx-0.7.62-statistics/src/http/ngx_http_request.h 2009-10-08 16:09:01.000000000 +0200
@@ -497,7 +497,7 @@
unsigned filter_need_temporary:1;
unsigned allow_ranges:1;
-#if (NGX_STAT_STUB)
+#if (NGX_STAT_STUB) || (NGX_STATISTICS)
unsigned stat_reading:1;
unsigned stat_writing:1;
#endif
diff -Nru nginx-0.7.62/src/http/ngx_http_upstream.c nginx-0.7.62-statistics/src/http/ngx_http_upstream.c
--- nginx-0.7.62/src/http/ngx_http_upstream.c 2009-09-07 13:27:07.000000000 +0200
+++ nginx-0.7.62-statistics/src/http/ngx_http_upstream.c 2009-10-08 16:09:01.000000000 +0200
@@ -18,6 +18,8 @@
ngx_http_variable_value_t *v, uintptr_t data);
#endif
+static ngx_int_t ngx_http_upstream_module_init(ngx_cycle_t *cycle);
+
static void ngx_http_upstream_resolve_handler(ngx_resolver_ctx_t *ctx);
static void ngx_http_upstream_rd_check_broken_connection(ngx_http_request_t *r);
static void ngx_http_upstream_wr_check_broken_connection(ngx_http_request_t *r);
@@ -132,6 +134,12 @@
static void ngx_http_upstream_ssl_handshake(ngx_connection_t *c);
#endif
+#if (NGX_STATISTICS)
+ngx_stat_key_t ngx_stat_http_cached_key = NGX_STAT_KEY_INVALID;
+ngx_stat_key_t ngx_stat_http_upstream_key = NGX_STAT_KEY_INVALID;
+ngx_stat_key_t ngx_stat_http_active_upstream_key = NGX_STAT_KEY_INVALID;
+#endif
+
ngx_http_upstream_header_t ngx_http_upstream_headers_in[] = {
@@ -296,7 +304,7 @@
ngx_http_upstream_commands, /* module directives */
NGX_HTTP_MODULE, /* module type */
NULL, /* init master */
- NULL, /* init module */
+ ngx_http_upstream_module_init, /* init module */
NULL, /* init process */
NULL, /* init thread */
NULL, /* exit thread */
@@ -354,6 +362,40 @@
};
+static ngx_int_t
+ngx_http_upstream_module_init(ngx_cycle_t *cycle)
+{
+#if (NGX_STATISTICS)
+ static const ngx_statistics_descr_t UPSTREAM = {
+ ngx_string("Http-Upstreams-Total"),
+ ngx_string("HTTP Upstream Requests Since Start"),
+ ngx_string("requests"),
+ 1.0f, 0,
+ 0, 0, 1, ngx_statistics_invalid_histo };
+
+ static const ngx_statistics_descr_t ACTIVE_UPSTREAM = {
+ ngx_string("Http-Upstreams-Active"),
+ ngx_string("HTTP Upstream Requests Currently Active"),
+ ngx_string("requests"),
+ 1.0f, 0,
+ 0, 0, 1, ngx_statistics_invalid_histo };
+
+ static const ngx_statistics_descr_t CACHED = {
+ ngx_string("Http-Cached"),
+ ngx_string("HTTP Requests Cached Since Start"),
+ ngx_string("requests"),
+ 1.0f, 0,
+ 0, 0, 1, ngx_statistics_invalid_histo };
+
+ ngx_stat_http_upstream_key = ngx_statistics_create_int(&UPSTREAM, 0);
+ ngx_stat_http_active_upstream_key = ngx_statistics_create_int(&ACTIVE_UPSTREAM, 0);
+ ngx_stat_http_cached_key = ngx_statistics_create_int(&CACHED, 0);
+#endif
+
+ return NGX_OK;
+}
+
+
void
ngx_http_upstream_init(ngx_http_request_t *r)
{
@@ -977,6 +1019,10 @@
u->state->response_msec = tp->msec - u->state->response_msec;
}
+#if (NGX_STATISTICS)
+ (void) ngx_statistics_add_int(ngx_stat_http_active_upstream_key, 1);
+#endif
+
u->state = ngx_array_push(r->upstream_states);
if (u->state == NULL) {
ngx_http_upstream_finalize_request(r, u,
@@ -1248,6 +1294,12 @@
c->log->action = "sending request to upstream";
+#if (NGX_STATISTICS)
+ (void) ngx_statistics_add_int(ngx_stat_http_upstream_key, 1);
+ if (u->cacheable)
+ (void) ngx_statistics_add_int(ngx_stat_http_cached_key, 1);
+#endif
+
rc = ngx_output_chain(&u->output, u->request_sent ? NULL : u->request_bufs);
u->request_sent = 1;
@@ -2804,6 +2856,10 @@
{
ngx_time_t *tp;
+#if (NGX_STATISTICS)
+ (void) ngx_statistics_add_int(ngx_stat_http_active_upstream_key, -1);
+#endif
+
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"finalize http upstream request: %i", rc);
diff -Nru nginx-0.7.62/src/http/ngx_http_upstream.h nginx-0.7.62-statistics/src/http/ngx_http_upstream.h
--- nginx-0.7.62/src/http/ngx_http_upstream.h 2009-09-07 11:49:51.000000000 +0200
+++ nginx-0.7.62-statistics/src/http/ngx_http_upstream.h 2009-10-08 16:09:01.000000000 +0200
@@ -332,6 +332,10 @@
extern ngx_module_t ngx_http_upstream_module;
extern ngx_conf_bitmask_t ngx_http_upstream_cache_method_mask[];
+#if (NGX_STATISTICS)
+extern ngx_stat_key_t ngx_stat_http_cached_key;
+extern ngx_stat_key_t ngx_stat_http_upstream_key;
+#endif
#endif /* _NGX_HTTP_UPSTREAM_H_INCLUDED_ */
diff -Nru nginx-0.7.62/src/mail/ngx_mail_handler.c nginx-0.7.62-statistics/src/mail/ngx_mail_handler.c
--- nginx-0.7.62/src/mail/ngx_mail_handler.c 2009-06-22 11:31:33.000000000 +0200
+++ nginx-0.7.62-statistics/src/mail/ngx_mail_handler.c 2009-10-08 16:09:01.000000000 +0200
@@ -712,6 +712,9 @@
#if (NGX_STAT_STUB)
(void) ngx_atomic_fetch_add(ngx_stat_active, -1);
#endif
+#if (NGX_STATISTICS)
+ (void) ngx_statistics_add_int(ngx_stat_active_key, -1);
+#endif
c->destroyed = 1;
More information about the nginx
mailing list