WARNING

To collect statistics, enable a shared memory zone in the appropriate contexts using:

  1. status_zone directive set in server and location context have separate shared memory zone and each request is accounted for in both of them.
  2. Number of processing requests is only available in server context, but you may use upstream zone metrics as an approximation.
  3. 499 status code from logs corresponds to angie_http_server_zones_requests_discarded in metrics.
  4. Ignore the “nested location blocks” thing from status_zone docs. It’s evil to nest location blocks because the inheritance rule for nested location blocks is surprisingly different from others.

The server zone statistics is working before the location is finally determined (and it allows it to have an additional metric like number of requests currently processing by the server). So it’s technically not possible to disable it for a particular location.

Note also that the location can be changed multiple times during the request processing, while the server context stays the same for a particular request. That’s the reason why the location statistics are only counted at the end of request processing.

Note that each request is counted twice at most, first before the location is determined, last at the end of request processing.

  • ngx_http_server_stats_s and ngx_http_get_server_stats() for server
  • ngx_http_location_stats_t and ngx_http_get_location_stats() for location

ngx_http_calculate_request_statistic() and ngx_http_calculate_post_request_statistic() combined collects statistics for server status_zone, and the later is also responsible for location status_zone collection.

This is the first function’s code:

void
ngx_http_calculate_request_statistic(ngx_http_request_t *r,
    ngx_http_status_zone_t *status_zone)
{
    ngx_http_server_stats_t  *stats;
 
    stats = ngx_http_get_server_stats(r, status_zone);
    if (stats == NULL) {
        return;
    }
 
    (void) ngx_atomic_fetch_add(&stats->processing, 1);
    (void) ngx_atomic_fetch_add(&stats->requests, 1);
 
    r->server_stats = stats;
}

Bonus script

You may use this awk command to count first level of URL prefixes in $10:

awk -F\\t '{
  uri = $10
  sub(/\?.*$/, "", uri)                     # strip query string
  i = 1; lead = ""; n = length(uri)
  while (i <= n && substr(uri, i, 1) == "/") { lead = lead "/"; i++ }   # preserve leading slashes
  rest = substr(uri, i)
  if (rest == "") { print lead; next }      # only slashes or empty
  j = index(rest, "/")
  if (j == 0) print lead rest               # no further path -> keep segment without trailing slash
  else print lead substr(rest, 1, j-1) "/"  # had more path -> append trailing slash
}'

Also note https://nginx.org/en/docs/http/ngx_http_core_module.html#merge_slashes, which applies to