static ngx_int_t
ngx_http_reqstat_input_body_filter(ngx_http_request_t *r, ngx_buf_t *buf)
{
    ngx_uint_t                    i, diff;
    ngx_http_reqstat_conf_t      *slcf;
    ngx_http_reqstat_store_t     *store;
    ngx_http_reqstat_rbnode_t    *fnode, **fnode_store;

    slcf = ngx_http_get_module_loc_conf(r, ngx_http_reqstat_module);

    if (slcf->monitor == NULL) {
        return ngx_http_next_input_body_filter(r, buf);
    }

    store = ngx_http_get_module_ctx(r, ngx_http_reqstat_module);
    if (store == NULL) {
        store = ngx_http_reqstat_create_store(r, slcf);
        if (store == NULL) {
            return NGX_ERROR;
        }

        ngx_http_set_ctx(r, store, ngx_http_reqstat_module);
    }

    if (store->bypass) {
        return ngx_http_next_input_body_filter(r, buf);
    }

    diff = r->connection->received - store->recv;
    store->recv = r->connection->received;

    fnode_store = store->monitor_index.elts;
    for (i = 0; i < store->monitor_index.nelts; i++) {
        fnode = fnode_store[i];
        ngx_http_reqstat_count(fnode, NGX_HTTP_REQSTAT_BYTES_IN, diff);
    }

    return ngx_http_next_input_body_filter(r, buf);
}
ngx_int_t
ngx_http_reqstat_log_flow(ngx_http_request_t *r)
{
    ngx_uint_t                    i, diff;
    ngx_http_reqstat_conf_t      *slcf;
    ngx_http_reqstat_store_t     *store;
    ngx_http_reqstat_rbnode_t    *fnode, **fnode_store;

    slcf = ngx_http_get_module_loc_conf(r, ngx_http_reqstat_module);

    if (slcf->monitor == NULL) {
        return NGX_OK;
    }

    store = ngx_http_get_module_ctx(r, ngx_http_reqstat_module);
    if (store == NULL) {
        store = ngx_http_reqstat_create_store(r, slcf);
        if (store == NULL) {
            return NGX_ERROR;
        }

        ngx_http_set_ctx(r, store, ngx_http_reqstat_module);
    }

    if (store->bypass) {
        return NGX_OK;
    }

    diff = r->connection->sent - store->sent;
    store->sent = r->connection->sent;

    fnode_store = store->monitor_index.elts;
    for (i = 0; i < store->monitor_index.nelts; i++) {
        fnode = fnode_store[i];
        ngx_http_reqstat_count(fnode, NGX_HTTP_REQSTAT_BYTES_OUT, diff);
    }

    return NGX_OK;
}
static ngx_int_t
ngx_http_reqstat_log_handler(ngx_http_request_t *r)
{
    u_char                       *p;
    ngx_int_t                    *indicator, iv;
    ngx_uint_t                    i, j, k, status, utries;
    ngx_time_t                   *tp;
    ngx_msec_int_t                ms, total_ms;
    ngx_shm_zone_t              **shm_zone, *z;
    ngx_http_reqstat_ctx_t       *ctx;
    ngx_http_reqstat_conf_t      *rcf;
    ngx_http_reqstat_store_t     *store;
    ngx_http_reqstat_rbnode_t    *fnode, **fnode_store;
    ngx_http_upstream_state_t    *state;
    ngx_http_variable_value_t    *v;

    switch (ngx_http_reqstat_check_enable(r, &rcf, &store)) {
        case NGX_ERROR:
            return NGX_ERROR;

        case NGX_DECLINED:
        case NGX_AGAIN:
            return NGX_OK;

        default:
            break;
    }

    shm_zone = rcf->monitor->elts;
    fnode_store = store->monitor_index.elts;
    for (i = 0; i < store->monitor_index.nelts; i++) {
        fnode = fnode_store[i];
        if (r->connection->requests == 1) {
            ngx_http_reqstat_count(fnode, NGX_HTTP_REQSTAT_CONN_TOTAL, 1);
        }

        ngx_http_reqstat_count(fnode, NGX_HTTP_REQSTAT_REQ_TOTAL, 1);
        ngx_http_reqstat_count(fnode, NGX_HTTP_REQSTAT_BYTES_IN,
                               ngx_http_request_received(r)
                                    - (store ? store->recv : 0));

        if (r->err_status) {
            status = r->err_status;

        } else if (r->headers_out.status) {
            status = r->headers_out.status;

        } else if (r->http_version == NGX_HTTP_VERSION_9) {
            status = 9;

        } else {
            status = 0;
        }

        if (status >= 200 && status < 300) {
            ngx_http_reqstat_count(fnode, NGX_HTTP_REQSTAT_2XX, 1);

            switch (status) {
            case 200:
                ngx_http_reqstat_count(fnode, NGX_HTTP_REQSTAT_200, 1);
                break;

            case 206:
                ngx_http_reqstat_count(fnode, NGX_HTTP_REQSTAT_206, 1);
                break;

            default:
                ngx_http_reqstat_count(fnode,
                                       NGX_HTTP_REQSTAT_OTHER_DETAIL_STATUS, 1);
                break;
            }

        } else if (status >= 300 && status < 400) {
            ngx_http_reqstat_count(fnode, NGX_HTTP_REQSTAT_3XX, 1);

            switch (status) {
            case 302:
                ngx_http_reqstat_count(fnode, NGX_HTTP_REQSTAT_302, 1);
                break;

            case 304:
                ngx_http_reqstat_count(fnode, NGX_HTTP_REQSTAT_304, 1);
                break;

            default:
                ngx_http_reqstat_count(fnode,
                                       NGX_HTTP_REQSTAT_OTHER_DETAIL_STATUS, 1);
                break;
            }

        } else if (status >= 400 && status < 500) {
            ngx_http_reqstat_count(fnode, NGX_HTTP_REQSTAT_4XX, 1);

            switch (status) {
            case 403:
                ngx_http_reqstat_count(fnode, NGX_HTTP_REQSTAT_403, 1);
                break;

            case 404:
                ngx_http_reqstat_count(fnode, NGX_HTTP_REQSTAT_404, 1);
                break;

            case 416:
                ngx_http_reqstat_count(fnode, NGX_HTTP_REQSTAT_416, 1);
                break;

            case 499:
                ngx_http_reqstat_count(fnode, NGX_HTTP_REQSTAT_499, 1);
                break;

            default:
                ngx_http_reqstat_count(fnode,
                                       NGX_HTTP_REQSTAT_OTHER_DETAIL_STATUS, 1);
                break;
            }

        } else if (status >= 500 && status < 600) {
            ngx_http_reqstat_count(fnode, NGX_HTTP_REQSTAT_5XX, 1);

            switch (status) {
            case 500:
                ngx_http_reqstat_count(fnode, NGX_HTTP_REQSTAT_500, 1);
                break;

            case 502:
                ngx_http_reqstat_count(fnode, NGX_HTTP_REQSTAT_502, 1);
                break;

            case 503:
                ngx_http_reqstat_count(fnode, NGX_HTTP_REQSTAT_503, 1);
                break;

            case 504:
                ngx_http_reqstat_count(fnode, NGX_HTTP_REQSTAT_504, 1);
                break;

            case 508:
                ngx_http_reqstat_count(fnode, NGX_HTTP_REQSTAT_508, 1);
                break;

            default:
                ngx_http_reqstat_count(fnode,
                                       NGX_HTTP_REQSTAT_OTHER_DETAIL_STATUS, 1);
                break;
            }

        } else {
            ngx_http_reqstat_count(fnode, NGX_HTTP_REQSTAT_OTHER_STATUS, 1);

            ngx_http_reqstat_count(fnode, NGX_HTTP_REQSTAT_OTHER_DETAIL_STATUS,
                                   1);
        }

        /* response status of last upstream peer */

        if (r->upstream_states != NULL && r->upstream_states->nelts > 0) {
            ngx_http_upstream_state_t *state = r->upstream_states->elts;
            status = state[r->upstream_states->nelts - 1].status;

            if (status >= 400 && status < 500) {
                ngx_http_reqstat_count(fnode, NGX_HTTP_REQSTAT_UPS_4XX, 1);

            } else if (status >= 500 && status < 600) {
                ngx_http_reqstat_count(fnode, NGX_HTTP_REQSTAT_UPS_5XX, 1);
            }
        }

        tp = ngx_timeofday();

        ms = (ngx_msec_int_t)
             ((tp->sec - r->start_sec) * 1000 + (tp->msec - r->start_msec));
        ms = ngx_max(ms, 0);
        ngx_http_reqstat_count(fnode, NGX_HTTP_REQSTAT_RT, ms);

        if (r->upstream_states != NULL && r->upstream_states->nelts > 0) {
            ngx_http_reqstat_count(fnode, NGX_HTTP_REQSTAT_UPS_REQ, 1);

            j = 0;
            total_ms = 0;
            utries = 0;
            state = r->upstream_states->elts;

            for ( ;; ) {

                utries++;

#if nginx_version >= 1009002
                ms = state[j].response_time;
#else
                ms = (ngx_msec_int_t) (state[j].response_sec * 1000
                                               + state[j].response_msec);
#endif
                ms = ngx_max(ms, 0);
                total_ms += ms;

                if (++j == r->upstream_states->nelts) {
                    break;
                }

                if (state[j].peer == NULL) {
                    if (++j == r->upstream_states->nelts) {
                        break;
                    }
                }
            }

            ngx_http_reqstat_count(fnode, NGX_HTTP_REQSTAT_UPS_RT,
                                   total_ms);
            ngx_http_reqstat_count(fnode, NGX_HTTP_REQSTAT_UPS_TRIES,
                                   utries);
        }

        z = shm_zone[i];
        ctx = z->data;

        if (ctx->user_defined) {
            indicator = ctx->user_defined->elts;
            for (j = 0; j < ctx->user_defined->nelts; j++) {
                v = ngx_http_get_indexed_variable(r, indicator[j]);
                if (v == NULL || v->not_found || !v->valid) {
                    ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
                                  "variable is uninitialized");
                    continue;
                }

                for (k = 0, p = v->data + v->len - 1; p >= v->data; p--) {
                    if (*p == '.') {
                        k = v->data + v->len - 1 - p;
                        continue;
                    }

                    if (*p < '0' || *p > '9') {
                        break;
                    }
                }

                p++;

                if (k) {
                    iv = ngx_atofp(p, v->data + v->len - p, k);

                } else {
                    iv = ngx_atoi(p, v->data + v->len - p);
                }

                if (iv == NGX_ERROR) {
                    continue;
                }

                ngx_http_reqstat_count(fnode, NGX_HTTP_REQSTAT_EXTRA(j), iv);
            }
        }
    }

    return NGX_OK;
}
static ngx_int_t
ngx_http_reqstat_log_handler(ngx_http_request_t *r)
{
    ngx_uint_t                    i, j, status, utries;
    ngx_time_t                   *tp;
    ngx_msec_int_t                ms, total_ms;
    ngx_http_reqstat_conf_t      *slcf;
    ngx_http_reqstat_rbnode_t    *fnode, **fnode_store;
    ngx_http_upstream_state_t    *state;
    ngx_http_reqstat_store_t     *store;

    slcf = ngx_http_get_module_loc_conf(r, ngx_http_reqstat_module);

    if (slcf->monitor == NULL) {
        return NGX_OK;
    }

    store = ngx_http_get_module_ctx(r, ngx_http_reqstat_module);

    if (store == NULL) {
        store = ngx_http_reqstat_create_store(r, slcf);
        if (store == NULL) {
            return NGX_ERROR;
        }
    } else {
        store = ngx_http_reqstat_lookup_fnode(r, slcf);
        if (store == NULL) {
            return NGX_ERROR;
        }
    }

    if (store->bypass) {
        return NGX_OK;
    }

    fnode_store = store->monitor_index.elts;
    for (i = 0; i < store->monitor_index.nelts; i++) {
        fnode = fnode_store[i];
        if (r->connection->requests == 1) {
            ngx_http_reqstat_count(fnode, NGX_HTTP_REQSTAT_CONN_TOTAL, 1);
        }

        ngx_http_reqstat_count(fnode, NGX_HTTP_REQSTAT_REQ_TOTAL, 1);
        ngx_http_reqstat_count(fnode, NGX_HTTP_REQSTAT_BYTES_IN,
                               r->connection->received
                                    - (store ? store->recv : 0) + store->bytes_in);
        ngx_http_reqstat_count(fnode, NGX_HTTP_REQSTAT_BYTES_OUT,
                               r->connection->sent
                                    - (store ? store->sent : 0));

        if (r->err_status) {
            status = r->err_status;

        } else if (r->headers_out.status) {
            status = r->headers_out.status;

        } else if (r->http_version == NGX_HTTP_VERSION_9) {
            status = 9;

        } else {
            status = 0;
        }

        if (status >= 200 && status < 300) {
            ngx_http_reqstat_count(fnode, NGX_HTTP_REQSTAT_2XX, 1);

        } else if (status >= 300 && status < 400) {
            ngx_http_reqstat_count(fnode, NGX_HTTP_REQSTAT_3XX, 1);

        } else if (status >= 400 && status < 500) {
            ngx_http_reqstat_count(fnode, NGX_HTTP_REQSTAT_4XX, 1);

        } else if (status >= 500 && status < 600) {
            ngx_http_reqstat_count(fnode, NGX_HTTP_REQSTAT_5XX, 1);

        } else {
            ngx_http_reqstat_count(fnode, NGX_HTTP_REQSTAT_OTHER_STATUS, 1);
        }

        tp = ngx_timeofday();

        ms = (ngx_msec_int_t)
             ((tp->sec - r->start_sec) * 1000 + (tp->msec - r->start_msec));
        ms = ngx_max(ms, 0);
        ngx_http_reqstat_count(fnode, NGX_HTTP_REQSTAT_RT, ms);

        if (r->upstream_states != NULL && r->upstream_states->nelts > 0) {
            ngx_http_reqstat_count(fnode, NGX_HTTP_REQSTAT_UPS_REQ, 1);

            j = 0;
            total_ms = 0;
            utries = 0;
            state = r->upstream_states->elts;

            for ( ;; ) {

                utries++;

                ms = (ngx_msec_int_t) (state[j].response_sec * 1000
                                               + state[j].response_msec);
                ms = ngx_max(ms, 0);
                total_ms += ms;

                if (++j == r->upstream_states->nelts) {
                    break;
                }

                if (state[j].peer == NULL) {
                    if (++j == r->upstream_states->nelts) {
                        break;
                    }
                }
            }

            ngx_http_reqstat_count(fnode, NGX_HTTP_REQSTAT_UPS_RT,
                                   total_ms);
            ngx_http_reqstat_count(fnode, NGX_HTTP_REQSTAT_UPS_TRIES,
                                   utries);
        }
    }

    return NGX_OK;
}