diff --git a/README.md b/README.md index 1490fcd..11d00dc 100644 --- a/README.md +++ b/README.md @@ -1887,6 +1887,41 @@ http { } ``` +### vhost_traffic_status_measure_status_codes + +Allows tracking of specific HTTP status codes or all status codes in the Vhost Traffic Status module. + + +| - | - | +| --- | --- | +| **Syntax** | vhost_traffic_status_measure_status_codes [all] [status_code1] [status_code2] ... | +| **Default** | off | +| **Context** | http | + + + +#### Parameters +- `status_code1, status_code2, ...`: Specific HTTP status codes to track (100-599) +- `all`: Track all HTTP status codes + +#### Examples + +Track specific status codes: +```nginx +vhost_traffic_status_measure_status_codes 200 404 500; +``` + +Track all status codes: +```nginx +vhost_traffic_status_measure_status_codes all; +``` + +#### Description +- By default, no specific status code tracking is enabled +- Status codes must be in ascending order +- Only valid HTTP status codes between 100 and 599 are accepted +- When using `all`, every status code will be tracked + ## Releases To cut a release, create a changelog entry PR with [git-chglog](https://github.com/git-chglog/git-chglog) diff --git a/src/ngx_http_vhost_traffic_status_display_json.c b/src/ngx_http_vhost_traffic_status_display_json.c index 5a3ba90..ca0b697 100644 --- a/src/ngx_http_vhost_traffic_status_display_json.c +++ b/src/ngx_http_vhost_traffic_status_display_json.c @@ -59,9 +59,13 @@ ngx_http_vhost_traffic_status_display_set_server_node( { u_char *p, *c; ngx_int_t rc; + ngx_uint_t i; ngx_str_t tmp, dst; + ngx_uint_t *status_codes; ngx_http_vhost_traffic_status_loc_conf_t *vtscf; + ngx_http_vhost_traffic_status_ctx_t *ctx; + ctx = ngx_http_get_module_main_conf(r, ngx_http_vhost_traffic_status_module); vtscf = ngx_http_get_module_loc_conf(r, ngx_http_vhost_traffic_status_module); tmp = *key; @@ -91,16 +95,40 @@ ngx_http_vhost_traffic_status_display_set_server_node( "display_set_server_node::escape_json_pool() failed"); } + buf = ngx_sprintf(buf, NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_SERVER_START, + &dst, vtsn->stat_request_counter, + vtsn->stat_in_bytes, + vtsn->stat_out_bytes); + + if (ctx->measure_status_codes != NULL && vtsn->stat_status_code_counter != NULL) { + buf = ngx_sprintf(buf, NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_SERVER_STATUS_CODE_START); + + buf = ngx_sprintf(buf, NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_SERVER_OTHER_STATUS_CODE, + vtsn->stat_status_code_counter[0]); + + status_codes = (ngx_uint_t *) ctx->measure_status_codes->elts; + + for (i = 0; i < ctx->measure_status_codes->nelts; i++) { + if (vtsn->stat_status_code_counter[i+1] == 0 && ctx->measure_all_status_codes) { + continue; + } + buf = ngx_sprintf(buf, NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_SERVER_STATUS_CODE, + status_codes[i], vtsn->stat_status_code_counter[i+1]); + } + + buf = ngx_sprintf(buf, NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_SERVER_STATUS_CODE_END); + } + + buf = ngx_sprintf(buf, NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_SERVER_MIDDLE, + vtsn->stat_1xx_counter, + vtsn->stat_2xx_counter, + vtsn->stat_3xx_counter, + vtsn->stat_4xx_counter, + vtsn->stat_5xx_counter); + + #if (NGX_HTTP_CACHE) - buf = ngx_sprintf(buf, NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_SERVER, - &dst, vtsn->stat_request_counter, - vtsn->stat_in_bytes, - vtsn->stat_out_bytes, - vtsn->stat_1xx_counter, - vtsn->stat_2xx_counter, - vtsn->stat_3xx_counter, - vtsn->stat_4xx_counter, - vtsn->stat_5xx_counter, + buf = ngx_sprintf(buf, NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_SERVER_END, vtsn->stat_cache_miss_counter, vtsn->stat_cache_bypass_counter, vtsn->stat_cache_expired_counter, @@ -140,15 +168,7 @@ ngx_http_vhost_traffic_status_display_set_server_node( vtsn->stat_cache_scarce_counter_oc, vtsn->stat_request_time_counter_oc); #else - buf = ngx_sprintf(buf, NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_SERVER, - &dst, vtsn->stat_request_counter, - vtsn->stat_in_bytes, - vtsn->stat_out_bytes, - vtsn->stat_1xx_counter, - vtsn->stat_2xx_counter, - vtsn->stat_3xx_counter, - vtsn->stat_4xx_counter, - vtsn->stat_5xx_counter, + buf = ngx_sprintf(buf, NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_SERVER_END, vtsn->stat_request_time_counter, ngx_http_vhost_traffic_status_node_time_queue_average( &vtsn->stat_request_times, vtscf->average_method, @@ -215,6 +235,12 @@ ngx_http_vhost_traffic_status_display_set_server(ngx_http_request_t *r, &vtscf->stats.stat_request_times, &vtsn->stat_request_times, vtscf->average_period); + if (ctx->measure_status_codes != NULL && vtsn->stat_status_code_counter != NULL) { + ngx_http_vhost_traffic_status_status_code_merge( + vtscf->stats.stat_status_code_counter, + vtsn->stat_status_code_counter, ctx->measure_status_codes->nelts+1); + } + vtscf->stats.stat_request_counter_oc += vtsn->stat_request_counter_oc; vtscf->stats.stat_in_bytes_oc += vtsn->stat_in_bytes_oc; vtscf->stats.stat_out_bytes_oc += vtsn->stat_out_bytes_oc; @@ -822,6 +848,11 @@ ngx_http_vhost_traffic_status_display_set(ngx_http_request_t *r, ngx_memzero(&vtscf->stats, sizeof(vtscf->stats)); ngx_http_vhost_traffic_status_node_time_queue_init(&vtscf->stats.stat_request_times); + if (ctx->measure_status_codes != NULL) { + vtscf->stats.stat_status_code_counter = ngx_pcalloc(r->pool, sizeof(ngx_atomic_t) * (ctx->measure_status_codes->nelts +1)); + vtscf->stats.stat_status_code_length = ctx->measure_status_codes->nelts; + } + /* main & connections */ buf = ngx_sprintf(buf, NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_S); diff --git a/src/ngx_http_vhost_traffic_status_display_json.h b/src/ngx_http_vhost_traffic_status_display_json.h index 30ad652..65a1b5d 100644 --- a/src/ngx_http_vhost_traffic_status_display_json.h +++ b/src/ngx_http_vhost_traffic_status_display_json.h @@ -40,18 +40,20 @@ #define NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_SERVER_S "\"serverZones\":{" -#if (NGX_HTTP_CACHE) -#define NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_SERVER "\"%V\":{" \ +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_SERVER_START "\"%V\":{" \ "\"requestCounter\":%uA," \ "\"inBytes\":%uA," \ - "\"outBytes\":%uA," \ - "\"responses\":{" \ + "\"outBytes\":%uA," + +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_SERVER_MIDDLE "\"responses\":{" \ "\"1xx\":%uA," \ "\"2xx\":%uA," \ "\"3xx\":%uA," \ "\"4xx\":%uA," \ - "\"5xx\":%uA," \ - "\"miss\":%uA," \ + "\"5xx\":%uA" + +#if (NGX_HTTP_CACHE) +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_SERVER_END ",\"miss\":%uA," \ "\"bypass\":%uA," \ "\"expired\":%uA," \ "\"stale\":%uA," \ @@ -92,17 +94,7 @@ "}" \ "}," #else -#define NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_SERVER "\"%V\":{" \ - "\"requestCounter\":%uA," \ - "\"inBytes\":%uA," \ - "\"outBytes\":%uA," \ - "\"responses\":{" \ - "\"1xx\":%uA," \ - "\"2xx\":%uA," \ - "\"3xx\":%uA," \ - "\"4xx\":%uA," \ - "\"5xx\":%uA" \ - "}," \ +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_SERVER_END "}," \ "\"requestMsecCounter\":%uA," \ "\"requestMsec\":%M," \ "\"requestMsecs\":{" \ @@ -128,6 +120,11 @@ "}," #endif +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_SERVER_STATUS_CODE_START "\"statusCodes\":{" +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_SERVER_STATUS_CODE ",\"%uA\":%uA" +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_SERVER_OTHER_STATUS_CODE "\"other\":%uA" +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_SERVER_STATUS_CODE_END "}, " + #define NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_FILTER_S "\"filterZones\":{" #define NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_UPSTREAM_S "\"upstreamZones\":{" diff --git a/src/ngx_http_vhost_traffic_status_display_prometheus.c b/src/ngx_http_vhost_traffic_status_display_prometheus.c index 858c2fb..f461299 100644 --- a/src/ngx_http_vhost_traffic_status_display_prometheus.c +++ b/src/ngx_http_vhost_traffic_status_display_prometheus.c @@ -54,8 +54,10 @@ ngx_http_vhost_traffic_status_display_prometheus_set_server_node( ngx_str_t server; ngx_uint_t i, n; ngx_http_vhost_traffic_status_loc_conf_t *vtscf; + ngx_http_vhost_traffic_status_ctx_t *ctx; ngx_http_vhost_traffic_status_node_histogram_bucket_t *b; + ctx = ngx_http_get_module_main_conf(r, ngx_http_vhost_traffic_status_module); vtscf = ngx_http_get_module_loc_conf(r, ngx_http_vhost_traffic_status_module); server = *key; @@ -75,6 +77,23 @@ ngx_http_vhost_traffic_status_display_prometheus_set_server_node( &vtsn->stat_request_times, vtscf->average_method, vtscf->average_period) / 1000); + + if (ctx->measure_status_codes != NULL && vtsn->stat_status_code_counter != NULL) { + ngx_uint_t *status_codes = (ngx_uint_t *) ctx->measure_status_codes->elts; + + buf = ngx_sprintf(buf, NGX_HTTP_VHOST_TRAFFIC_STATUS_PROMETHEUS_FMT_SERVER_OTHER_STATUS_CODE, + &server, vtsn->stat_status_code_counter[0]); + + for (i = 0; i < ctx->measure_status_codes->nelts; i++) { + if (vtsn->stat_status_code_counter[i+1] == 0 && ctx->measure_all_status_codes) { + continue; + } + + buf = ngx_sprintf(buf, NGX_HTTP_VHOST_TRAFFIC_STATUS_PROMETHEUS_FMT_SERVER_STATUS_CODE, + &server, status_codes[i], vtsn->stat_status_code_counter[i+1]); + } + } + /* histogram */ b = &vtsn->stat_request_buckets; @@ -157,6 +176,11 @@ ngx_http_vhost_traffic_status_display_prometheus_set_server(ngx_http_request_t * &vtscf->stats.stat_request_times, &vtsn->stat_request_times, vtscf->average_period); + if (ctx->measure_status_codes != NULL && vtsn->stat_status_code_counter != NULL) { + ngx_http_vhost_traffic_status_status_code_merge(vtscf->stats.stat_status_code_counter, + vtsn->stat_status_code_counter, ctx->measure_status_codes->nelts+1); + } + #if (NGX_HTTP_CACHE) vtscf->stats.stat_cache_miss_counter += vtsn->stat_cache_miss_counter; @@ -497,6 +521,11 @@ ngx_http_vhost_traffic_status_display_prometheus_set(ngx_http_request_t *r, ngx_memzero(&vtscf->stats, sizeof(vtscf->stats)); ngx_http_vhost_traffic_status_node_time_queue_init(&vtscf->stats.stat_request_times); + if (ctx->measure_status_codes != NULL) { + vtscf->stats.stat_status_code_counter = ngx_pcalloc(r->pool, sizeof(ngx_atomic_t) * (ctx->measure_status_codes->nelts+1)); + vtscf->stats.stat_status_code_length = ctx->measure_status_codes->nelts; + } + /* main & connections */ buf = ngx_http_vhost_traffic_status_display_prometheus_set_main(r, buf); diff --git a/src/ngx_http_vhost_traffic_status_display_prometheus.h b/src/ngx_http_vhost_traffic_status_display_prometheus.h index 60ab37f..7a9becd 100644 --- a/src/ngx_http_vhost_traffic_status_display_prometheus.h +++ b/src/ngx_http_vhost_traffic_status_display_prometheus.h @@ -35,6 +35,8 @@ "# TYPE nginx_vts_server_bytes_total counter\n" \ "# HELP nginx_vts_server_requests_total The requests counter\n" \ "# TYPE nginx_vts_server_requests_total counter\n" \ + "# HELP nginx_vts_status_code_requests_total The requests counter by status code \n" \ + "# TYPE nginx_vts_status_code_requests_total counter\n" \ "# HELP nginx_vts_server_request_seconds_total The request processing " \ "time in seconds\n" \ "# TYPE nginx_vts_server_request_seconds_total counter\n" \ @@ -56,6 +58,12 @@ "nginx_vts_server_request_seconds_total{host=\"%V\"} %.3f\n" \ "nginx_vts_server_request_seconds{host=\"%V\"} %.3f\n" +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_PROMETHEUS_FMT_SERVER_OTHER_STATUS_CODE \ + "nginx_vts_status_code_requests_total{host=\"%V\",code=\"other\"} %uA\n" + +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_PROMETHEUS_FMT_SERVER_STATUS_CODE \ + "nginx_vts_status_code_requests_total{host=\"%V\",code=\"%d\"} %uA\n" + #define NGX_HTTP_VHOST_TRAFFIC_STATUS_PROMETHEUS_FMT_SERVER_HISTOGRAM_BUCKET \ "nginx_vts_server_request_duration_seconds_bucket{host=\"%V\"," \ "le=\"%.3f\"} %uA\n" diff --git a/src/ngx_http_vhost_traffic_status_module.c b/src/ngx_http_vhost_traffic_status_module.c index 5625232..9e12c9f 100644 --- a/src/ngx_http_vhost_traffic_status_module.c +++ b/src/ngx_http_vhost_traffic_status_module.c @@ -21,6 +21,8 @@ static void ngx_http_vhost_traffic_status_rbtree_insert_value( ngx_rbtree_node_t *sentinel); static ngx_int_t ngx_http_vhost_traffic_status_init_zone( ngx_shm_zone_t *shm_zone, void *data); +static char *ngx_http_vhost_traffic_status_measure_status_codes(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); static char *ngx_http_vhost_traffic_status_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static char *ngx_http_vhost_traffic_status_dump(ngx_conf_t *cf, @@ -139,6 +141,13 @@ static ngx_command_t ngx_http_vhost_traffic_status_commands[] = { 0, NULL }, + { ngx_string("vhost_traffic_status_measure_status_codes"), + NGX_HTTP_MAIN_CONF|NGX_CONF_NOARGS|NGX_CONF_1MORE, + ngx_http_vhost_traffic_status_measure_status_codes, + 0, + 0, + NULL }, + { ngx_string("vhost_traffic_status_dump"), NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE12, ngx_http_vhost_traffic_status_dump, @@ -459,6 +468,69 @@ ngx_http_vhost_traffic_status_init_zone(ngx_shm_zone_t *shm_zone, void *data) } +static char * +ngx_http_vhost_traffic_status_measure_status_codes(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_vhost_traffic_status_ctx_t *ctx; + ngx_str_t *value; + ngx_int_t n; + ngx_int_t previous_n; + ngx_uint_t i; + ngx_int_t *status_code; + + ctx = ngx_http_conf_get_module_main_conf(cf, ngx_http_vhost_traffic_status_module); + if (ctx == NULL) { + return NGX_CONF_ERROR; + } + + ctx->measure_status_codes = ngx_array_create(cf->pool, 1, sizeof(ngx_int_t)); + previous_n = 0; + value = cf->args->elts; + + /* arguments process */ + if (ngx_strncmp(value[1].data, "all", 3) == 0) { + for (n = 100; n < 600; n++) { + status_code = ngx_array_push(ctx->measure_status_codes); + if (status_code == NULL) { + return NGX_CONF_ERROR; + } + *status_code = n; + } + ctx->measure_all_status_codes = 1; + return NGX_OK; + } + for (i = 1; i < cf->args->nelts; i++) { + n = ngx_atoi(value[i].data, value[i].len); + if (n == NGX_ERROR || n == 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%V\"", &value[i]); + return NGX_CONF_ERROR; + } + + if (n < previous_n) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "status codes must be ordered"); + return NGX_CONF_ERROR; + } + + if (n < 100 || n > 599) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid status_code \"%V\"", &value[i]); + return NGX_CONF_ERROR; + } + + status_code = ngx_array_push(ctx->measure_status_codes); + if (status_code == NULL) { + return NGX_CONF_ERROR; + } + + *status_code = n; + previous_n = n; + } + + ctx->measure_all_status_codes = 0; + + return NGX_CONF_OK; +} + + static char * ngx_http_vhost_traffic_status_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { diff --git a/src/ngx_http_vhost_traffic_status_module.h b/src/ngx_http_vhost_traffic_status_module.h index 4557b8b..6b63785 100644 --- a/src/ngx_http_vhost_traffic_status_module.h +++ b/src/ngx_http_vhost_traffic_status_module.h @@ -256,6 +256,9 @@ typedef struct { ngx_str_t dump_file; ngx_msec_t dump_period; ngx_event_t dump_event; + + ngx_flag_t measure_all_status_codes; + ngx_array_t *measure_status_codes; } ngx_http_vhost_traffic_status_ctx_t; diff --git a/src/ngx_http_vhost_traffic_status_node.c b/src/ngx_http_vhost_traffic_status_node.c index e60d1f9..f5f9ef0 100644 --- a/src/ngx_http_vhost_traffic_status_node.c +++ b/src/ngx_http_vhost_traffic_status_node.c @@ -267,6 +267,8 @@ ngx_http_vhost_traffic_status_node_lookup(ngx_rbtree_t *rbtree, ngx_str_t *key, void ngx_http_vhost_traffic_status_node_zero(ngx_http_vhost_traffic_status_node_t *vtsn) { + ngx_uint_t i; + vtsn->stat_request_counter = 0; vtsn->stat_in_bytes = 0; vtsn->stat_out_bytes = 0; @@ -292,6 +294,10 @@ ngx_http_vhost_traffic_status_node_zero(ngx_http_vhost_traffic_status_node_t *vt vtsn->stat_request_time_counter_oc = 0; vtsn->stat_response_time_counter_oc = 0; + for (i = 0; i < vtsn->stat_status_code_length; i++) { + vtsn->stat_status_code_counter[i] = 0; + } + #if (NGX_HTTP_CACHE) vtsn->stat_cache_miss_counter = 0; vtsn->stat_cache_bypass_counter = 0; @@ -321,7 +327,7 @@ ngx_http_vhost_traffic_status_node_zero(ngx_http_vhost_traffic_status_node_t *vt */ void ngx_http_vhost_traffic_status_node_init(ngx_http_request_t *r, - ngx_http_vhost_traffic_status_node_t *vtsn) + ngx_http_vhost_traffic_status_node_t *vtsn, ngx_int_t status_code_slot) { ngx_msec_int_t ms; @@ -342,7 +348,7 @@ ngx_http_vhost_traffic_status_node_init(ngx_http_request_t *r, ms = ngx_http_vhost_traffic_status_request_time(r); vtsn->stat_request_time = (ngx_msec_t) ms; - ngx_http_vhost_traffic_status_node_update(r, vtsn, ms); + ngx_http_vhost_traffic_status_node_update(r, vtsn, ms, status_code_slot); } @@ -352,7 +358,7 @@ ngx_http_vhost_traffic_status_node_init(ngx_http_request_t *r, */ void ngx_http_vhost_traffic_status_node_set(ngx_http_request_t *r, - ngx_http_vhost_traffic_status_node_t *vtsn) + ngx_http_vhost_traffic_status_node_t *vtsn, ngx_int_t status_code_slot) { ngx_msec_int_t ms; ngx_http_vhost_traffic_status_node_t ovtsn; @@ -363,7 +369,7 @@ ngx_http_vhost_traffic_status_node_set(ngx_http_request_t *r, ovtsn = *vtsn; ms = ngx_http_vhost_traffic_status_request_time(r); - ngx_http_vhost_traffic_status_node_update(r, vtsn, ms); + ngx_http_vhost_traffic_status_node_update(r, vtsn, ms, status_code_slot); vtsn->stat_request_time = ngx_http_vhost_traffic_status_node_time_queue_average( &vtsn->stat_request_times, vtscf->average_method, @@ -375,7 +381,7 @@ ngx_http_vhost_traffic_status_node_set(ngx_http_request_t *r, void ngx_http_vhost_traffic_status_node_update(ngx_http_request_t *r, - ngx_http_vhost_traffic_status_node_t *vtsn, ngx_msec_int_t ms) + ngx_http_vhost_traffic_status_node_t *vtsn, ngx_msec_int_t ms, ngx_int_t status_code_slot) { ngx_uint_t status = r->headers_out.status; @@ -385,6 +391,10 @@ ngx_http_vhost_traffic_status_node_update(ngx_http_request_t *r, ngx_http_vhost_traffic_status_add_rc(status, vtsn); + if (status_code_slot != -1 && vtsn->stat_status_code_counter != NULL ) { + vtsn->stat_status_code_counter[status_code_slot]++; + } + vtsn->stat_request_time_counter += (ngx_atomic_uint_t) ms; ngx_http_vhost_traffic_status_node_time_queue_insert(&vtsn->stat_request_times, @@ -587,6 +597,14 @@ ngx_http_vhost_traffic_status_node_time_queue_merge( (void) ngx_cpymem(a, &q, sizeof(q)); } +void ngx_http_vhost_traffic_status_status_code_merge(ngx_atomic_t *dst, ngx_atomic_t *src, ngx_uint_t n) +{ + ngx_uint_t i; + + for (i = 0; i < n; i++) { + dst[i] += src[i]; + } +} void ngx_http_vhost_traffic_status_node_histogram_bucket_init(ngx_http_request_t *r, diff --git a/src/ngx_http_vhost_traffic_status_node.h b/src/ngx_http_vhost_traffic_status_node.h index 9cc4a0e..0e7d0b8 100644 --- a/src/ngx_http_vhost_traffic_status_node.h +++ b/src/ngx_http_vhost_traffic_status_node.h @@ -58,6 +58,8 @@ typedef struct { ngx_atomic_t stat_3xx_counter; ngx_atomic_t stat_4xx_counter; ngx_atomic_t stat_5xx_counter; + uint stat_status_code_length; + ngx_atomic_t *stat_status_code_counter; ngx_atomic_t stat_request_time_counter; ngx_msec_t stat_request_time; @@ -115,11 +117,11 @@ ngx_rbtree_node_t *ngx_http_vhost_traffic_status_node_lookup( void ngx_http_vhost_traffic_status_node_zero( ngx_http_vhost_traffic_status_node_t *vtsn); void ngx_http_vhost_traffic_status_node_init(ngx_http_request_t *r, - ngx_http_vhost_traffic_status_node_t *vtsn); + ngx_http_vhost_traffic_status_node_t *vtsn, ngx_int_t status_code_slot); void ngx_http_vhost_traffic_status_node_set(ngx_http_request_t *r, - ngx_http_vhost_traffic_status_node_t *vtsn); + ngx_http_vhost_traffic_status_node_t *vtsn, ngx_int_t status_code_slot); void ngx_http_vhost_traffic_status_node_update(ngx_http_request_t *r, - ngx_http_vhost_traffic_status_node_t *vtsn, ngx_msec_int_t ms); + ngx_http_vhost_traffic_status_node_t *vtsn, ngx_msec_int_t ms, ngx_int_t status_code_slot); void ngx_http_vhost_traffic_status_node_time_queue_zero( ngx_http_vhost_traffic_status_node_time_queue_t *q); @@ -150,6 +152,7 @@ void ngx_http_vhost_traffic_status_node_time_queue_merge( ngx_http_vhost_traffic_status_node_time_queue_t *a, ngx_http_vhost_traffic_status_node_time_queue_t *b, ngx_msec_t period); +void ngx_http_vhost_traffic_status_status_code_merge(ngx_atomic_t *dst, ngx_atomic_t *src, ngx_uint_t n); void ngx_http_vhost_traffic_status_node_histogram_bucket_init( ngx_http_request_t *r, diff --git a/src/ngx_http_vhost_traffic_status_shm.c b/src/ngx_http_vhost_traffic_status_shm.c index 78d181c..93009f0 100644 --- a/src/ngx_http_vhost_traffic_status_shm.c +++ b/src/ngx_http_vhost_traffic_status_shm.c @@ -87,6 +87,7 @@ ngx_http_vhost_traffic_status_shm_add_node(ngx_http_request_t *r, size_t size; unsigned init; uint32_t hash; + ngx_int_t status_code_slot; ngx_slab_pool_t *shpool; ngx_rbtree_node_t *node, *lrun; ngx_http_vhost_traffic_status_ctx_t *ctx; @@ -104,6 +105,18 @@ ngx_http_vhost_traffic_status_shm_add_node(ngx_http_request_t *r, shpool = (ngx_slab_pool_t *) vtscf->shm_zone->shm.addr; + + status_code_slot = 0; + if (ctx->measure_all_status_codes) { + if (r->headers_out.status >= 100 && r->headers_out.status < 600) { + // slot 0 is reserved to other status codes <100 and >600 + status_code_slot = r->headers_out.status - 99; + } + } else if (ctx->measure_status_codes != NULL) { + status_code_slot = ngx_http_vhost_traffic_status_find_status_code_slot(r->headers_out.status, + ctx->measure_status_codes); + } + ngx_shmtx_lock(&shpool->mutex); /* find node */ @@ -149,7 +162,32 @@ ngx_http_vhost_traffic_status_shm_add_node(ngx_http_request_t *r, node->key = hash; vtsn->len = key->len; - ngx_http_vhost_traffic_status_node_init(r, vtsn); + + if (ctx->measure_status_codes != NULL) { + vtsn->stat_status_code_counter = ngx_slab_alloc_locked(shpool, sizeof(ngx_atomic_t) * (ctx->measure_status_codes->nelts + 1)); + if (vtsn->stat_status_code_counter == NULL) { + shm_info = ngx_pcalloc(r->pool, sizeof(ngx_http_vhost_traffic_status_shm_info_t)); + if (shm_info == NULL) { + ngx_slab_free_locked(shpool, node); + ngx_shmtx_unlock(&shpool->mutex); + return NGX_ERROR; + } + + ngx_http_vhost_traffic_status_shm_info(r, shm_info); + + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "shm_add_node::ngx_slab_alloc_locked() failed: " + "used_size[%ui], used_node[%ui]", + shm_info->used_size, shm_info->used_node); + + ngx_slab_free_locked(shpool, node); + ngx_shmtx_unlock(&shpool->mutex); + return NGX_ERROR; + } + vtsn->stat_status_code_length = ctx->measure_status_codes->nelts; + } + + ngx_http_vhost_traffic_status_node_init(r, vtsn, status_code_slot); vtsn->stat_upstream.type = type; ngx_memcpy(vtsn->data, key->data, key->len); @@ -158,7 +196,7 @@ ngx_http_vhost_traffic_status_shm_add_node(ngx_http_request_t *r, } else { init = NGX_HTTP_VHOST_TRAFFIC_STATUS_NODE_FIND; vtsn = (ngx_http_vhost_traffic_status_node_t *) &node->color; - ngx_http_vhost_traffic_status_node_set(r, vtsn); + ngx_http_vhost_traffic_status_node_set(r, vtsn, status_code_slot); } /* set addition */ @@ -520,6 +558,27 @@ ngx_http_vhost_traffic_status_shm_add_upstream(ngx_http_request_t *r) return NGX_OK; } +static int +ngx_http_vhost_traffic_status_find_status_code_slot_cmp(const void *one, const void *two) +{ + return (*(ngx_uint_t *) one - *(ngx_uint_t *) two); +} + +ngx_uint_t +ngx_http_vhost_traffic_status_find_status_code_slot(ngx_uint_t status, ngx_array_t *status_codes) +{ + ngx_uint_t *found = (ngx_uint_t *) bsearch(&status, status_codes->elts, status_codes->nelts, + sizeof(ngx_uint_t), + ngx_http_vhost_traffic_status_find_status_code_slot_cmp); + + if (found == NULL) { + ngx_log_error(NGX_LOG_DEBUG, ngx_cycle->log, 0, + "Status code %ui not found in status_codes array", status); + return 0; + } + + return found - (ngx_uint_t *)status_codes->elts + 1; +} #if (NGX_HTTP_CACHE) diff --git a/src/ngx_http_vhost_traffic_status_shm.h b/src/ngx_http_vhost_traffic_status_shm.h index bbc9d97..8d351ca 100644 --- a/src/ngx_http_vhost_traffic_status_shm.h +++ b/src/ngx_http_vhost_traffic_status_shm.h @@ -22,6 +22,7 @@ typedef struct { ngx_int_t ngx_http_vhost_traffic_status_shm_add_server(ngx_http_request_t *r); ngx_int_t ngx_http_vhost_traffic_status_shm_add_filter(ngx_http_request_t *r); ngx_int_t ngx_http_vhost_traffic_status_shm_add_upstream(ngx_http_request_t *r); +ngx_uint_t ngx_http_vhost_traffic_status_find_status_code_slot(ngx_uint_t status, ngx_array_t *status_codes); #if (NGX_HTTP_CACHE) ngx_int_t ngx_http_vhost_traffic_status_shm_add_cache(ngx_http_request_t *r);