diff --git a/README.md b/README.md index fbe3d92..1d984ed 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,7 @@ Here is a list of variables you can use in log format string: * $ws_opcode - websocket packet opcode. Look into https://tools.ietf.org/html/rfc6455 Section 5.2, Base Framing Protocol. * $ws_payload_size - Websocket packet size without protocol specific data. Only data that been sent or received by the client + * $ws_total_payload_size - total packet size on a Websocket connection, without protocol specific data. Only data that been sent or received by the client * $ws_packet_source - Could be "client" if packet has been sent by the user or "upstream" if it has been received from the server * $ws_conn_age - Number of seconds connection is alive * $time_local - Nginx local time, date and timezone diff --git a/ngx_http_websocket_stat_format.c b/ngx_http_websocket_stat_format.c index 8030f20..1fece77 100644 --- a/ngx_http_websocket_stat_format.c +++ b/ngx_http_websocket_stat_format.c @@ -1,3 +1,5 @@ +#include +#include #include #include #include @@ -12,7 +14,7 @@ size_t HTTP_VAR_LEN = sizeof("$http_") - 1; template_variable null_variable = {NULL, 0, 0, NULL}; const char *http_header_var(ngx_http_request_t *r, void *data); -template_variable header_variable = {NULL, 0, 50, http_header_var}; +template_variable header_variable = {NULL, 0, 150, http_header_var}; typedef struct { const template_variable *variable; diff --git a/ngx_http_websocket_stat_module.c b/ngx_http_websocket_stat_module.c index f74a386..37dbcd1 100644 --- a/ngx_http_websocket_stat_module.c +++ b/ngx_http_websocket_stat_module.c @@ -1,10 +1,11 @@ -#include "ngx_http_websocket_stat_format.h" -#include "ngx_http_websocket_stat_frame_counter.h" -#include #include #include #include +#include "ngx_http_websocket_stat_format.h" +#include "ngx_http_websocket_stat_frame_counter.h" +#include + #include #include #include @@ -99,7 +100,7 @@ websocket_log(char *str) void ws_do_log(compiled_template *template, ngx_http_request_t *r, void *ctx) { - if (ws_log) { + if (ws_log && template) { char *log_line = apply_template(template, r, ctx); websocket_log(log_line); free(log_line); @@ -329,14 +330,15 @@ my_send(ngx_connection_t *c, u_char *buf, size_t size) ngx_atomic_fetch_add(frame_counter->frames, 1); ngx_atomic_fetch_add(frame_counter->total_payload_size, ctx->frame_counter.current_payload_size); + ctx->frame_counter.total_payload_size += ctx->frame_counter.current_payload_size; ws_do_log(log_template, r, &template_ctx); } } int n = orig_send(c, buf, size); if (n < 0) { - if(!ngx_atomic_cmp_set(ngx_websocket_stat_active, 0, 0)){ - ngx_atomic_fetch_add(ngx_websocket_stat_active, -1); - ws_do_log(log_close_template, r, &template_ctx); + if (!ngx_atomic_cmp_set(ngx_websocket_stat_active, 0, 0)) { + ngx_atomic_fetch_add(ngx_websocket_stat_active, -1); + ws_do_log(log_close_template, r, &template_ctx); } } return n; @@ -370,6 +372,7 @@ my_recv(ngx_connection_t *c, u_char *buf, size_t size) ngx_atomic_fetch_add(frame_counter->frames, 1); ngx_atomic_fetch_add(frame_counter->total_payload_size, ctx->frame_counter.current_payload_size); + ctx->frame_counter.total_payload_size += ctx->frame_counter.current_payload_size; ws_do_log(log_template, r, &template_ctx); } } @@ -401,10 +404,13 @@ ngx_http_websocket_stat_body_filter(ngx_http_request_t *r, ngx_chain_t *in) if (ctx == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } + template_ctx.ws_ctx = ctx; + const char *request_id_str = get_core_var(r, "request_id"); ctx->connection_id.data = ngx_pcalloc(r->pool, UID_LENGTH + 1); ctx->connection_id.len = UID_LENGTH; memcpy(ctx->connection_id.data, request_id_str, UID_LENGTH + 1); + ctx->frame_counter.total_payload_size = 0; ws_do_log(log_open_template, r, &template_ctx); ngx_http_set_ctx(r, ctx, ngx_http_websocket_stat_module); @@ -415,9 +421,9 @@ ngx_http_websocket_stat_body_filter(ngx_http_request_t *r, ngx_chain_t *in) ngx_atomic_fetch_add(ngx_websocket_stat_active, 1); ctx->ws_conn_start_time = ngx_time(); } else { - if(!ngx_atomic_cmp_set(ngx_websocket_stat_active, 0, 0)){ - ngx_atomic_fetch_add(ngx_websocket_stat_active, -1); - ws_do_log(log_close_template, r, &template_ctx); + if (!ngx_atomic_cmp_set(ngx_websocket_stat_active, 0, 0)) { + ngx_atomic_fetch_add(ngx_websocket_stat_active, -1); + ws_do_log(log_close_template, r, &template_ctx); } } } @@ -425,8 +431,6 @@ ngx_http_websocket_stat_body_filter(ngx_http_request_t *r, ngx_chain_t *in) return ngx_http_next_body_filter(r, in); } -char buff[100]; - const char * ws_packet_type(ngx_http_request_t *r, void *data) { @@ -434,7 +438,9 @@ ws_packet_type(ngx_http_request_t *r, void *data) ngx_frame_counter_t *frame_cntr = &(ctx->ws_ctx->frame_counter); if (!ctx || !frame_cntr) return UNKNOWN_VAR; - sprintf(buff, "%d", frame_cntr->current_frame_type); + + char* buff = ngx_pcalloc(r->pool, NGX_ATOMIC_T_LEN); + snprintf(buff, NGX_ATOMIC_T_LEN, "%d", frame_cntr->current_frame_type); return buff; } @@ -445,7 +451,22 @@ ws_packet_size(ngx_http_request_t *r, void *data) ngx_frame_counter_t *frame_cntr = &ctx->ws_ctx->frame_counter; if (!ctx || !frame_cntr) return UNKNOWN_VAR; - sprintf(buff, "%lu", frame_cntr->current_payload_size); + + char* buff = ngx_pcalloc(r->pool, NGX_ATOMIC_T_LEN); + snprintf(buff, NGX_ATOMIC_T_LEN, "%lu", frame_cntr->current_payload_size); + return (char *)buff; +} + +const char * +ws_total_payload_size(ngx_http_request_t *r, void *data) +{ + template_ctx_s *ctx = data; + ngx_frame_counter_t *frame_cntr = &ctx->ws_ctx->frame_counter; + if (!ctx || !frame_cntr) + return UNKNOWN_VAR; + + char* buff = ngx_pcalloc(r->pool, NGX_ATOMIC_T_LEN); + snprintf(buff, NGX_ATOMIC_T_LEN, "%lu", frame_cntr->total_payload_size); return (char *)buff; } @@ -472,6 +493,7 @@ get_core_var(ngx_http_request_t *r, const char *variable) key = ngx_hash(key, *(variable++)); vv = ngx_http_get_variable(r, &var, key); + char* buff = ngx_pcalloc(r->pool, vv->len + 1); memcpy(buff, vv->data, vv->len); buff[vv->len] = '\0'; return buff; @@ -483,7 +505,9 @@ ws_connection_age(ngx_http_request_t *r, void *data) template_ctx_s *ctx = data; if (!ctx || !ctx->ws_ctx) return UNKNOWN_VAR; - sprintf(buff, "%lu", ngx_time() - ctx->ws_ctx->ws_conn_start_time); + + char* buff = ngx_pcalloc(r->pool, NGX_ATOMIC_T_LEN); + snprintf(buff, NGX_ATOMIC_T_LEN, "%lu", ngx_time() - ctx->ws_ctx->ws_conn_start_time); return (char *)buff; } @@ -491,12 +515,16 @@ ws_connection_age(ngx_http_request_t *r, void *data) const char * local_time(ngx_http_request_t *r, void *data) { - return memcpy(buff, ngx_cached_http_time.data, ngx_cached_http_time.len); + char* buff = ngx_pcalloc(r->pool, ngx_cached_http_time.len + 1); + memcpy(buff, ngx_cached_http_time.data, ngx_cached_http_time.len); + buff[ngx_cached_http_time.len] = '\0'; + return buff; } const char * remote_ip(ngx_http_request_t *r, void *data) { + char* buff = ngx_pcalloc(r->pool, r->connection->addr_text.len + 1); memcpy(buff, r->connection->addr_text.data, r->connection->addr_text.len); buff[r->connection->addr_text.len] = '\0'; @@ -542,13 +570,14 @@ GEN_CORE_GET_FUNC(server_port, "server_port") const template_variable variables[] = { {VAR_NAME("$ws_opcode"), sizeof("ping") - 1, ws_packet_type}, {VAR_NAME("$ws_payload_size"), NGX_SIZE_T_LEN, ws_packet_size}, + {VAR_NAME("$ws_total_payload_size"), NGX_SIZE_T_LEN, ws_total_payload_size}, {VAR_NAME("$ws_packet_source"), sizeof("upstream") - 1, ws_packet_source}, {VAR_NAME("$ws_conn_age"), NGX_SIZE_T_LEN, ws_connection_age}, {VAR_NAME("$time_local"), sizeof("Mon, 23 Oct 2017 11:27:42 GMT") - 1, local_time}, - {VAR_NAME("$upstream_addr"), 60, upstream_addr}, - {VAR_NAME("$request"), 60, request}, - {VAR_NAME("$uri"), 60, uri}, + {VAR_NAME("$upstream_addr"), 160, upstream_addr}, + {VAR_NAME("$request"), 160, request}, + {VAR_NAME("$uri"), 160, uri}, {VAR_NAME("$request_id"), UID_LENGTH, request_id}, {VAR_NAME("$remote_user"), 60, remote_user}, {VAR_NAME("$remote_addr"), 60, remote_addr}, @@ -582,12 +611,18 @@ ngx_http_ws_log_format(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "Wrong argument number"); return NGX_CONF_ERROR; } + if (cf->args->nelts == 2) { log_template = compile_template((char *)args[1].data, variables, cf->pool); return NGX_CONF_OK; + } - if (strcmp((char *)args[1].data, "close") == 0) { + if (strcmp((char *)args[1].data, "packet") == 0) { + log_template = + compile_template((char *)args[2].data, variables, cf->pool); + return NGX_CONF_OK; + } else if (strcmp((char *)args[1].data, "close") == 0) { log_close_template = compile_template((char *)args[2].data, variables, cf->pool); return NGX_CONF_OK; @@ -697,7 +732,7 @@ complete_ws_handshake(ngx_connection_t *connection, const char *ws_key) Base64Encode(hash, SHA_DIGEST_LENGTH, access_key, ACCEPT_SIZE); access_key[ACCEPT_SIZE] = '\0'; char resp[256]; - sprintf(resp, resp_template, access_key); + snprintf(resp, 256, resp_template, access_key); ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "Websocket connection closed"); connection->send(connection, (unsigned char *)resp, strlen(resp)); @@ -743,18 +778,18 @@ ngx_http_websocket_stat_init(ngx_conf_t *cf) ngx_http_next_body_filter = ngx_http_top_body_filter; ngx_http_top_body_filter = ngx_http_websocket_stat_body_filter; - if (!log_template) { - log_template = - compile_template(default_log_template_str, variables, cf->pool); - } - if (!log_open_template) { - log_open_template = compile_template(default_open_log_template_str, - variables, cf->pool); - } - if (!log_close_template) { - log_close_template = compile_template(default_close_log_template_str, - variables, cf->pool); - } +// if (!log_template) { +// log_template = +// compile_template(default_log_template_str, variables, cf->pool); +// } +// if (!log_open_template) { +// log_open_template = compile_template(default_open_log_template_str, +// variables, cf->pool); +// } +// if (!log_close_template) { +// log_close_template = compile_template(default_close_log_template_str, +// variables, cf->pool); +// } ngx_http_handler_pt *h; ngx_http_core_main_conf_t *cmcf;