528 lines
14 KiB
C
528 lines
14 KiB
C
#include <ngx_config.h>
|
|
#include <ngx_core.h>
|
|
#include <ngx_http.h>
|
|
|
|
|
|
typedef struct {
|
|
ngx_flag_t trace;
|
|
} ngx_http_trace_main_conf_t;
|
|
|
|
|
|
typedef struct {
|
|
u_char traceid[32]; /* X-NTM-Traceid */
|
|
u_char cid[32]; /* X-NTM-Currentid */
|
|
u_char pid[32]; /* X-NTM-Parentid */
|
|
ngx_flag_t debug; /* X-NTM-Debug */
|
|
} ngx_http_trace_ctx_t;
|
|
|
|
|
|
static void *ngx_http_trace_create_main_conf(ngx_conf_t *cf);
|
|
static char *ngx_http_trace_init_main_conf(ngx_conf_t *cf, void *conf);
|
|
|
|
static char *ngx_http_trace(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
|
|
|
|
static ngx_int_t ngx_http_trace_add_variables(ngx_conf_t *cf);
|
|
static ngx_int_t ngx_http_trace_init(ngx_conf_t *cf);
|
|
|
|
static ngx_int_t ngx_http_trace_traceid_variable(ngx_http_request_t *r,
|
|
ngx_http_variable_value_t *v, uintptr_t data);
|
|
static ngx_int_t ngx_http_trace_currentid_variable(ngx_http_request_t *r,
|
|
ngx_http_variable_value_t *v, uintptr_t data);
|
|
static ngx_int_t ngx_http_trace_parentid_variable(ngx_http_request_t *r,
|
|
ngx_http_variable_value_t *v, uintptr_t data);
|
|
static ngx_int_t ngx_http_trace_debug_variable(ngx_http_request_t *r,
|
|
ngx_http_variable_value_t *v, uintptr_t data);
|
|
static ngx_int_t ngx_http_trace_newid_variable(ngx_http_request_t *r,
|
|
ngx_http_variable_value_t *v, uintptr_t data);
|
|
|
|
|
|
static ngx_command_t ngx_http_trace_commands[] = {
|
|
|
|
{ ngx_string("http_trace"),
|
|
NGX_HTTP_MAIN_CONF|NGX_CONF_NOARGS,
|
|
ngx_http_trace,
|
|
0,
|
|
0,
|
|
NULL },
|
|
|
|
ngx_null_command
|
|
};
|
|
|
|
|
|
static ngx_http_module_t ngx_http_trace_module_ctx = {
|
|
ngx_http_trace_add_variables, /* preconfiguration */
|
|
ngx_http_trace_init, /* postconfiguration */
|
|
|
|
ngx_http_trace_create_main_conf, /* create main configuration */
|
|
ngx_http_trace_init_main_conf, /* init main configuration */
|
|
|
|
NULL, /* create server configuration */
|
|
NULL, /* merge server configuration */
|
|
|
|
NULL, /* create location configuration */
|
|
NULL /* merge location configuration */
|
|
};
|
|
|
|
|
|
ngx_module_t ngx_http_trace_module = {
|
|
NGX_MODULE_V1,
|
|
&ngx_http_trace_module_ctx, /* module context */
|
|
ngx_http_trace_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_http_variable_t ngx_http_trace_vars[] = {
|
|
|
|
{ ngx_string("ntm_traceid"), NULL,
|
|
ngx_http_trace_traceid_variable, 0, 0, 0 },
|
|
|
|
{ ngx_string("ntm_currentid"), NULL,
|
|
ngx_http_trace_currentid_variable, 0, 0, 0 },
|
|
|
|
{ ngx_string("ntm_parentid"), NULL,
|
|
ngx_http_trace_parentid_variable, 0, 0, 0 },
|
|
|
|
{ ngx_string("ntm_debug"), NULL,
|
|
ngx_http_trace_debug_variable, 0, 0, 0 },
|
|
|
|
{ ngx_string("ntm_newid"), NULL,
|
|
ngx_http_trace_newid_variable, 0, 0, 0 },
|
|
|
|
{ ngx_null_string, NULL, NULL, 0, 0, 0 }
|
|
};
|
|
|
|
|
|
static void
|
|
ngx_http_trace_genid(u_char *id) {
|
|
ngx_sprintf(id, "%08xD%08xD%08xD%08xD",
|
|
(uint32_t) ngx_random(), (uint32_t) ngx_random(),
|
|
(uint32_t) ngx_random(), (uint32_t) ngx_random());
|
|
}
|
|
|
|
|
|
static u_char *
|
|
ngx_http_trace_log_error(ngx_log_t *log, u_char *buf, size_t len)
|
|
{
|
|
u_char *p;
|
|
ngx_http_request_t *r;
|
|
ngx_http_log_ctx_t *ctx;
|
|
ngx_http_trace_ctx_t *tctx;
|
|
ngx_str_t traceid, currentid, parentid;
|
|
|
|
if (log->action) {
|
|
p = ngx_snprintf(buf, len, " while %s", log->action);
|
|
len -= p - buf;
|
|
buf = p;
|
|
}
|
|
|
|
ctx = log->data;
|
|
|
|
p = ngx_snprintf(buf, len, ", client: %V", &ctx->connection->addr_text);
|
|
len -= p - buf;
|
|
buf = p;
|
|
|
|
r = ctx->request;
|
|
|
|
if (r) {
|
|
p = r->log_handler(r, ctx->current_request, p, len);
|
|
len -= p - buf;
|
|
buf = p;
|
|
|
|
} else {
|
|
p = ngx_snprintf(p, len, ", server: %V",
|
|
&ctx->connection->listening->addr_text);
|
|
len -= p - buf;
|
|
buf = p;
|
|
}
|
|
|
|
tctx = ngx_http_get_module_ctx(r, ngx_http_trace_module);
|
|
if (tctx) {
|
|
traceid.data = tctx->traceid;
|
|
traceid.len = sizeof(tctx->traceid);
|
|
|
|
currentid.data = tctx->cid;
|
|
currentid.len = sizeof(tctx->cid);
|
|
|
|
parentid.data = tctx->pid;
|
|
parentid.len = sizeof(tctx->pid);
|
|
|
|
p = ngx_snprintf(p, len, ", [NGINX-TRACE] traceid: %V, currentid: %V, "
|
|
"parentid: %V [NGINX-TRACE-END]",
|
|
&traceid, ¤tid, &parentid);
|
|
}
|
|
|
|
return p;
|
|
}
|
|
|
|
|
|
// First request without X-NTM-Traceid X-NTM-Currentid or X-NTM-Parentid
|
|
// Need to gen these ids and set X-NTM headers in main request
|
|
static ngx_int_t
|
|
ngx_http_trace_first_request(ngx_http_request_t *r, ngx_http_trace_ctx_t *ctx)
|
|
{
|
|
ngx_table_elt_t *h;
|
|
|
|
ngx_http_trace_genid(ctx->traceid);
|
|
ngx_http_trace_genid(ctx->cid);
|
|
ngx_sprintf(ctx->pid, "00000000000000000000000000000000");
|
|
|
|
// Set X-NTM-Traceid
|
|
h = ngx_list_push(&r->headers_in.headers);
|
|
if (h == NULL) {
|
|
return NGX_ERROR;
|
|
}
|
|
|
|
h->key.data = (u_char *) "X-NTM-Traceid";
|
|
h->key.len = sizeof("X-NTM-Traceid") - 1;
|
|
|
|
h->value.data = ctx->traceid;
|
|
h->value.len = sizeof(ctx->traceid);
|
|
|
|
h->lowcase_key = ngx_pnalloc(r->pool, h->key.len);
|
|
if (h->lowcase_key == NULL) {
|
|
return NGX_ERROR;
|
|
}
|
|
h->hash = ngx_hash_strlow(h->lowcase_key, h->key.data, h->key.len);
|
|
|
|
// Set X-NTM-Currentid
|
|
h = ngx_list_push(&r->headers_in.headers);
|
|
if (h == NULL) {
|
|
return NGX_ERROR;
|
|
}
|
|
|
|
h->key.data = (u_char *) "X-NTM-Currentid";
|
|
h->key.len = sizeof("X-NTM-Currentid") - 1;
|
|
|
|
h->value.data = ctx->cid;
|
|
h->value.len = sizeof(ctx->cid);
|
|
|
|
h->lowcase_key = ngx_pnalloc(r->pool, h->key.len);
|
|
if (h->lowcase_key == NULL) {
|
|
return NGX_ERROR;
|
|
}
|
|
h->hash = ngx_hash_strlow(h->lowcase_key, h->key.data, h->key.len);
|
|
|
|
// Set X-NTM-Parentid
|
|
h = ngx_list_push(&r->headers_in.headers);
|
|
if (h == NULL) {
|
|
return NGX_ERROR;
|
|
}
|
|
|
|
h->key.data = (u_char *) "X-NTM-Parentid";
|
|
h->key.len = sizeof("X-NTM-Parentid") - 1;
|
|
|
|
h->value.data = ctx->pid;
|
|
h->value.len = sizeof(ctx->pid);
|
|
|
|
h->lowcase_key = ngx_pnalloc(r->pool, h->key.len);
|
|
if (h->lowcase_key == NULL) {
|
|
return NGX_ERROR;
|
|
}
|
|
h->hash = ngx_hash_strlow(h->lowcase_key, h->key.data, h->key.len);
|
|
|
|
return NGX_OK;
|
|
}
|
|
|
|
|
|
static ngx_int_t
|
|
ngx_http_trace_handler(ngx_http_request_t *r)
|
|
{
|
|
ngx_http_trace_main_conf_t *tmcf;
|
|
ngx_http_trace_ctx_t *ctx;
|
|
ngx_http_variable_value_t v;
|
|
ngx_str_t header;
|
|
|
|
if (r != r->main) { // subrequest
|
|
return NGX_DECLINED;
|
|
}
|
|
|
|
tmcf = ngx_http_get_module_main_conf(r, ngx_http_trace_module);
|
|
if (!tmcf->trace) {
|
|
return NGX_DECLINED;
|
|
}
|
|
|
|
ctx = ngx_http_get_module_ctx(r, ngx_http_trace_module);
|
|
if (ctx) { // ctx already create, enter twice
|
|
return NGX_DECLINED;
|
|
}
|
|
|
|
ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_trace_ctx_t));
|
|
if (ctx == NULL) {
|
|
return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
|
}
|
|
ngx_http_set_ctx(r, ctx, ngx_http_trace_module);
|
|
|
|
// traceid currentid parentid log into nginx error log
|
|
r->connection->log->handler = ngx_http_trace_log_error;
|
|
|
|
// Get X-NTM-Debug
|
|
header.data = (u_char *) "http_x_ntm_debug";
|
|
header.len = sizeof("http_x_ntm_debug") - 1;
|
|
ngx_http_variable_unknown_header(&v, &header, &r->headers_in.headers.part,
|
|
sizeof("http_") - 1);
|
|
if (!v.not_found && v.len == 1 && v.data[0] == '1') {
|
|
// Has header X-NTM-Debug: 1
|
|
ctx->debug = 1;
|
|
}
|
|
|
|
// Get X-NTM-Traceid
|
|
header.data = (u_char *) "http_x_ntm_traceid";
|
|
header.len = sizeof("http_x_ntm_traceid") - 1;
|
|
ngx_http_variable_unknown_header(&v, &header, &r->headers_in.headers.part,
|
|
sizeof("http_") - 1);
|
|
if (v.not_found) {
|
|
goto notfound;
|
|
}
|
|
|
|
ngx_memcpy(ctx->traceid, v.data, ngx_min(v.len, sizeof(ctx->traceid)));
|
|
|
|
// Get X-NTM-Currentid
|
|
header.data = (u_char *) "http_x_ntm_currentid";
|
|
header.len = sizeof("http_x_ntm_currentid") - 1;
|
|
ngx_http_variable_unknown_header(&v, &header, &r->headers_in.headers.part,
|
|
sizeof("http_") - 1);
|
|
if (v.not_found) {
|
|
goto notfound;
|
|
}
|
|
|
|
ngx_memcpy(ctx->cid, v.data, ngx_min(v.len, sizeof(ctx->cid)));
|
|
|
|
// Get X-NTM-Parentid
|
|
header.data = (u_char *) "http_x_ntm_parentid";
|
|
header.len = sizeof("http_x_ntm_parentid") - 1;
|
|
ngx_http_variable_unknown_header(&v, &header, &r->headers_in.headers.part,
|
|
sizeof("http_") - 1);
|
|
if (v.not_found) {
|
|
goto notfound;
|
|
}
|
|
|
|
ngx_memcpy(ctx->pid, v.data, ngx_min(v.len, sizeof(ctx->pid)));
|
|
|
|
return NGX_DECLINED;
|
|
|
|
notfound:
|
|
|
|
if (ngx_http_trace_first_request(r, ctx) != NGX_OK) {
|
|
return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
|
}
|
|
|
|
return NGX_DECLINED;
|
|
}
|
|
|
|
|
|
static ngx_int_t
|
|
ngx_http_trace_traceid_variable(ngx_http_request_t *r,
|
|
ngx_http_variable_value_t *v, uintptr_t data)
|
|
{
|
|
ngx_http_trace_ctx_t *ctx;
|
|
|
|
ctx = ngx_http_get_module_ctx(r, ngx_http_trace_module);
|
|
if (ctx == NULL) {
|
|
v->not_found = 1;
|
|
return NGX_OK;
|
|
}
|
|
|
|
v->data = ctx->traceid;
|
|
v->len = sizeof(ctx->traceid);
|
|
v->valid = 1;
|
|
v->no_cacheable = 0;
|
|
v->not_found = 0;
|
|
|
|
return NGX_OK;
|
|
}
|
|
|
|
|
|
static ngx_int_t
|
|
ngx_http_trace_currentid_variable(ngx_http_request_t *r,
|
|
ngx_http_variable_value_t *v, uintptr_t data)
|
|
{
|
|
ngx_http_trace_ctx_t *ctx;
|
|
|
|
ctx = ngx_http_get_module_ctx(r, ngx_http_trace_module);
|
|
if (ctx == NULL) {
|
|
v->not_found = 1;
|
|
return NGX_OK;
|
|
}
|
|
|
|
v->data = ctx->cid;
|
|
v->len = sizeof(ctx->cid);
|
|
v->valid = 1;
|
|
v->no_cacheable = 0;
|
|
v->not_found = 0;
|
|
|
|
return NGX_OK;
|
|
}
|
|
|
|
|
|
static ngx_int_t
|
|
ngx_http_trace_parentid_variable(ngx_http_request_t *r,
|
|
ngx_http_variable_value_t *v, uintptr_t data)
|
|
{
|
|
ngx_http_trace_ctx_t *ctx;
|
|
|
|
ctx = ngx_http_get_module_ctx(r, ngx_http_trace_module);
|
|
if (ctx == NULL) {
|
|
v->not_found = 1;
|
|
return NGX_OK;
|
|
}
|
|
|
|
v->data = ctx->pid;
|
|
v->len = sizeof(ctx->pid);
|
|
v->valid = 1;
|
|
v->no_cacheable = 0;
|
|
v->not_found = 0;
|
|
|
|
return NGX_OK;
|
|
}
|
|
|
|
|
|
static ngx_int_t
|
|
ngx_http_trace_debug_variable(ngx_http_request_t *r,
|
|
ngx_http_variable_value_t *v, uintptr_t data)
|
|
{
|
|
ngx_http_trace_ctx_t *ctx;
|
|
|
|
ctx = ngx_http_get_module_ctx(r, ngx_http_trace_module);
|
|
if (ctx == NULL) {
|
|
v->not_found = 1;
|
|
return NGX_OK;
|
|
}
|
|
|
|
if (ctx->debug) {
|
|
v->data = (u_char *) "1";
|
|
} else {
|
|
v->data = (u_char *) "0";
|
|
}
|
|
|
|
v->len = sizeof("1") - 1;
|
|
v->valid = 1;
|
|
v->no_cacheable = 0;
|
|
v->not_found = 0;
|
|
|
|
return NGX_OK;
|
|
}
|
|
|
|
|
|
static ngx_int_t
|
|
ngx_http_trace_newid_variable(ngx_http_request_t *r,
|
|
ngx_http_variable_value_t *v, uintptr_t data)
|
|
{
|
|
ngx_http_trace_ctx_t *ctx;
|
|
u_char *newid;
|
|
|
|
ctx = ngx_http_get_module_ctx(r, ngx_http_trace_module);
|
|
if (ctx == NULL) {
|
|
v->not_found = 1;
|
|
return NGX_OK;
|
|
}
|
|
|
|
newid = ngx_pcalloc(r->pool, sizeof(ctx->cid));
|
|
if (newid == NULL) {
|
|
return NGX_ERROR;
|
|
}
|
|
|
|
// fill newid
|
|
ngx_http_trace_genid(newid);
|
|
|
|
v->data = newid;
|
|
v->len = sizeof(ctx->cid);
|
|
v->valid = 1;
|
|
v->no_cacheable = 0;
|
|
v->not_found = 0;
|
|
|
|
return NGX_OK;
|
|
}
|
|
|
|
|
|
static void *
|
|
ngx_http_trace_create_main_conf(ngx_conf_t *cf)
|
|
{
|
|
ngx_http_trace_main_conf_t *conf;
|
|
|
|
conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_trace_main_conf_t));
|
|
if (conf == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
conf->trace = NGX_CONF_UNSET;
|
|
|
|
return conf;
|
|
}
|
|
|
|
|
|
static char *
|
|
ngx_http_trace_init_main_conf(ngx_conf_t *cf, void *conf)
|
|
{
|
|
ngx_http_trace_main_conf_t *tmcf;
|
|
|
|
tmcf = conf;
|
|
|
|
ngx_conf_init_value(tmcf->trace, 0);
|
|
|
|
return NGX_CONF_OK;
|
|
}
|
|
|
|
|
|
static char *
|
|
ngx_http_trace(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
|
{
|
|
ngx_http_trace_main_conf_t *tmcf;
|
|
|
|
tmcf = conf;
|
|
|
|
if (tmcf->trace != NGX_CONF_UNSET) {
|
|
return "is duplicate";
|
|
}
|
|
|
|
tmcf->trace = 1;
|
|
|
|
return NGX_CONF_OK;
|
|
}
|
|
|
|
|
|
static ngx_int_t
|
|
ngx_http_trace_add_variables(ngx_conf_t *cf)
|
|
{
|
|
ngx_http_variable_t *var, *v;
|
|
|
|
for (v = ngx_http_trace_vars; v->name.len; v++) {
|
|
var = ngx_http_add_variable(cf, &v->name, v->flags);
|
|
if (var == NULL) {
|
|
return NGX_ERROR;
|
|
}
|
|
|
|
var->get_handler = v->get_handler;
|
|
var->data = v->data;
|
|
}
|
|
|
|
return NGX_OK;
|
|
}
|
|
|
|
|
|
static ngx_int_t
|
|
ngx_http_trace_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_POST_READ_PHASE].handlers);
|
|
if (h == NULL) {
|
|
return NGX_ERROR;
|
|
}
|
|
|
|
*h = ngx_http_trace_handler;
|
|
|
|
return NGX_OK;
|
|
}
|