我写了一个NGX三方模块,用来各个配置文件下的域名各自的流量。基本上逻辑是这样的:在nginx.conf的server下配置指令,flow file_name。flow模块读取file_name,然后将body_bytes_sent加到模块的累加器里面,每次都写入file_name。若是NGX重启了就重新去读取这个文件(不存在就创建,模块的累加器清0)。但是碰到一个问题,下面是一段输出:
....
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>
/* Module config */
typedef struct ngx_http_flow_conf_s ngx_http_flow_conf_t;
struct ngx_http_flow_conf_s {
ngx_int_t fd ; //文件标识符
int flow_len; //记录所有流量
ngx_str_t file;
};
#define NGX_FLOW_LENGTH 20
static char *ngx_http_flow_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
static ngx_int_t ngx_http_flow_handler(ngx_http_request_t *r);
static ngx_int_t ngx_http_flow_init(ngx_conf_t *cf);
static void *ngx_http_flow_create_srv_conf(ngx_conf_t *cf);
/* Directives */
static ngx_command_t ngx_http_flow_commands[] = {
{ ngx_string("flow"),
NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
// ngx_conf_set_str_slot,
ngx_http_flow_set,
NGX_HTTP_SRV_CONF_OFFSET,
offsetof(ngx_http_flow_conf_t,file),
NULL },
ngx_null_command
};
//static u_char ngx_flow[] = "hello world";
static ngx_http_module_t ngx_http_flow_module_ctx = {
NULL, /* preconfiguration */
ngx_http_flow_init, /* postconfiguration */
NULL, /* create main configuration */
NULL, /* init main configuration */
ngx_http_flow_create_srv_conf, /* create server configuration */
NULL, /* merge server configuration */
NULL, /* create location configuration */
NULL /* merge location configuration */
};
/* hook */
ngx_module_t ngx_http_flow_module = {
NGX_MODULE_V1,
&ngx_http_flow_module_ctx, /* module context */
ngx_http_flow_commands, /* module directives */
NGX_HTTP_MODULE, /* module type */
NULL, /* init master */
NULL, /* init module */
NULL, /* init process */
NULL, /* init thread */
NULL, /* exit thread */
NULL, /* exit process */
NULL, /* exit master */
NGX_MODULE_V1_PADDING
};
static ngx_int_t
ngx_http_flow_handler(ngx_http_request_t *r)
{
ngx_int_t len;
int body_bytes_sent;
ngx_http_flow_conf_t *fct;
u_char buff[NGX_FLOW_LENGTH] = {'\0'};
body_bytes_sent = r->connection->sent - r->header_size;
if (body_bytes_sent > 0) {
fct = ngx_http_get_module_srv_conf(r,ngx_http_flow_module);
fct->flow_len += body_bytes_sent;
ngx_sprintf(buff, "%d", fct->flow_len);
len = ngx_strlen(buff);
printf("%d %d\n",body_bytes_sent,fct->flow_len); //这里就是上面的打印
lseek(fct->fd,0,SEEK_SET);
write(fct->fd,(char*)buff,len);
}
return NGX_OK;
}
static void *ngx_http_flow_create_srv_conf(ngx_conf_t *cf)
{
ngx_http_flow_conf_t *conf;
conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_flow_conf_t));
if (conf == NULL)
{
return NGX_CONF_ERROR;
}
conf->flow_len = 0;
conf->fd = 0;
conf->file.data = "">
conf->file.len = 0;
return conf;
}
static char *
ngx_http_flow_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_str_t *value;
ngx_http_flow_conf_t *fct;
int read_size;
u_char buff[NGX_FLOW_LENGTH];
fct = conf;
value = cf->args->elts;
if (cf->args->nelts != 2)
{
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid parameter \"%V\"", &value[1]);
return NGX_CONF_ERROR;
}
fct->file = value[1];
fct->fd = ngx_open_file(fct->file.data, NGX_FILE_RDWR, NGX_FILE_CREATE_OR_OPEN, NGX_FILE_DEFAULT_ACCESS);
if (fct->fd == NGX_INVALID_FILE) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno,
ngx_open_file_n " \"%s\" failed",
fct->file.data);
return NGX_CONF_ERROR;
}
read_size = read(fct->fd,buff,NGX_FLOW_LENGTH);
if (read_size < 0)
{
ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno,
ngx_open_file_n " \"%s\" failed",
fct->file.data);
return NGX_CONF_ERROR;
}
else if (read_size == 0)
{
// first create flow file
fct->flow_len = 0;
}
else{
buff[read_size] = '\0';
// printf("first read : %s\n",buff);
fct->flow_len = ngx_atoi(buff,read_size);
}
printf("first read : %d\n",fct->flow_len);
return NGX_CONF_OK;
}
static ngx_int_t
ngx_http_flow_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_flow_handler;
return NGX_OK;
}