├── README ├── config ├── src └── ngx_http_requestid_module.c └── t └── test.t /README: -------------------------------------------------------------------------------- 1 | The ngx_http_requestid_module is designed to generate a unique request identificator with timestamp. 2 | 3 | Since nginx 1.11.0 has introduced the $request_id variable, this module is useful only for older versions of nginx or if you need a timestamp prepended request identifier. 4 | 5 | The module sets $trequest_id variable with a unique request ID. 6 | 7 | The $trequest_id variable is composed of (time){13} and (md5(ngx_pid, connection_number, rand())){19}, where: 8 | * time - timestamp in milliseconds 9 |   * ngx_pid - nginx process id 10 |   * connection_number - connection counter value local to worker process 11 |   * rand() - random number 12 | 13 | Supports both old and new configuration methods including dynamic compilation. 14 | 15 | Example configurations: 16 | 17 | # Set Proxy Header 18 | location / { 19 |      trequestid on; 20 |      proxy_pass http://127.0.0.1; 21 |      proxy_set_header X-Request-Id $trequest_id; 22 | } 23 | 24 | 25 | # Set HTTP Header 26 | location / { 27 | add_header X-Request-Id $trequest_id; 28 | } 29 | 30 | # Write request id to log 31 | log_format main '$remote_addr - $remote_user [$time_local] ' 32 | '"$request" $status $body_bytes_sent $trequest_id ' 33 | '"$http_referer" "$http_user_agent"'; 34 | 35 | 36 | Configuration: 37 | 38 | syntax: trequestid on | off 39 | default: off 40 | context: server, location 41 | 42 | -------------------------------------------------------------------------------- /config: -------------------------------------------------------------------------------- 1 | USE_MD5=YES 2 | ngx_addon_name=ngx_http_requestid_module 3 | 4 | REQUESTID_SRCS="$ngx_addon_dir/src/ngx_http_requestid_module.c" 5 | 6 | if test -n "$ngx_module_link"; then 7 | ngx_module_type=HTTP_AUX_FILTER 8 | ngx_module_name=$ngx_addon_name 9 | ngx_module_srcs=$REQUESTID_SRCS 10 | 11 | . auto/module 12 | else 13 | HTTP_AUX_FILTER_MODULES="$HTTP_AUX_FILTER_MODULES ngx_http_requestid_module" 14 | NGX_ADDON_SRCS="$NGX_ADDON_SRCS $REQUESTID_SRCS" 15 | fi 16 | 17 | -------------------------------------------------------------------------------- /src/ngx_http_requestid_module.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define MD5_BHASH_LEN 16 7 | #define MD5_HASH_LEN (MD5_BHASH_LEN * 2) 8 | #define TIMESTAMP_LENGTH 13 9 | 10 | typedef struct { 11 | ngx_flag_t enable; 12 | } ngx_http_requestid_conf_t; 13 | 14 | 15 | static ngx_str_t ngx_http_requestid = ngx_string("trequest_id"); 16 | static const u_char hex[] = "0123456789abcdef"; 17 | 18 | static ngx_int_t ngx_http_requestid_add_variables(ngx_conf_t *cf); 19 | static void *ngx_http_requestid_create_conf(ngx_conf_t *cf); 20 | static char *ngx_http_requestid_merge_conf(ngx_conf_t *cf, void *parent, 21 | void *child); 22 | 23 | 24 | static ngx_command_t ngx_http_requestid_commands[] = { 25 | { 26 | ngx_string("trequestid"), 27 | NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, 28 | ngx_conf_set_flag_slot, 29 | NGX_HTTP_LOC_CONF_OFFSET, 30 | offsetof(ngx_http_requestid_conf_t, enable), 31 | NULL 32 | }, 33 | ngx_null_command 34 | }; 35 | 36 | 37 | static ngx_http_module_t ngx_http_requestid_module_ctx = { 38 | ngx_http_requestid_add_variables, /* preconfiguration */ 39 | NULL, /* postconfiguration */ 40 | 41 | NULL, /* create main configuration */ 42 | NULL, /* init main configuration */ 43 | 44 | NULL, /* create server configuration */ 45 | NULL, /* merge server configuration */ 46 | 47 | ngx_http_requestid_create_conf, /* create location configration */ 48 | ngx_http_requestid_merge_conf /* merge location configration */ 49 | }; 50 | 51 | 52 | ngx_module_t ngx_http_requestid_module = { 53 | NGX_MODULE_V1, 54 | &ngx_http_requestid_module_ctx, /* module context */ 55 | ngx_http_requestid_commands, /* module directives */ 56 | NGX_HTTP_MODULE, /* module type */ 57 | NULL, /* init master */ 58 | NULL, /* init module */ 59 | NULL, /* init process */ 60 | NULL, /* init thread */ 61 | NULL, /* exit thread */ 62 | NULL, /* exit process */ 63 | NULL, /* exit master */ 64 | NGX_MODULE_V1_PADDING 65 | }; 66 | 67 | 68 | static ngx_int_t 69 | ngx_http_requestid_set_variable(ngx_http_request_t *r, 70 | ngx_http_variable_value_t *v, uintptr_t data) 71 | { 72 | ngx_md5_t md5; 73 | ngx_http_requestid_conf_t *conf; 74 | u_char *end; 75 | u_char val[NGX_INT64_LEN * 3 + 3]; 76 | u_char hashb[MD5_BHASH_LEN]; 77 | ngx_uint_t i, k; 78 | 79 | conf = ngx_http_get_module_loc_conf(r, ngx_http_requestid_module); 80 | 81 | if (!conf->enable) { 82 | v->not_found = 1; 83 | return NGX_OK; 84 | } 85 | 86 | end = ngx_sprintf(val, "%i,%ui,%i", 87 | ngx_pid, r->connection->number, ngx_random()); 88 | *end = 0; 89 | 90 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 91 | "requestid: data for hash=%s", val); 92 | 93 | ngx_md5_init(&md5); 94 | ngx_md5_update(&md5, val, end-val); 95 | ngx_md5_final(hashb, &md5); 96 | 97 | v->valid = 1; 98 | v->no_cacheable = 0; 99 | v->not_found = 0; 100 | v->len = MD5_HASH_LEN; 101 | v->data = ngx_pnalloc(r->pool, MD5_HASH_LEN); 102 | 103 | if (v->data == NULL) { 104 | return NGX_ERROR; 105 | } 106 | 107 | for (i = TIMESTAMP_LENGTH & ~1, k = 0; i < MD5_HASH_LEN; i += 2, ++k) { 108 | v->data[i] = hex[hashb[k] >> 4]; 109 | v->data[i+1] = hex[hashb[k] & 0xf]; 110 | } 111 | 112 | ngx_snprintf(v->data, TIMESTAMP_LENGTH, "%ui%03d", 113 | r->start_sec, r->start_msec); 114 | 115 | return NGX_OK; 116 | } 117 | 118 | 119 | static void * 120 | ngx_http_requestid_create_conf(ngx_conf_t *cf) 121 | { 122 | ngx_http_requestid_conf_t *conf; 123 | 124 | conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_requestid_conf_t)); 125 | if (conf == NULL) { 126 | return NGX_CONF_ERROR; 127 | } 128 | 129 | conf->enable = NGX_CONF_UNSET; 130 | return conf; 131 | } 132 | 133 | 134 | static char * 135 | ngx_http_requestid_merge_conf(ngx_conf_t *cf, void *parent, void *child) 136 | { 137 | ngx_http_requestid_conf_t *prev = parent; 138 | ngx_http_requestid_conf_t *conf = child; 139 | 140 | ngx_conf_merge_off_value(conf->enable, prev->enable, 0); 141 | 142 | return NGX_CONF_OK; 143 | } 144 | 145 | 146 | static ngx_int_t 147 | ngx_http_requestid_add_variables(ngx_conf_t *cf) 148 | { 149 | ngx_http_variable_t *var; 150 | 151 | var = ngx_http_add_variable(cf, &ngx_http_requestid, 152 | NGX_HTTP_VAR_CHANGEABLE); 153 | if (var == NULL) { 154 | return NGX_ERROR; 155 | } 156 | 157 | var->get_handler = ngx_http_requestid_set_variable; 158 | 159 | return NGX_OK; 160 | } 161 | -------------------------------------------------------------------------------- /t/test.t: -------------------------------------------------------------------------------- 1 | use Test::Nginx::Socket 'no_plan'; 2 | 3 | run_tests(); 4 | 5 | __DATA__ 6 | 7 | === TEST 1: Check request id pattern 8 | --- config 9 | location = /test { 10 | trequestid on; 11 | return 200 "$trequest_id"; 12 | } 13 | --- request 14 | GET /test 15 | --- response_body_like: ^[0-9]{13}[0-9a-f]{19}$ 16 | 17 | 18 | === TEST 2: Check server and location both on 19 | --- config 20 | trequestid on; 21 | 22 | location = /test { 23 | trequestid on; 24 | return 200 "$trequest_id"; 25 | } 26 | --- request 27 | GET /test 28 | --- response_body_like: ^[0-9]{13}[0-9a-f]{19}$ 29 | 30 | 31 | === TEST 3: Check server directive only 32 | --- config 33 | trequestid on; 34 | 35 | location = /test { 36 | return 200 "$trequest_id"; 37 | } 38 | --- request 39 | GET /test 40 | --- response_body_like: ^[0-9]{13}[0-9a-f]{19}$ 41 | 42 | 43 | === TEST 4: Check disabled for location 44 | --- config 45 | trequestid on; 46 | 47 | location = /test { 48 | trequestid off; 49 | return 200 "$trequest_id"; 50 | } 51 | --- request 52 | GET /test 53 | --- response_body_like: ^$ 54 | 55 | 56 | === TEST 5: Check location with if 57 | --- config 58 | trequestid on; 59 | 60 | location = /test { 61 | if ( $request_method = POST ) { 62 | return 406; 63 | } 64 | return 200 "$trequest_id"; 65 | } 66 | --- request 67 | GET /test 68 | --- response_body_like: ^[0-9]{13}[0-9a-f]{19}$ 69 | 70 | 71 | === TEST 6: Test http context forbidden 72 | --- http_config 73 | trequestid on; 74 | --- config 75 | --- must_die 76 | 77 | 78 | === TEST 7: No request id by default 79 | --- config 80 | location = /test { 81 | return 200 "$trequest_id"; 82 | } 83 | --- request 84 | GET /test 85 | --- response_body_like: ^$ 86 | 87 | --------------------------------------------------------------------------------