Nginx之Keepalive请求长连接复用率统计
该模块的实现原理比较简单:在NGX_LOG_PHASE阶段加入一个handler,根据请求是否upstream,再结合upstream->peer.cached参数即可判断该请求是否复用长连接。
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>
#include <nginx.h>
#include <ngx_files.h>
#define KEEPALIVE_LOG_DEBUG
#define KEEPALIVE_LOG_DEBUG_LEVEL NGX_LOG_NOTICE
#define KEEPALIVE_LOG_MAX_LOG_LEN 1024
typedef struct {
ngx_log_t *default_log;
}ngx_http_keepalive_log_main_conf_t;
typedef struct {
ngx_flag_t on;
ngx_log_t *log;
} ngx_http_keepalive_log_loc_conf_t;
static void* ngx_http_keepalive_log_create_main_conf(ngx_conf_t *cf);
static void* ngx_http_keepalive_log_create_loc_conf(ngx_conf_t *cf);
static char* ngx_http_keepalive_log_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child);
static ngx_int_t ngx_http_keepalive_log_init(ngx_conf_t *cf);
static ngx_int_t ngx_http_keepalive_log_init_process(ngx_cycle_t *cycle);
static ngx_int_t ngx_http_keepalive_log_handler(ngx_http_request_t *r);
static void ngx_http_keepalive_log_get_req_info(ngx_http_request_t *r, ngx_str_t *serv, ngx_str_t *hostname, ngx_str_t *ip);
static ngx_log_t *ngx_log_create(ngx_cycle_t *cycle, ngx_str_t *name);
static char* ngx_http_keepalive_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
static ngx_http_module_t ngx_http_keepalive_log_module_ctx = {
NULL,
ngx_http_keepalive_log_init, /* postconfiguration */
ngx_http_keepalive_log_create_main_conf, /* create main configuration */
NULL,
NULL,
NULL,
ngx_http_keepalive_log_create_loc_conf,
ngx_http_keepalive_log_merge_loc_conf
};
static ngx_command_t ngx_http_keepalive_log_commands[] = {
{
ngx_string("keepalive_log"),
NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_HTTP_LIF_CONF | NGX_CONF_TAKE1,
ngx_http_keepalive_log_set_log,
NGX_HTTP_LOC_CONF_OFFSET,
0,
NULL
},
{
ngx_string("keepalive_log_enable"),
NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_CONF_TAKE1,
ngx_conf_set_flag_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_keepalive_log_loc_conf_t, on),
NULL
},
ngx_null_command
};
ngx_module_t ngx_http_keepalive_log_module = {
NGX_MODULE_V1,
&ngx_http_keepalive_log_module_ctx,
ngx_http_keepalive_log_commands,
NGX_HTTP_MODULE,
NULL, /* init master */
NULL, /* init module */
ngx_http_keepalive_log_init_process, /* init process */
NULL, /* init thread */
NULL, /* exit thread */
NULL, /* exit process */
NULL, /* exit master */
NGX_MODULE_V1_PADDING
};
static ngx_int_t
ngx_http_keepalive_log_init_process(ngx_cycle_t *cycle)
{
ngx_http_keepalive_log_main_conf_t *kmcf = ngx_http_cycle_get_module_main_conf(cycle, ngx_http_keepalive_log_module);
kmcf->default_log = &cycle->new_log;
return NGX_OK;
}
static void*
ngx_http_keepalive_log_create_main_conf(ngx_conf_t *cf)
{
ngx_http_keepalive_log_main_conf_t *kmcf;
kmcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_keepalive_log_main_conf_t));
if(!kmcf) {
return NGX_CONF_ERROR;
}
kmcf->default_log = NULL;
return kmcf;
}
static void*
ngx_http_keepalive_log_create_loc_conf(ngx_conf_t *cf)
{
ngx_http_keepalive_log_loc_conf_t *klcf;
klcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_keepalive_log_loc_conf_t));
if(klcf == NULL) {
return NULL;
}
klcf->on = NGX_CONF_UNSET;
klcf->log = NGX_CONF_UNSET_PTR;
return klcf;
}
static char*
ngx_http_keepalive_log_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
{
ngx_http_keepalive_log_loc_conf_t *prev = parent;
ngx_http_keepalive_log_loc_conf_t *conf = child;
ngx_conf_merge_value(conf->on, prev->on, 0);
ngx_conf_merge_ptr_value(conf->log, prev->log, NULL);
return NGX_CONF_OK;
}
static ngx_int_t
ngx_http_keepalive_log_init(ngx_conf_t *cf)
{
ngx_http_handler_pt *h;
ngx_http_core_main_conf_t *cmcf;
cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
h = ngx_array_push(&cmcf->phases[NGX_HTTP_LOG_PHASE].handlers);
if (h == NULL) {
return NGX_ERROR;
}
*h = ngx_http_keepalive_log_handler;
return NGX_OK;
}
static ngx_int_t
ngx_http_keepalive_log_handler(ngx_http_request_t *r)
{
ngx_fd_t fd;
u_char *p;
u_char msg[KEEPALIVE_LOG_MAX_LOG_LEN];
ngx_http_keepalive_log_main_conf_t *kmcf;
ngx_http_keepalive_log_loc_conf_t *klcf = ngx_http_get_module_loc_conf(r, ngx_http_keepalive_log_module);
if(!klcf->on || !klcf->log) {
return NGX_OK;
}
fd= klcf->log->file->fd;
if (r == r->main) {
u_char portstr[] = "65535";
ngx_str_t serv;
ngx_str_t hostname;
ngx_str_t ip;
serv.data = portstr;
ngx_http_keepalive_log_get_req_info(r, &serv, &hostname, &ip);
#ifdef KEEPALIVE_LOG_DEBUG
kmcf = ngx_http_get_module_main_conf(r, ngx_http_keepalive_log_module);
ngx_log_error(KEEPALIVE_LOG_DEBUG_LEVEL, kmcf->default_log, 0,
"%V %V %V", &ip, &serv, &hostname);
#endif
if (!r->upstream) {
return NGX_OK;
}
ngx_uint_t cached = r->upstream->peer.cached ? 1 : 0;
p = ngx_snprintf(msg, KEEPALIVE_LOG_MAX_LOG_LEN, "%V %V %V %ui\n", ip, serv, hostname, cached);
(void) ngx_write_fd(fd, msg, p - msg);
}
return NGX_OK;
}
static void
ngx_http_keepalive_log_get_req_info(ngx_http_request_t *r, ngx_str_t *serv, ngx_str_t *hostname, ngx_str_t *ip)
{
ngx_http_core_srv_conf_t *cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
if(cscf->server_name.len > 0) {
*serv = cscf->server_name;
} else {
ngx_uint_t port;
port = ntohs(((struct sockaddr_in*)(r->connection->local_sockaddr))->sin_port);
if(port > 0 && port < 65536) {
//用端口来代表server
serv->len = ngx_sprintf(serv->data, "%ui", port) - serv->data;
} else {
ngx_str_set(serv, "-");
}
}
if(r->headers_in.host) {
*hostname = r->headers_in.host->value;
} else {
ngx_str_set(hostname, "-");
}
*ip = r->connection->addr_text;
}
static ngx_log_t
*ngx_log_create(ngx_cycle_t *cycle, ngx_str_t *name)
{
ngx_log_t *log = ngx_pcalloc(cycle->pool, sizeof(ngx_log_t));
if(log == NULL) {
return NULL;
}
log->file = ngx_conf_open_file(cycle, name);
if(log->file == NULL) {
return NULL;
}
return log;
}
static char*
ngx_http_keepalive_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_keepalive_log_loc_conf_t *klcf = conf;
ngx_str_t *value = NULL;
if(klcf->log != NGX_CONF_UNSET_PTR) {
return "is duplicated";
}
value = cf->args->elts;
klcf->log = ngx_log_create(cf->cycle, &value[1]);
if(klcf->log == NULL) {
return NGX_CONF_ERROR;
}
return NGX_CONF_OK;
}