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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值