├── Changes ├── LICENSE ├── README.md ├── config ├── share ├── status.compress.html └── status.template.html ├── src ├── ngx_http_stream_server_traffic_status_control.c ├── ngx_http_stream_server_traffic_status_control.h ├── ngx_http_stream_server_traffic_status_display.c ├── ngx_http_stream_server_traffic_status_display.h ├── ngx_http_stream_server_traffic_status_display_json.c ├── ngx_http_stream_server_traffic_status_display_json.h ├── ngx_http_stream_server_traffic_status_display_prometheus.c ├── ngx_http_stream_server_traffic_status_display_prometheus.h ├── ngx_http_stream_server_traffic_status_filter.c ├── ngx_http_stream_server_traffic_status_filter.h ├── ngx_http_stream_server_traffic_status_module.c ├── ngx_http_stream_server_traffic_status_module.h ├── ngx_http_stream_server_traffic_status_module_html.h ├── ngx_http_stream_server_traffic_status_node.c ├── ngx_http_stream_server_traffic_status_node.h ├── ngx_http_stream_server_traffic_status_shm.c ├── ngx_http_stream_server_traffic_status_shm.h ├── ngx_http_stream_server_traffic_status_string.c └── ngx_http_stream_server_traffic_status_string.h ├── t ├── 000.display_html.t ├── 001.display_json.t ├── 002.display_filter.t ├── 003.check_json_syntax.t ├── 004.control_status_fully.t ├── 005.control_status_group.t ├── 006.control_status_zone.t ├── 007.control_reset_fully.t ├── 008.control_reset_group.t ├── 009.control_reset_zone.t ├── 010.control_delete_fully.t ├── 011.control_delete_group.t └── 012.control_delete_zone.t └── util ├── fileToHex.pl ├── tplToBuffer.sh └── tplToDefine.sh /Changes: -------------------------------------------------------------------------------- 1 | v0.1.1 [Wed Jul 04 2018 YoungJoo.Kim ] 2 | * Feature: added support for implementing format/prometheus 3 | 4 | * Feature: added sharedZones in JSON to support shared memory information 5 | 6 | * Feature: added stream_server_traffic_status_average_method directive to 7 | support for selecting an average formula. 8 | 9 | * Feature: added data fields for server_traffic_status_histogram_buckets 10 | directive to set the histogram type of request processing time. 11 | 12 | * Bugfix: fixed to display all A records of server without zone directive 13 | in the upstream block. 14 | 15 | * Compatibility: fixed ngx_current_msec that changed in nginx-1.13.10 16 | 17 | v0.1.0 [Mon Feb 20 2017 YoungJoo.Kim ] 18 | * The first version. 19 | 20 | # vi:set ft=changelog ts=4 sw=4 et fdm=marker: 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2017, YoungJoo.Kim 2 | 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, 9 | this list of conditions and the following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 19 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 20 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 21 | OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 24 | OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /config: -------------------------------------------------------------------------------- 1 | ngx_addon_name=ngx_http_stream_server_traffic_status_module 2 | have=NGX_STAT_STUB . auto/have 3 | 4 | HTTP_STREAM_STS_SRCS=" \ 5 | $ngx_addon_dir/src/ngx_http_stream_server_traffic_status_module.c \ 6 | $ngx_addon_dir/src/ngx_http_stream_server_traffic_status_string.c \ 7 | $ngx_addon_dir/src/ngx_http_stream_server_traffic_status_shm.c \ 8 | $ngx_addon_dir/src/ngx_http_stream_server_traffic_status_node.c \ 9 | $ngx_addon_dir/src/ngx_http_stream_server_traffic_status_filter.c \ 10 | $ngx_addon_dir/src/ngx_http_stream_server_traffic_status_control.c \ 11 | $ngx_addon_dir/src/ngx_http_stream_server_traffic_status_display.c \ 12 | $ngx_addon_dir/src/ngx_http_stream_server_traffic_status_display_json.c \ 13 | $ngx_addon_dir/src/ngx_http_stream_server_traffic_status_display_prometheus.c \ 14 | " 15 | 16 | HTTP_STREAM_STS_DEPS=" \ 17 | $ngx_addon_dir/src/ngx_http_stream_server_traffic_status_module.h \ 18 | $ngx_addon_dir/src/ngx_http_stream_server_traffic_status_string.h \ 19 | $ngx_addon_dir/src/ngx_http_stream_server_traffic_status_shm.h \ 20 | $ngx_addon_dir/src/ngx_http_stream_server_traffic_status_node.h \ 21 | $ngx_addon_dir/src/ngx_http_stream_server_traffic_status_filter.h \ 22 | $ngx_addon_dir/src/ngx_http_stream_server_traffic_status_control.h \ 23 | $ngx_addon_dir/src/ngx_http_stream_server_traffic_status_display.h \ 24 | $ngx_addon_dir/src/ngx_http_stream_server_traffic_status_display_json.h \ 25 | $ngx_addon_dir/src/ngx_http_stream_server_traffic_status_display_prometheus.h \ 26 | $ngx_addon_dir/src/ngx_http_stream_server_traffic_status_module_html.h \ 27 | " 28 | if test -n "$ngx_module_link"; then 29 | ngx_module_type=HTTP 30 | ngx_module_name=$ngx_addon_name 31 | ngx_module_srcs="$HTTP_STREAM_STS_SRCS" 32 | ngx_module_deps="$HTTP_STREAM_STS_DEPS" 33 | 34 | . auto/module 35 | else 36 | HTTP_MODULES="$HTTP_MODULES $ngx_addon_name" 37 | NGX_ADDON_SRCS="$NGX_ADDON_SRCS $HTTP_STREAM_STS_SRCS" 38 | NGX_ADDON_DEPS="$NGX_ADDON_DEPS $HTTP_STREAM_STS_DEPS" 39 | fi 40 | 41 | # vi:set ft=sh ts=4 sw=4 et fdm=marker: 42 | -------------------------------------------------------------------------------- /src/ngx_http_stream_server_traffic_status_control.c: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) YoungJoo Kim (vozlt) 4 | */ 5 | 6 | 7 | #include 8 | 9 | #include "ngx_http_stream_server_traffic_status_module.h" 10 | #include "ngx_http_stream_server_traffic_status_control.h" 11 | #include "ngx_http_stream_server_traffic_status_display_json.h" 12 | #include "ngx_http_stream_server_traffic_status_display.h" 13 | 14 | static void ngx_http_stream_server_traffic_status_node_upstream_lookup( 15 | ngx_http_stream_server_traffic_status_control_t *control, 16 | ngx_stream_upstream_server_t *us); 17 | static void ngx_http_stream_server_traffic_status_node_status_all( 18 | ngx_http_stream_server_traffic_status_control_t *control); 19 | static void ngx_http_stream_server_traffic_status_node_status_group( 20 | ngx_http_stream_server_traffic_status_control_t *control); 21 | static void ngx_http_stream_server_traffic_status_node_status_zone( 22 | ngx_http_stream_server_traffic_status_control_t *control); 23 | 24 | static ngx_int_t ngx_http_stream_server_traffic_status_node_delete_get_nodes( 25 | ngx_http_stream_server_traffic_status_control_t *control, 26 | ngx_array_t **nodes, ngx_rbtree_node_t *node); 27 | static void ngx_http_stream_server_traffic_status_node_delete_all( 28 | ngx_http_stream_server_traffic_status_control_t *control); 29 | static void ngx_http_stream_server_traffic_status_node_delete_group( 30 | ngx_http_stream_server_traffic_status_control_t *control); 31 | static void ngx_http_stream_server_traffic_status_node_delete_zone( 32 | ngx_http_stream_server_traffic_status_control_t *control); 33 | 34 | static void ngx_http_stream_server_traffic_status_node_reset_all( 35 | ngx_http_stream_server_traffic_status_control_t *control, 36 | ngx_rbtree_node_t *node); 37 | static void ngx_http_stream_server_traffic_status_node_reset_group( 38 | ngx_http_stream_server_traffic_status_control_t *control, 39 | ngx_rbtree_node_t *node); 40 | static void ngx_http_stream_server_traffic_status_node_reset_zone( 41 | ngx_http_stream_server_traffic_status_control_t *control); 42 | 43 | 44 | static void 45 | ngx_http_stream_server_traffic_status_node_upstream_lookup( 46 | ngx_http_stream_server_traffic_status_control_t *control, 47 | ngx_stream_upstream_server_t *usn) 48 | { 49 | ngx_int_t rc; 50 | ngx_str_t key, usg, ush; 51 | ngx_uint_t i, j; 52 | ngx_stream_upstream_server_t *us; 53 | ngx_stream_upstream_srv_conf_t *uscf, **uscfp; 54 | ngx_stream_upstream_main_conf_t *umcf; 55 | ngx_http_stream_server_traffic_status_ctx_t *ctx; 56 | 57 | ctx = ngx_http_get_module_main_conf(control->r, ngx_http_stream_server_traffic_status_module); 58 | umcf = ctx->upstream; 59 | uscfp = umcf->upstreams.elts; 60 | 61 | key = *control->zone; 62 | 63 | if (control->group == NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_UPSTREAM_UA) { 64 | 65 | #if nginx_version > 1007001 66 | usn->name = key; 67 | #endif 68 | 69 | usn->weight = 0; 70 | usn->max_fails = 0; 71 | usn->fail_timeout = 0; 72 | usn->down = 0; 73 | usn->backup = 0; 74 | control->count++; 75 | return; 76 | } 77 | 78 | usg = ush = key; 79 | 80 | rc = ngx_http_stream_server_traffic_status_node_position_key(&usg, 0); 81 | if (rc != NGX_OK) { 82 | ngx_log_error(NGX_LOG_ERR, control->r->connection->log, 0, 83 | "node_upstream_lookup::node_position_key(\"%V\", 0) group not found", &usg); 84 | return; 85 | } 86 | 87 | rc = ngx_http_stream_server_traffic_status_node_position_key(&ush, 1); 88 | if (rc != NGX_OK) { 89 | ngx_log_error(NGX_LOG_ERR, control->r->connection->log, 0, 90 | "node_upstream_lookup::node_position_key(\"%V\", 1) host not found", &ush); 91 | return; 92 | } 93 | 94 | for (i = 0; i < umcf->upstreams.nelts; i++) { 95 | uscf = uscfp[i]; 96 | 97 | /* nogroups */ 98 | if(uscf->servers == NULL && uscf->port != 0) { 99 | continue; 100 | } 101 | 102 | us = uscf->servers->elts; 103 | 104 | if (uscf->host.len == usg.len) { 105 | if (ngx_strncmp(uscf->host.data, usg.data, usg.len) == 0) { 106 | 107 | for (j = 0; j < uscf->servers->nelts; j++) { 108 | if (us[j].addrs->name.len == ush.len) { 109 | if (ngx_strncmp(us[j].addrs->name.data, ush.data, ush.len) == 0) { 110 | *usn = us[j]; 111 | 112 | #if nginx_version > 1007001 113 | usn->name = us[j].addrs->name; 114 | #endif 115 | 116 | control->count++; 117 | break; 118 | } 119 | } 120 | } 121 | 122 | break; 123 | } 124 | } 125 | } 126 | } 127 | 128 | 129 | void 130 | ngx_http_stream_server_traffic_status_node_control_range_set( 131 | ngx_http_stream_server_traffic_status_control_t *control) 132 | { 133 | ngx_uint_t state; 134 | 135 | if (control->group == -1) { 136 | state = NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_CONTROL_RANGE_ALL; 137 | 138 | } else { 139 | state = NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_CONTROL_RANGE_ZONE; 140 | 141 | if (control->zone->len == 0) { 142 | state = NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_CONTROL_RANGE_NONE; 143 | 144 | } else if (control->zone->len == 1) { 145 | if(ngx_strncmp(control->zone->data, "*", 1) == 0) { 146 | state = NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_CONTROL_RANGE_GROUP; 147 | } 148 | } 149 | } 150 | 151 | control->range = state; 152 | } 153 | 154 | 155 | static void 156 | ngx_http_stream_server_traffic_status_node_status_all( 157 | ngx_http_stream_server_traffic_status_control_t *control) 158 | { 159 | *control->buf = ngx_http_stream_server_traffic_status_display_set(control->r, *control->buf); 160 | } 161 | 162 | 163 | static void 164 | ngx_http_stream_server_traffic_status_node_status_group( 165 | ngx_http_stream_server_traffic_status_control_t *control) 166 | { 167 | u_char *o, *s; 168 | ngx_str_t key; 169 | ngx_rbtree_node_t *node; 170 | ngx_http_stream_server_traffic_status_ctx_t *ctx; 171 | 172 | ctx = ngx_http_get_module_main_conf(control->r, ngx_http_stream_server_traffic_status_module); 173 | 174 | node = ctx->rbtree->root; 175 | 176 | *control->buf = ngx_sprintf(*control->buf, NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_JSON_FMT_S); 177 | 178 | o = s = *control->buf; 179 | 180 | switch(control->group) { 181 | case NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_UPSTREAM_NO: 182 | *control->buf = ngx_sprintf(*control->buf, 183 | NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_JSON_FMT_SERVER_S); 184 | s = *control->buf; 185 | *control->buf = ngx_http_stream_server_traffic_status_display_set_server( 186 | control->r, *control->buf, node); 187 | break; 188 | 189 | case NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_UPSTREAM_UA: 190 | ngx_str_set(&key, "::nogroups"); 191 | *control->buf = ngx_sprintf(*control->buf, 192 | NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_JSON_FMT_ARRAY_S, &key); 193 | s = *control->buf; 194 | *control->buf = ngx_http_stream_server_traffic_status_display_set_upstream_alone( 195 | control->r, *control->buf, node); 196 | break; 197 | 198 | case NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_UPSTREAM_UG: 199 | *control->buf = ngx_sprintf(*control->buf, 200 | NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_JSON_FMT_UPSTREAM_S); 201 | s = *control->buf; 202 | *control->buf = ngx_http_stream_server_traffic_status_display_set_upstream_group( 203 | control->r, *control->buf); 204 | break; 205 | 206 | case NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_UPSTREAM_FG: 207 | *control->buf = ngx_sprintf(*control->buf, 208 | NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_JSON_FMT_FILTER_S); 209 | s = *control->buf; 210 | *control->buf = ngx_http_stream_server_traffic_status_display_set_filter( 211 | control->r, *control->buf, node); 212 | break; 213 | } 214 | 215 | if (s == *control->buf) { 216 | *control->buf = o; 217 | 218 | } else { 219 | (*control->buf)--; 220 | 221 | if (control->group == NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_UPSTREAM_UA) { 222 | *control->buf = ngx_sprintf(*control->buf, 223 | NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_JSON_FMT_ARRAY_E); 224 | 225 | } else { 226 | *control->buf = ngx_sprintf(*control->buf, NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_JSON_FMT_E); 227 | } 228 | 229 | control->count++; 230 | } 231 | 232 | *control->buf = ngx_sprintf(*control->buf, NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_JSON_FMT_E); 233 | } 234 | 235 | 236 | static void 237 | ngx_http_stream_server_traffic_status_node_status_zone( 238 | ngx_http_stream_server_traffic_status_control_t *control) 239 | { 240 | u_char *o; 241 | uint32_t hash; 242 | ngx_int_t rc; 243 | ngx_str_t key, dst; 244 | ngx_rbtree_node_t *node; 245 | ngx_stream_upstream_server_t us; 246 | ngx_http_stream_server_traffic_status_ctx_t *ctx; 247 | ngx_http_stream_server_traffic_status_node_t *stsn; 248 | 249 | ctx = ngx_http_get_module_main_conf(control->r, ngx_http_stream_server_traffic_status_module); 250 | 251 | rc = ngx_http_stream_server_traffic_status_node_generate_key(control->r->pool, &key, control->zone, 252 | control->group); 253 | if (rc != NGX_OK) { 254 | ngx_log_error(NGX_LOG_ERR, control->r->connection->log, 0, 255 | "node_status_zone::node_generate_key(\"%V\") failed", &key); 256 | return; 257 | } 258 | 259 | hash = ngx_crc32_short(key.data, key.len); 260 | node = ngx_http_stream_server_traffic_status_node_lookup(ctx->rbtree, &key, hash); 261 | 262 | if (node == NULL) { 263 | return; 264 | } 265 | 266 | stsn = (ngx_http_stream_server_traffic_status_node_t *) &node->color; 267 | 268 | if (control->group != NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_UPSTREAM_UG 269 | && control->group != NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_UPSTREAM_UA) 270 | { 271 | *control->buf = ngx_sprintf(*control->buf, NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_JSON_FMT_S); 272 | 273 | o = *control->buf; 274 | 275 | } else { 276 | o = *control->buf; 277 | } 278 | 279 | dst.data = stsn->data; 280 | dst.len = stsn->len; 281 | 282 | switch (control->group) { 283 | 284 | case NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_UPSTREAM_NO: 285 | *control->buf = ngx_http_stream_server_traffic_status_display_set_server_node(control->r, 286 | *control->buf, &key, stsn); 287 | break; 288 | 289 | case NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_UPSTREAM_UA: 290 | case NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_UPSTREAM_UG: 291 | ngx_http_stream_server_traffic_status_node_upstream_lookup(control, &us); 292 | if (control->count) { 293 | #if nginx_version > 1007001 294 | *control->buf = ngx_http_stream_server_traffic_status_display_set_upstream_node(control->r, 295 | *control->buf, &us, stsn); 296 | #else 297 | (void) ngx_http_stream_server_traffic_status_node_position_key(&dst, 1); 298 | *control->buf = ngx_http_stream_server_traffic_status_display_set_upstream_node(control->r, 299 | *control->buf, &us, stsn, &dst); 300 | #endif 301 | } 302 | break; 303 | 304 | case NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_UPSTREAM_FG: 305 | (void) ngx_http_stream_server_traffic_status_node_position_key(&dst, 2); 306 | *control->buf = ngx_http_stream_server_traffic_status_display_set_server_node(control->r, 307 | *control->buf, &dst, stsn); 308 | break; 309 | } 310 | 311 | if (o != *control->buf) { 312 | (*control->buf)--; 313 | 314 | if (control->group != NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_UPSTREAM_UG 315 | && control->group != NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_UPSTREAM_UA) 316 | { 317 | *control->buf = ngx_sprintf(*control->buf, NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_JSON_FMT_E); 318 | } 319 | 320 | control->count++; 321 | } 322 | } 323 | 324 | 325 | void 326 | ngx_http_stream_server_traffic_status_node_status( 327 | ngx_http_stream_server_traffic_status_control_t *control) 328 | { 329 | switch (control->range) { 330 | 331 | case NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_CONTROL_RANGE_ALL: 332 | ngx_http_stream_server_traffic_status_node_status_all(control); 333 | break; 334 | 335 | case NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_CONTROL_RANGE_GROUP: 336 | ngx_http_stream_server_traffic_status_node_status_group(control); 337 | break; 338 | 339 | case NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_CONTROL_RANGE_ZONE: 340 | ngx_http_stream_server_traffic_status_node_status_zone(control); 341 | break; 342 | } 343 | } 344 | 345 | 346 | static ngx_int_t 347 | ngx_http_stream_server_traffic_status_node_delete_get_nodes( 348 | ngx_http_stream_server_traffic_status_control_t *control, 349 | ngx_array_t **nodes, ngx_rbtree_node_t *node) 350 | { 351 | ngx_int_t rc; 352 | ngx_http_stream_server_traffic_status_ctx_t *ctx; 353 | ngx_http_stream_server_traffic_status_node_t *stsn; 354 | ngx_http_stream_server_traffic_status_delete_t *delete; 355 | 356 | ctx = ngx_http_get_module_main_conf(control->r, ngx_http_stream_server_traffic_status_module); 357 | 358 | if (node != ctx->rbtree->sentinel) { 359 | stsn = (ngx_http_stream_server_traffic_status_node_t *) &node->color; 360 | 361 | if ((ngx_int_t) stsn->stat_upstream.type == control->group) { 362 | 363 | if (*nodes == NULL) { 364 | *nodes = ngx_array_create(control->r->pool, 1, 365 | sizeof(ngx_http_stream_server_traffic_status_delete_t)); 366 | 367 | if (*nodes == NULL) { 368 | ngx_log_error(NGX_LOG_ERR, control->r->connection->log, 0, 369 | "node_delete_get_nodes::ngx_array_create() failed"); 370 | return NGX_ERROR; 371 | } 372 | } 373 | 374 | delete = ngx_array_push(*nodes); 375 | if (delete == NULL) { 376 | ngx_log_error(NGX_LOG_ERR, control->r->connection->log, 0, 377 | "node_delete_get_nodes::ngx_array_push() failed"); 378 | return NGX_ERROR; 379 | } 380 | 381 | delete->node = node; 382 | } 383 | 384 | rc = ngx_http_stream_server_traffic_status_node_delete_get_nodes(control, nodes, node->left); 385 | if (rc != NGX_OK) { 386 | return rc; 387 | } 388 | 389 | rc = ngx_http_stream_server_traffic_status_node_delete_get_nodes(control, nodes, node->right); 390 | if (rc != NGX_OK) { 391 | return rc; 392 | } 393 | } 394 | 395 | return NGX_OK; 396 | } 397 | 398 | 399 | static void 400 | ngx_http_stream_server_traffic_status_node_delete_all( 401 | ngx_http_stream_server_traffic_status_control_t *control) 402 | { 403 | ngx_slab_pool_t *shpool; 404 | ngx_rbtree_node_t *node, *sentinel; 405 | ngx_http_stream_server_traffic_status_ctx_t *ctx; 406 | ngx_http_stream_server_traffic_status_loc_conf_t *stscf; 407 | 408 | ctx = ngx_http_get_module_main_conf(control->r, ngx_http_stream_server_traffic_status_module); 409 | 410 | stscf = ngx_http_get_module_loc_conf(control->r, ngx_http_stream_server_traffic_status_module); 411 | 412 | node = ctx->rbtree->root; 413 | sentinel = ctx->rbtree->sentinel; 414 | shpool = (ngx_slab_pool_t *) stscf->shm_zone->shm.addr; 415 | 416 | while (node != sentinel) { 417 | 418 | ngx_rbtree_delete(ctx->rbtree, node); 419 | ngx_slab_free_locked(shpool, node); 420 | 421 | control->count++; 422 | 423 | node = ctx->rbtree->root; 424 | } 425 | } 426 | 427 | 428 | static void 429 | ngx_http_stream_server_traffic_status_node_delete_group( 430 | ngx_http_stream_server_traffic_status_control_t *control) 431 | { 432 | ngx_int_t rc; 433 | ngx_uint_t n, i; 434 | ngx_array_t *nodes; 435 | ngx_slab_pool_t *shpool; 436 | ngx_rbtree_node_t *node; 437 | ngx_http_stream_server_traffic_status_ctx_t *ctx; 438 | ngx_http_stream_server_traffic_status_delete_t *deletes; 439 | ngx_http_stream_server_traffic_status_loc_conf_t *stscf; 440 | 441 | ctx = ngx_http_get_module_main_conf(control->r, ngx_http_stream_server_traffic_status_module); 442 | 443 | stscf = ngx_http_get_module_loc_conf(control->r, ngx_http_stream_server_traffic_status_module); 444 | 445 | node = ctx->rbtree->root; 446 | shpool = (ngx_slab_pool_t *) stscf->shm_zone->shm.addr; 447 | 448 | nodes = NULL; 449 | 450 | rc = ngx_http_stream_server_traffic_status_node_delete_get_nodes(control, &nodes, node); 451 | 452 | /* not found */ 453 | if (nodes == NULL) { 454 | return; 455 | } 456 | 457 | if (rc != NGX_OK) { 458 | ngx_log_error(NGX_LOG_ERR, control->r->connection->log, 0, 459 | "node_delete_group::node_delete_get_nodes() failed"); 460 | return; 461 | } 462 | 463 | deletes = nodes->elts; 464 | n = nodes->nelts; 465 | 466 | for (i = 0; i < n; i++) { 467 | node = deletes[i].node; 468 | 469 | ngx_rbtree_delete(ctx->rbtree, node); 470 | ngx_slab_free_locked(shpool, node); 471 | 472 | control->count++; 473 | } 474 | } 475 | 476 | 477 | static void 478 | ngx_http_stream_server_traffic_status_node_delete_zone( 479 | ngx_http_stream_server_traffic_status_control_t *control) 480 | { 481 | uint32_t hash; 482 | ngx_int_t rc; 483 | ngx_str_t key; 484 | ngx_slab_pool_t *shpool; 485 | ngx_rbtree_node_t *node; 486 | ngx_http_stream_server_traffic_status_ctx_t *ctx; 487 | ngx_http_stream_server_traffic_status_loc_conf_t *stscf; 488 | 489 | ctx = ngx_http_get_module_main_conf(control->r, ngx_http_stream_server_traffic_status_module); 490 | 491 | stscf = ngx_http_get_module_loc_conf(control->r, ngx_http_stream_server_traffic_status_module); 492 | 493 | shpool = (ngx_slab_pool_t *) stscf->shm_zone->shm.addr; 494 | 495 | rc = ngx_http_stream_server_traffic_status_node_generate_key(control->r->pool, &key, control->zone, 496 | control->group); 497 | if (rc != NGX_OK) { 498 | return; 499 | } 500 | 501 | hash = ngx_crc32_short(key.data, key.len); 502 | node = ngx_http_stream_server_traffic_status_node_lookup(ctx->rbtree, &key, hash); 503 | 504 | if (node != NULL) { 505 | ngx_rbtree_delete(ctx->rbtree, node); 506 | ngx_slab_free_locked(shpool, node); 507 | 508 | control->count++; 509 | } 510 | } 511 | 512 | 513 | void 514 | ngx_http_stream_server_traffic_status_node_delete( 515 | ngx_http_stream_server_traffic_status_control_t *control) 516 | { 517 | switch (control->range) { 518 | 519 | case NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_CONTROL_RANGE_ALL: 520 | ngx_http_stream_server_traffic_status_node_delete_all(control); 521 | break; 522 | 523 | case NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_CONTROL_RANGE_GROUP: 524 | ngx_http_stream_server_traffic_status_node_delete_group(control); 525 | break; 526 | 527 | case NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_CONTROL_RANGE_ZONE: 528 | ngx_http_stream_server_traffic_status_node_delete_zone(control); 529 | break; 530 | } 531 | 532 | *control->buf = ngx_sprintf(*control->buf, 533 | NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_JSON_FMT_CONTROL, 534 | ngx_http_stream_server_traffic_status_boolean_to_string(1), 535 | control->arg_cmd, control->arg_group, 536 | control->arg_zone, control->count); 537 | } 538 | 539 | 540 | static void 541 | ngx_http_stream_server_traffic_status_node_reset_all( 542 | ngx_http_stream_server_traffic_status_control_t *control, 543 | ngx_rbtree_node_t *node) 544 | { 545 | ngx_http_stream_server_traffic_status_ctx_t *ctx; 546 | ngx_http_stream_server_traffic_status_node_t *stsn; 547 | 548 | ctx = ngx_http_get_module_main_conf(control->r, ngx_http_stream_server_traffic_status_module); 549 | 550 | if (node != ctx->rbtree->sentinel) { 551 | stsn = (ngx_http_stream_server_traffic_status_node_t *) &node->color; 552 | 553 | ngx_http_stream_server_traffic_status_node_zero(stsn); 554 | control->count++; 555 | 556 | ngx_http_stream_server_traffic_status_node_reset_all(control, node->left); 557 | ngx_http_stream_server_traffic_status_node_reset_all(control, node->right); 558 | } 559 | } 560 | 561 | 562 | static void 563 | ngx_http_stream_server_traffic_status_node_reset_group( 564 | ngx_http_stream_server_traffic_status_control_t *control, 565 | ngx_rbtree_node_t *node) 566 | { 567 | ngx_http_stream_server_traffic_status_ctx_t *ctx; 568 | ngx_http_stream_server_traffic_status_node_t *stsn; 569 | 570 | ctx = ngx_http_get_module_main_conf(control->r, ngx_http_stream_server_traffic_status_module); 571 | 572 | if (node != ctx->rbtree->sentinel) { 573 | stsn = (ngx_http_stream_server_traffic_status_node_t *) &node->color; 574 | 575 | if ((ngx_int_t) stsn->stat_upstream.type == control->group) { 576 | ngx_http_stream_server_traffic_status_node_zero(stsn); 577 | control->count++; 578 | } 579 | 580 | ngx_http_stream_server_traffic_status_node_reset_group(control, node->left); 581 | ngx_http_stream_server_traffic_status_node_reset_group(control, node->right); 582 | } 583 | } 584 | 585 | 586 | static void 587 | ngx_http_stream_server_traffic_status_node_reset_zone( 588 | ngx_http_stream_server_traffic_status_control_t *control) 589 | { 590 | uint32_t hash; 591 | ngx_int_t rc; 592 | ngx_str_t key; 593 | ngx_rbtree_node_t *node; 594 | ngx_http_stream_server_traffic_status_ctx_t *ctx; 595 | ngx_http_stream_server_traffic_status_node_t *stsn; 596 | 597 | ctx = ngx_http_get_module_main_conf(control->r, ngx_http_stream_server_traffic_status_module); 598 | 599 | rc = ngx_http_stream_server_traffic_status_node_generate_key(control->r->pool, 600 | &key, 601 | control->zone, 602 | control->group); 603 | if (rc != NGX_OK) { 604 | return; 605 | } 606 | 607 | hash = ngx_crc32_short(key.data, key.len); 608 | node = ngx_http_stream_server_traffic_status_node_lookup(ctx->rbtree, &key, hash); 609 | 610 | if (node != NULL) { 611 | stsn = (ngx_http_stream_server_traffic_status_node_t *) &node->color; 612 | ngx_http_stream_server_traffic_status_node_zero(stsn); 613 | control->count++; 614 | } 615 | } 616 | 617 | 618 | void 619 | ngx_http_stream_server_traffic_status_node_reset( 620 | ngx_http_stream_server_traffic_status_control_t *control) 621 | { 622 | ngx_rbtree_node_t *node; 623 | ngx_http_stream_server_traffic_status_ctx_t *ctx; 624 | 625 | ctx = ngx_http_get_module_main_conf(control->r, ngx_http_stream_server_traffic_status_module); 626 | 627 | node = ctx->rbtree->root; 628 | 629 | switch (control->range) { 630 | 631 | case NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_CONTROL_RANGE_ALL: 632 | ngx_http_stream_server_traffic_status_node_reset_all(control, node); 633 | break; 634 | 635 | case NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_CONTROL_RANGE_GROUP: 636 | ngx_http_stream_server_traffic_status_node_reset_group(control, node); 637 | break; 638 | 639 | case NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_CONTROL_RANGE_ZONE: 640 | ngx_http_stream_server_traffic_status_node_reset_zone(control); 641 | break; 642 | } 643 | 644 | *control->buf = ngx_sprintf(*control->buf, 645 | NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_JSON_FMT_CONTROL, 646 | ngx_http_stream_server_traffic_status_boolean_to_string(1), 647 | control->arg_cmd, control->arg_group, 648 | control->arg_zone, control->count); 649 | } 650 | 651 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ 652 | -------------------------------------------------------------------------------- /src/ngx_http_stream_server_traffic_status_control.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) YoungJoo Kim (vozlt) 4 | */ 5 | 6 | 7 | #ifndef _NGX_HTTP_STREAM_STS_CONTROL_H_INCLUDED_ 8 | #define _NGX_HTTP_STREAM_STS_CONTROL_H_INCLUDED_ 9 | 10 | 11 | #define NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_CONTROL_CMD_NONE 0 12 | #define NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_CONTROL_CMD_STATUS 1 13 | #define NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_CONTROL_CMD_DELETE 2 14 | #define NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_CONTROL_CMD_RESET 3 15 | 16 | #define NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_CONTROL_RANGE_NONE 0 17 | #define NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_CONTROL_RANGE_ALL 1 18 | #define NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_CONTROL_RANGE_GROUP 2 19 | #define NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_CONTROL_RANGE_ZONE 3 20 | 21 | #define NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_JSON_FMT_CONTROL "{" \ 22 | "\"processingReturn\":%s," \ 23 | "\"processingCommandString\":\"%V\"," \ 24 | "\"processingGroupString\":\"%V\"," \ 25 | "\"processingZoneString\":\"%V\"," \ 26 | "\"processingCounts\":%ui" \ 27 | "}" 28 | 29 | 30 | typedef struct { 31 | ngx_rbtree_node_t *node; 32 | } ngx_http_stream_server_traffic_status_delete_t; 33 | 34 | 35 | typedef struct { 36 | ngx_http_request_t *r; 37 | ngx_uint_t command; 38 | ngx_int_t group; 39 | ngx_str_t *zone; 40 | ngx_str_t *arg_cmd; 41 | ngx_str_t *arg_group; 42 | ngx_str_t *arg_zone; 43 | ngx_uint_t range; 44 | ngx_uint_t count; 45 | u_char **buf; 46 | } ngx_http_stream_server_traffic_status_control_t; 47 | 48 | 49 | void ngx_http_stream_server_traffic_status_node_control_range_set( 50 | ngx_http_stream_server_traffic_status_control_t *control); 51 | void ngx_http_stream_server_traffic_status_node_status( 52 | ngx_http_stream_server_traffic_status_control_t *control); 53 | void ngx_http_stream_server_traffic_status_node_delete( 54 | ngx_http_stream_server_traffic_status_control_t *control); 55 | void ngx_http_stream_server_traffic_status_node_reset( 56 | ngx_http_stream_server_traffic_status_control_t *control); 57 | 58 | 59 | #endif /* _NGX_HTTP_STREAM_STS_CONTROL_H_INCLUDED_ */ 60 | 61 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ 62 | -------------------------------------------------------------------------------- /src/ngx_http_stream_server_traffic_status_display.c: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) YoungJoo Kim (vozlt) 4 | */ 5 | 6 | 7 | #include 8 | 9 | #include "ngx_http_stream_server_traffic_status_module_html.h" 10 | #include "ngx_http_stream_server_traffic_status_module.h" 11 | #include "ngx_http_stream_server_traffic_status_shm.h" 12 | #include "ngx_http_stream_server_traffic_status_display_prometheus.h" 13 | #include "ngx_http_stream_server_traffic_status_display_json.h" 14 | #include "ngx_http_stream_server_traffic_status_display.h" 15 | #include "ngx_http_stream_server_traffic_status_control.h" 16 | 17 | 18 | static ngx_int_t ngx_http_stream_server_traffic_status_display_handler( 19 | ngx_http_request_t *r); 20 | static ngx_int_t ngx_http_stream_server_traffic_status_display_handler_control( 21 | ngx_http_request_t *r); 22 | static ngx_int_t ngx_http_stream_server_traffic_status_display_handler_default( 23 | ngx_http_request_t *r); 24 | 25 | 26 | static ngx_int_t 27 | ngx_http_stream_server_traffic_status_display_handler(ngx_http_request_t *r) 28 | { 29 | size_t len; 30 | u_char *p; 31 | ngx_int_t rc; 32 | ngx_http_stream_server_traffic_status_ctx_t *ctx; 33 | 34 | ctx = ngx_http_get_module_main_conf(r, ngx_http_stream_server_traffic_status_module); 35 | 36 | if (!ctx->enable) { 37 | return NGX_HTTP_NOT_IMPLEMENTED; 38 | } 39 | 40 | if (r->method != NGX_HTTP_GET && r->method != NGX_HTTP_HEAD) { 41 | return NGX_HTTP_NOT_ALLOWED; 42 | } 43 | 44 | rc = ngx_http_stream_server_traffic_status_shm_init(r); 45 | if (rc != NGX_OK) { 46 | ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, 47 | "display_handler::shm_init() failed"); 48 | return NGX_HTTP_SERVICE_UNAVAILABLE; 49 | } 50 | 51 | len = 0; 52 | 53 | p = (u_char *) ngx_strchr(r->uri.data, '/'); 54 | 55 | if (p) { 56 | p = (u_char *) ngx_strchr(p + 1, '/'); 57 | len = r->uri.len - (p - r->uri.data); 58 | } 59 | 60 | /* control processing handler */ 61 | if (p && len >= sizeof("/control") - 1) { 62 | p = r->uri.data + r->uri.len - sizeof("/control") + 1; 63 | if (ngx_strncasecmp(p, (u_char *) "/control", sizeof("/control") - 1) == 0) { 64 | rc = ngx_http_stream_server_traffic_status_display_handler_control(r); 65 | goto done; 66 | } 67 | } 68 | 69 | /* default processing handler */ 70 | rc = ngx_http_stream_server_traffic_status_display_handler_default(r); 71 | 72 | done: 73 | 74 | return rc; 75 | } 76 | 77 | 78 | static ngx_int_t 79 | ngx_http_stream_server_traffic_status_display_handler_control(ngx_http_request_t *r) 80 | { 81 | size_t size; 82 | ngx_int_t rc; 83 | ngx_str_t type, alpha, arg_cmd, arg_group, arg_zone; 84 | ngx_buf_t *b; 85 | ngx_chain_t out; 86 | ngx_slab_pool_t *shpool; 87 | ngx_http_stream_server_traffic_status_ctx_t *ctx; 88 | ngx_http_stream_server_traffic_status_control_t *control; 89 | ngx_http_stream_server_traffic_status_loc_conf_t *stscf; 90 | 91 | ctx = ngx_http_get_module_main_conf(r, ngx_http_stream_server_traffic_status_module); 92 | 93 | stscf = ngx_http_get_module_loc_conf(r, ngx_http_stream_server_traffic_status_module); 94 | 95 | /* init control */ 96 | control = ngx_pcalloc(r->pool, sizeof(ngx_http_stream_server_traffic_status_control_t)); 97 | control->r = r; 98 | control->command = NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_CONTROL_CMD_NONE; 99 | control->group = -2; 100 | control->zone = ngx_pcalloc(r->pool, sizeof(ngx_str_t)); 101 | control->arg_cmd = &arg_cmd; 102 | control->arg_group = &arg_group; 103 | control->arg_zone = &arg_zone; 104 | control->range = NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_CONTROL_RANGE_NONE; 105 | control->count = 0; 106 | 107 | arg_cmd.len = 0; 108 | arg_group.len = 0; 109 | arg_zone.len = 0; 110 | 111 | if (r->args.len) { 112 | 113 | if (ngx_http_arg(r, (u_char *) "cmd", 3, &arg_cmd) == NGX_OK) { 114 | 115 | if (arg_cmd.len == 6 && ngx_strncmp(arg_cmd.data, "status", 6) == 0) 116 | { 117 | control->command = NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_CONTROL_CMD_STATUS; 118 | } 119 | else if (arg_cmd.len == 6 && ngx_strncmp(arg_cmd.data, "delete", 6) == 0) 120 | { 121 | control->command = NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_CONTROL_CMD_DELETE; 122 | } 123 | else if (arg_cmd.len == 5 && ngx_strncmp(arg_cmd.data, "reset", 5) == 0) 124 | { 125 | control->command = NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_CONTROL_CMD_RESET; 126 | } 127 | else 128 | { 129 | control->command = NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_CONTROL_CMD_NONE; 130 | } 131 | } 132 | 133 | if (ngx_http_arg(r, (u_char *) "group", 5, &arg_group) == NGX_OK) { 134 | 135 | if (arg_group.len == 1 && ngx_strncmp(arg_group.data, "*", 1) == 0) 136 | { 137 | control->group = -1; 138 | } 139 | else if (arg_group.len == 6 140 | && ngx_strncasecmp(arg_group.data, (u_char *) "server", 6) == 0) 141 | { 142 | control->group = NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_UPSTREAM_NO; 143 | } 144 | else if (arg_group.len == 14 145 | && ngx_strncasecmp(arg_group.data, (u_char *) "upstream@alone", 14) == 0) 146 | { 147 | control->group = NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_UPSTREAM_UA; 148 | } 149 | else if (arg_group.len == 14 150 | && ngx_strncasecmp(arg_group.data, (u_char *) "upstream@group", 14) == 0) 151 | { 152 | control->group = NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_UPSTREAM_UG; 153 | } 154 | else if (arg_group.len == 6 155 | && ngx_strncasecmp(arg_group.data, (u_char *) "filter", 6) == 0) 156 | { 157 | control->group = NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_UPSTREAM_FG; 158 | } 159 | else { 160 | control->command = NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_CONTROL_CMD_NONE; 161 | } 162 | } 163 | 164 | if (ngx_http_arg(r, (u_char *) "zone", 4, &arg_zone) != NGX_OK) { 165 | if (control->group != -1) { 166 | control->command = NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_CONTROL_CMD_NONE; 167 | } 168 | 169 | } else { 170 | rc = ngx_http_stream_server_traffic_status_copy_str(r->pool, control->zone, &arg_zone); 171 | if (rc != NGX_OK) { 172 | ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, 173 | "display_handler_control::copy_str() failed"); 174 | } 175 | 176 | (void) ngx_http_stream_server_traffic_status_replace_chrc(control->zone, '@', 177 | NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_KEY_SEPARATOR); 178 | 179 | ngx_str_set(&alpha, "[:alpha:]"); 180 | 181 | rc = ngx_http_stream_server_traffic_status_replace_strc(control->zone, &alpha, '@'); 182 | if (rc != NGX_OK) { 183 | ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, 184 | "display_handler_control::replace_strc() failed"); 185 | } 186 | } 187 | 188 | ngx_http_stream_server_traffic_status_node_control_range_set(control); 189 | } 190 | 191 | if (control->command == NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_CONTROL_CMD_STATUS) { 192 | size = ctx->shm_size; 193 | 194 | } else { 195 | size = sizeof(NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_JSON_FMT_CONTROL) 196 | + arg_cmd.len + arg_group.len + arg_zone.len + 256; 197 | } 198 | 199 | ngx_str_set(&type, "application/json"); 200 | 201 | r->headers_out.content_type_len = type.len; 202 | r->headers_out.content_type = type; 203 | 204 | if (r->method == NGX_HTTP_HEAD) { 205 | r->headers_out.status = NGX_HTTP_OK; 206 | 207 | rc = ngx_http_send_header(r); 208 | 209 | if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { 210 | return rc; 211 | } 212 | } 213 | 214 | b = ngx_create_temp_buf(r->pool, size); 215 | if (b == NULL) { 216 | return NGX_HTTP_INTERNAL_SERVER_ERROR; 217 | } 218 | 219 | control->buf = &b->last; 220 | 221 | shpool = (ngx_slab_pool_t *) stscf->shm_zone->shm.addr; 222 | 223 | ngx_shmtx_lock(&shpool->mutex); 224 | 225 | switch (control->command) { 226 | 227 | case NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_CONTROL_CMD_STATUS: 228 | ngx_http_stream_server_traffic_status_node_status(control); 229 | break; 230 | 231 | case NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_CONTROL_CMD_DELETE: 232 | ngx_http_stream_server_traffic_status_node_delete(control); 233 | break; 234 | 235 | case NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_CONTROL_CMD_RESET: 236 | ngx_http_stream_server_traffic_status_node_reset(control); 237 | break; 238 | 239 | default: 240 | *control->buf = ngx_sprintf(*control->buf, 241 | NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_JSON_FMT_CONTROL, 242 | ngx_http_stream_server_traffic_status_boolean_to_string(0), 243 | control->arg_cmd, control->arg_group, 244 | control->arg_zone, control->count); 245 | break; 246 | } 247 | 248 | ngx_shmtx_unlock(&shpool->mutex); 249 | 250 | if (b->last == b->pos) { 251 | b->last = ngx_sprintf(b->last, "{}"); 252 | } 253 | 254 | r->headers_out.status = NGX_HTTP_OK; 255 | r->headers_out.content_length_n = b->last - b->pos; 256 | 257 | b->last_buf = (r == r->main) ? 1 : 0; /* if subrequest 0 else 1 */ 258 | b->last_in_chain = 1; 259 | 260 | out.buf = b; 261 | out.next = NULL; 262 | 263 | rc = ngx_http_send_header(r); 264 | if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { 265 | return rc; 266 | } 267 | 268 | return ngx_http_output_filter(r, &out); 269 | } 270 | 271 | 272 | static ngx_int_t 273 | ngx_http_stream_server_traffic_status_display_handler_default(ngx_http_request_t *r) 274 | { 275 | size_t len; 276 | u_char *o, *s; 277 | ngx_str_t uri, type; 278 | ngx_int_t size, format, rc; 279 | ngx_buf_t *b; 280 | ngx_chain_t out; 281 | ngx_slab_pool_t *shpool; 282 | ngx_http_stream_server_traffic_status_ctx_t *ctx; 283 | ngx_http_stream_server_traffic_status_loc_conf_t *stscf; 284 | 285 | ctx = ngx_http_get_module_main_conf(r, ngx_http_stream_server_traffic_status_module); 286 | 287 | stscf = ngx_http_get_module_loc_conf(r, ngx_http_stream_server_traffic_status_module); 288 | 289 | if (!ctx->enable) { 290 | return NGX_HTTP_NOT_IMPLEMENTED; 291 | } 292 | 293 | if (r->method != NGX_HTTP_GET && r->method != NGX_HTTP_HEAD) { 294 | return NGX_HTTP_NOT_ALLOWED; 295 | } 296 | 297 | uri = r->uri; 298 | 299 | format = NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_FORMAT_NONE; 300 | 301 | if (uri.len == 1) { 302 | if (ngx_strncmp(uri.data, "/", 1) == 0) { 303 | uri.len = 0; 304 | } 305 | } 306 | 307 | o = (u_char *) r->uri.data; 308 | s = o; 309 | 310 | len = r->uri.len; 311 | 312 | while(sizeof("/format/type") - 1 <= len) { 313 | if (ngx_strncasecmp(s, (u_char *) "/format/", sizeof("/format/") - 1) == 0) { 314 | uri.data = o; 315 | uri.len = (o == s) ? 0 : (size_t) (s - o); 316 | 317 | s += sizeof("/format/") - 1; 318 | 319 | if (ngx_strncasecmp(s, (u_char *) "jsonp", sizeof("jsonp") - 1) == 0) { 320 | format = NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_FORMAT_JSONP; 321 | 322 | } else if (ngx_strncasecmp(s, (u_char *) "json", sizeof("json") - 1) == 0) { 323 | format = NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_FORMAT_JSON; 324 | 325 | } else if (ngx_strncasecmp(s, (u_char *) "html", sizeof("html") - 1) == 0) { 326 | format = NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_FORMAT_HTML; 327 | 328 | } else if (ngx_strncasecmp(s, (u_char *) "prometheus", sizeof("prometheus") - 1) == 0) { 329 | format = NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_FORMAT_PROMETHEUS; 330 | 331 | } else { 332 | s -= 2; 333 | } 334 | 335 | if (format != NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_FORMAT_NONE) { 336 | break; 337 | } 338 | } 339 | 340 | if ((s = (u_char *) ngx_strchr(++s, '/')) == NULL) { 341 | break; 342 | } 343 | 344 | if (r->uri.len <= (size_t) (s - o)) { 345 | break; 346 | } 347 | 348 | len = r->uri.len - (size_t) (s - o); 349 | } 350 | 351 | format = (format == NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_FORMAT_NONE) ? stscf->format : format; 352 | 353 | rc = ngx_http_discard_request_body(r); 354 | if (rc != NGX_OK) { 355 | return rc; 356 | } 357 | 358 | if (format == NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_FORMAT_JSON) { 359 | ngx_str_set(&type, "application/json"); 360 | 361 | } else if (format == NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_FORMAT_JSONP) { 362 | ngx_str_set(&type, "application/javascript"); 363 | 364 | } else if (format == NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_FORMAT_PROMETHEUS) { 365 | ngx_str_set(&type, "text/plain"); 366 | 367 | } else { 368 | ngx_str_set(&type, "text/html"); 369 | } 370 | 371 | r->headers_out.content_type_len = type.len; 372 | r->headers_out.content_type = type; 373 | 374 | if (r->method == NGX_HTTP_HEAD) { 375 | r->headers_out.status = NGX_HTTP_OK; 376 | 377 | rc = ngx_http_send_header(r); 378 | 379 | if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { 380 | return rc; 381 | } 382 | } 383 | 384 | size = ngx_http_stream_server_traffic_status_display_get_size(r, format); 385 | if (size == NGX_ERROR) { 386 | ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, 387 | "display_handler_default::display_get_size() failed"); 388 | return NGX_HTTP_INTERNAL_SERVER_ERROR; 389 | } 390 | 391 | b = ngx_create_temp_buf(r->pool, size); 392 | if (b == NULL) { 393 | return NGX_HTTP_INTERNAL_SERVER_ERROR; 394 | } 395 | 396 | if (format == NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_FORMAT_JSON) { 397 | shpool = (ngx_slab_pool_t *) stscf->shm_zone->shm.addr; 398 | ngx_shmtx_lock(&shpool->mutex); 399 | b->last = ngx_http_stream_server_traffic_status_display_set(r, b->last); 400 | ngx_shmtx_unlock(&shpool->mutex); 401 | 402 | if (b->last == b->pos) { 403 | b->last = ngx_sprintf(b->last, "{}"); 404 | } 405 | 406 | } else if (format == NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_FORMAT_JSONP) { 407 | shpool = (ngx_slab_pool_t *) stscf->shm_zone->shm.addr; 408 | ngx_shmtx_lock(&shpool->mutex); 409 | b->last = ngx_sprintf(b->last, "%V", &stscf->jsonp); 410 | b->last = ngx_sprintf(b->last, "("); 411 | b->last = ngx_http_stream_server_traffic_status_display_set(r, b->last); 412 | b->last = ngx_sprintf(b->last, ")"); 413 | ngx_shmtx_unlock(&shpool->mutex); 414 | 415 | } else if (format == NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_FORMAT_PROMETHEUS) { 416 | shpool = (ngx_slab_pool_t *) stscf->shm_zone->shm.addr; 417 | ngx_shmtx_lock(&shpool->mutex); 418 | b->last = ngx_http_stream_server_traffic_status_display_prometheus_set(r, b->last); 419 | ngx_shmtx_unlock(&shpool->mutex); 420 | 421 | if (b->last == b->pos) { 422 | b->last = ngx_sprintf(b->last, "#"); 423 | } 424 | 425 | } else { 426 | b->last = ngx_sprintf(b->last, NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_HTML_DATA, &uri, &uri); 427 | } 428 | 429 | r->headers_out.status = NGX_HTTP_OK; 430 | r->headers_out.content_length_n = b->last - b->pos; 431 | 432 | b->last_buf = (r == r->main) ? 1 : 0; /* if subrequest 0 else 1 */ 433 | b->last_in_chain = 1; 434 | 435 | out.buf = b; 436 | out.next = NULL; 437 | 438 | rc = ngx_http_send_header(r); 439 | if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { 440 | return rc; 441 | } 442 | 443 | return ngx_http_output_filter(r, &out); 444 | } 445 | 446 | 447 | ngx_int_t 448 | ngx_http_stream_server_traffic_status_display_get_upstream_nelts(ngx_http_request_t *r) 449 | { 450 | ngx_uint_t i, j, n; 451 | ngx_stream_upstream_server_t *us; 452 | #if (NGX_STREAM_UPSTREAM_ZONE) 453 | ngx_stream_upstream_rr_peer_t *peer; 454 | ngx_stream_upstream_rr_peers_t *peers; 455 | #endif 456 | ngx_stream_upstream_srv_conf_t *uscf, **uscfp; 457 | ngx_stream_upstream_main_conf_t *umcf; 458 | ngx_http_stream_server_traffic_status_ctx_t *ctx; 459 | 460 | ctx = ngx_http_get_module_main_conf(r, ngx_http_stream_server_traffic_status_module); 461 | umcf = ctx->upstream; 462 | uscfp = umcf->upstreams.elts; 463 | 464 | for (i = 0, j = 0, n = 0; i < umcf->upstreams.nelts; i++) { 465 | 466 | uscf = uscfp[i]; 467 | 468 | /* groups */ 469 | if (uscf->servers && !uscf->port) { 470 | us = uscf->servers->elts; 471 | 472 | #if (NGX_HTTP_UPSTREAM_ZONE) 473 | if (uscf->shm_zone == NULL) { 474 | goto not_supported; 475 | } 476 | 477 | peers = uscf->peer.data; 478 | 479 | ngx_http_upstream_rr_peers_rlock(peers); 480 | 481 | for (peer = peers->peer; peer; peer = peer->next) { 482 | n++; 483 | } 484 | 485 | ngx_http_upstream_rr_peers_unlock(peers); 486 | 487 | not_supported: 488 | 489 | #endif 490 | 491 | for (j = 0; j < uscf->servers->nelts; j++) { 492 | n += us[j].naddrs; 493 | } 494 | } 495 | } 496 | 497 | return n; 498 | } 499 | 500 | 501 | ngx_int_t 502 | ngx_http_stream_server_traffic_status_display_get_size(ngx_http_request_t *r, 503 | ngx_int_t format) 504 | { 505 | ngx_uint_t size, un; 506 | ngx_slab_pool_t *shpool; 507 | ngx_http_stream_server_traffic_status_loc_conf_t *stscf; 508 | ngx_http_stream_server_traffic_status_shm_info_t *shm_info; 509 | 510 | stscf = ngx_http_get_module_loc_conf(r, ngx_http_stream_server_traffic_status_module); 511 | shpool = (ngx_slab_pool_t *) stscf->shm_zone->shm.addr; 512 | 513 | shm_info = ngx_pcalloc(r->pool, sizeof(ngx_http_stream_server_traffic_status_shm_info_t)); 514 | if (shm_info == NULL) { 515 | return NGX_ERROR; 516 | } 517 | 518 | /* Caveat: Do not use duplicate ngx_shmtx_lock() before this function. */ 519 | ngx_shmtx_lock(&shpool->mutex); 520 | 521 | ngx_http_stream_server_traffic_status_shm_info(r, shm_info); 522 | 523 | ngx_shmtx_unlock(&shpool->mutex); 524 | 525 | /* allocate memory for the upstream groups even if upstream node not exists */ 526 | un = shm_info->used_node 527 | + (ngx_uint_t) ngx_http_stream_server_traffic_status_display_get_upstream_nelts(r); 528 | 529 | size = 0; 530 | 531 | switch (format) { 532 | 533 | case NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_FORMAT_JSON: 534 | case NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_FORMAT_JSONP: 535 | size = sizeof(ngx_http_stream_server_traffic_status_node_t) / NGX_PTR_SIZE 536 | * NGX_ATOMIC_T_LEN * un /* values size */ 537 | + (un * 1024) /* names size */ 538 | + 4096; /* main size */ 539 | break; 540 | 541 | case NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_FORMAT_HTML: 542 | size = sizeof(NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_HTML_DATA) + ngx_pagesize; 543 | break; 544 | } 545 | 546 | if (size <= 0) { 547 | size = shm_info->max_size; 548 | } 549 | 550 | ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 551 | "sts::display_get_size(): size[%ui] used_size[%ui], used_node[%ui]", 552 | size, shm_info->used_size, shm_info->used_node); 553 | 554 | return size; 555 | } 556 | 557 | 558 | u_char * 559 | ngx_http_stream_server_traffic_status_display_get_time_queue( 560 | ngx_http_request_t *r, 561 | ngx_http_stream_server_traffic_status_node_time_queue_t *q, 562 | ngx_uint_t offset 563 | ) 564 | { 565 | u_char *p, *s; 566 | ngx_int_t i; 567 | 568 | if (q->front == q->rear) { 569 | return (u_char *) ""; 570 | } 571 | 572 | p = ngx_pcalloc(r->pool, q->len * NGX_INT_T_LEN); 573 | 574 | s = p; 575 | 576 | for (i = q->front; i != q->rear; i = (i + 1) % q->len) { 577 | s = ngx_sprintf(s, "%M,", *((ngx_msec_t *) ((char *) &(q->times[i]) + offset))); 578 | } 579 | 580 | if (s > p) { 581 | *(s - 1) = '\0'; 582 | } 583 | 584 | return p; 585 | } 586 | 587 | 588 | u_char * 589 | ngx_http_stream_server_traffic_status_display_get_time_queue_times( 590 | ngx_http_request_t *r, 591 | ngx_http_stream_server_traffic_status_node_time_queue_t *q) 592 | { 593 | return ngx_http_stream_server_traffic_status_display_get_time_queue(r, q, 594 | offsetof(ngx_http_stream_server_traffic_status_node_time_t, time)); 595 | } 596 | 597 | 598 | u_char * 599 | ngx_http_stream_server_traffic_status_display_get_time_queue_msecs( 600 | ngx_http_request_t *r, 601 | ngx_http_stream_server_traffic_status_node_time_queue_t *q) 602 | { 603 | return ngx_http_stream_server_traffic_status_display_get_time_queue(r, q, 604 | offsetof(ngx_http_stream_server_traffic_status_node_time_t, msec)); 605 | } 606 | 607 | 608 | u_char * 609 | ngx_http_stream_server_traffic_status_display_get_histogram_bucket( 610 | ngx_http_request_t *r, 611 | ngx_http_stream_server_traffic_status_node_histogram_bucket_t *b, 612 | ngx_uint_t offset, 613 | const char *fmt) 614 | { 615 | char *dst; 616 | u_char *p, *s; 617 | ngx_uint_t i, n; 618 | 619 | n = b->len; 620 | 621 | if (n == 0) { 622 | return (u_char *) ""; 623 | } 624 | 625 | p = ngx_pcalloc(r->pool, n * NGX_INT_T_LEN); 626 | if (p == NULL) { 627 | return (u_char *) ""; 628 | } 629 | 630 | s = p; 631 | 632 | for (i = 0; i < n; i++) { 633 | dst = (char *) &(b->buckets[i]) + offset; 634 | 635 | if (ngx_strncmp(fmt, "%M", 2) == 0) { 636 | s = ngx_sprintf(s, fmt, *((ngx_msec_t *) dst)); 637 | 638 | } else if (ngx_strncmp(fmt, "%uA", 3) == 0) { 639 | s = ngx_sprintf(s, fmt, *((ngx_atomic_uint_t *) dst)); 640 | } 641 | } 642 | 643 | if (s > p) { 644 | *(s - 1) = '\0'; 645 | } 646 | 647 | return p; 648 | } 649 | 650 | 651 | u_char * 652 | ngx_http_stream_server_traffic_status_display_get_histogram_bucket_msecs( 653 | ngx_http_request_t *r, 654 | ngx_http_stream_server_traffic_status_node_histogram_bucket_t *b) 655 | { 656 | return ngx_http_stream_server_traffic_status_display_get_histogram_bucket(r, b, 657 | offsetof(ngx_http_stream_server_traffic_status_node_histogram_t, msec), "%M,"); 658 | } 659 | 660 | 661 | u_char * 662 | ngx_http_stream_server_traffic_status_display_get_histogram_bucket_counters( 663 | ngx_http_request_t *r, 664 | ngx_http_stream_server_traffic_status_node_histogram_bucket_t *b) 665 | { 666 | return ngx_http_stream_server_traffic_status_display_get_histogram_bucket(r, b, 667 | offsetof(ngx_http_stream_server_traffic_status_node_histogram_t, counter), "%uA,"); 668 | } 669 | 670 | 671 | char * 672 | ngx_http_stream_server_traffic_status_display(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 673 | { 674 | ngx_http_core_loc_conf_t *clcf; 675 | 676 | clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); 677 | clcf->handler = ngx_http_stream_server_traffic_status_display_handler; 678 | 679 | return NGX_CONF_OK; 680 | } 681 | 682 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ 683 | -------------------------------------------------------------------------------- /src/ngx_http_stream_server_traffic_status_display.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) YoungJoo Kim (vozlt) 4 | */ 5 | 6 | 7 | #ifndef _NGX_HTTP_STREAM_STS_DISPLAY_H_INCLUDED_ 8 | #define _NGX_HTTP_STREAM_STS_DISPLAY_H_INCLUDED_ 9 | 10 | 11 | ngx_int_t ngx_http_stream_server_traffic_status_display_get_upstream_nelts( 12 | ngx_http_request_t *r); 13 | ngx_int_t ngx_http_stream_server_traffic_status_display_get_size( 14 | ngx_http_request_t *r, ngx_int_t format); 15 | 16 | u_char *ngx_http_stream_server_traffic_status_display_get_time_queue( 17 | ngx_http_request_t *r, 18 | ngx_http_stream_server_traffic_status_node_time_queue_t *q, 19 | ngx_uint_t offset); 20 | u_char *ngx_http_stream_server_traffic_status_display_get_time_queue_times( 21 | ngx_http_request_t *r, 22 | ngx_http_stream_server_traffic_status_node_time_queue_t *q); 23 | u_char *ngx_http_stream_server_traffic_status_display_get_time_queue_msecs( 24 | ngx_http_request_t *r, 25 | ngx_http_stream_server_traffic_status_node_time_queue_t *q); 26 | 27 | u_char *ngx_http_stream_server_traffic_status_display_get_histogram_bucket( 28 | ngx_http_request_t *r, 29 | ngx_http_stream_server_traffic_status_node_histogram_bucket_t *b, 30 | ngx_uint_t offset, const char *fmt); 31 | u_char *ngx_http_stream_server_traffic_status_display_get_histogram_bucket_msecs( 32 | ngx_http_request_t *r, 33 | ngx_http_stream_server_traffic_status_node_histogram_bucket_t *b); 34 | u_char *ngx_http_stream_server_traffic_status_display_get_histogram_bucket_counters( 35 | ngx_http_request_t *r, 36 | ngx_http_stream_server_traffic_status_node_histogram_bucket_t *q); 37 | 38 | char *ngx_http_stream_server_traffic_status_display(ngx_conf_t *cf, 39 | ngx_command_t *cmd, void *conf); 40 | 41 | 42 | #endif /* _NGX_HTTP_STREAM_STS_DISPLAY_H_INCLUDED_ */ 43 | 44 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ 45 | -------------------------------------------------------------------------------- /src/ngx_http_stream_server_traffic_status_display_json.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) YoungJoo Kim (vozlt) 4 | */ 5 | 6 | 7 | #ifndef _NGX_HTTP_STREAM_STS_DISPLAY_JSON_H_INCLUDED_ 8 | #define _NGX_HTTP_STREAM_STS_DISPLAY_JSON_H_INCLUDED_ 9 | 10 | 11 | #define NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_JSON_FMT_S "{" 12 | #define NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_JSON_FMT_OBJECT_S "\"%V\":{" 13 | #define NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_JSON_FMT_ARRAY_S "\"%V\":[" 14 | 15 | #define NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_JSON_FMT_ARRAY_E "]" 16 | #define NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_JSON_FMT_OBJECT_E "}" 17 | #define NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_JSON_FMT_E "}" 18 | #define NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_JSON_FMT_NEXT "," 19 | 20 | #define NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_JSON_FMT_MAIN \ 21 | "\"hostName\":\"%V\"," \ 22 | "\"nginxVersion\":\"%s\"," \ 23 | "\"loadMsec\":%M," \ 24 | "\"nowMsec\":%M," \ 25 | "\"connections\":{" \ 26 | "\"active\":%uA," \ 27 | "\"reading\":%uA," \ 28 | "\"writing\":%uA," \ 29 | "\"waiting\":%uA," \ 30 | "\"accepted\":%uA," \ 31 | "\"handled\":%uA," \ 32 | "\"requests\":%uA" \ 33 | "}," \ 34 | "\"sharedZones\":{" \ 35 | "\"name\":\"%V\"," \ 36 | "\"maxSize\":%ui," \ 37 | "\"usedSize\":%ui," \ 38 | "\"usedNode\":%ui" \ 39 | "}," 40 | 41 | #define NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_JSON_FMT_SERVER_S \ 42 | "\"streamServerZones\":{" 43 | 44 | #define NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_JSON_FMT_SERVER "\"%V\":{" \ 45 | "\"port\":%ui," \ 46 | "\"protocol\":\"%V\"," \ 47 | "\"connectCounter\":%uA," \ 48 | "\"inBytes\":%uA," \ 49 | "\"outBytes\":%uA," \ 50 | "\"responses\":{" \ 51 | "\"1xx\":%uA," \ 52 | "\"2xx\":%uA," \ 53 | "\"3xx\":%uA," \ 54 | "\"4xx\":%uA," \ 55 | "\"5xx\":%uA" \ 56 | "}," \ 57 | "\"sessionMsecCounter\":%uA," \ 58 | "\"sessionMsec\":%M," \ 59 | "\"sessionMsecs\":{" \ 60 | "\"times\":[%s]," \ 61 | "\"msecs\":[%s]" \ 62 | "}," \ 63 | "\"sessionBuckets\":{" \ 64 | "\"msecs\":[%s]," \ 65 | "\"counters\":[%s]" \ 66 | "}," \ 67 | "\"overCounts\":{" \ 68 | "\"maxIntegerSize\":%s," \ 69 | "\"connectCounter\":%uA," \ 70 | "\"inBytes\":%uA," \ 71 | "\"outBytes\":%uA," \ 72 | "\"1xx\":%uA," \ 73 | "\"2xx\":%uA," \ 74 | "\"3xx\":%uA," \ 75 | "\"4xx\":%uA," \ 76 | "\"5xx\":%uA," \ 77 | "\"sessionMsecCounter\":%uA" \ 78 | "}" \ 79 | "}," 80 | 81 | #define NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_JSON_FMT_FILTER_S \ 82 | "\"streamFilterZones\":{" 83 | 84 | #define NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_JSON_FMT_UPSTREAM_S \ 85 | "\"streamUpstreamZones\":{" 86 | #define NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_JSON_FMT_UPSTREAM \ 87 | "{\"server\":\"%V\"," \ 88 | "\"connectCounter\":%uA," \ 89 | "\"inBytes\":%uA," \ 90 | "\"outBytes\":%uA," \ 91 | "\"responses\":{" \ 92 | "\"1xx\":%uA," \ 93 | "\"2xx\":%uA," \ 94 | "\"3xx\":%uA," \ 95 | "\"4xx\":%uA," \ 96 | "\"5xx\":%uA" \ 97 | "}," \ 98 | "\"sessionMsecCounter\":%uA," \ 99 | "\"sessionMsec\":%M," \ 100 | "\"sessionMsecs\":{" \ 101 | "\"times\":[%s]," \ 102 | "\"msecs\":[%s]" \ 103 | "}," \ 104 | "\"sessionBuckets\":{" \ 105 | "\"msecs\":[%s]," \ 106 | "\"counters\":[%s]" \ 107 | "}," \ 108 | "\"uSessionMsecCounter\":%uA," \ 109 | "\"uSessionMsec\":%M," \ 110 | "\"uSessionMsecs\":{" \ 111 | "\"times\":[%s]," \ 112 | "\"msecs\":[%s]" \ 113 | "}," \ 114 | "\"uSessionBuckets\":{" \ 115 | "\"msecs\":[%s]," \ 116 | "\"counters\":[%s]" \ 117 | "}," \ 118 | "\"uConnectMsecCounter\":%uA," \ 119 | "\"uConnectMsec\":%M," \ 120 | "\"uConnectMsecs\":{" \ 121 | "\"times\":[%s]," \ 122 | "\"msecs\":[%s]" \ 123 | "}," \ 124 | "\"uConnectBuckets\":{" \ 125 | "\"msecs\":[%s]," \ 126 | "\"counters\":[%s]" \ 127 | "}," \ 128 | "\"uFirstByteMsecCounter\":%uA," \ 129 | "\"uFirstByteMsec\":%M," \ 130 | "\"uFirstByteMsecs\":{" \ 131 | "\"times\":[%s]," \ 132 | "\"msecs\":[%s]" \ 133 | "}," \ 134 | "\"uFirstByteBuckets\":{" \ 135 | "\"msecs\":[%s]," \ 136 | "\"counters\":[%s]" \ 137 | "}," \ 138 | "\"weight\":%ui," \ 139 | "\"maxFails\":%ui," \ 140 | "\"failTimeout\":%T," \ 141 | "\"backup\":%s," \ 142 | "\"down\":%s," \ 143 | "\"overCounts\":{" \ 144 | "\"maxIntegerSize\":%s," \ 145 | "\"connectCounter\":%uA," \ 146 | "\"inBytes\":%uA," \ 147 | "\"outBytes\":%uA," \ 148 | "\"1xx\":%uA," \ 149 | "\"2xx\":%uA," \ 150 | "\"3xx\":%uA," \ 151 | "\"4xx\":%uA," \ 152 | "\"5xx\":%uA," \ 153 | "\"sessionMsecCounter\":%uA," \ 154 | "\"uSessionMsecCounter\":%uA," \ 155 | "\"uConnectMsecCounter\":%uA," \ 156 | "\"uFirstByteMsecCounter\":%uA" \ 157 | "}" \ 158 | "}," 159 | 160 | 161 | u_char *ngx_http_stream_server_traffic_status_display_set_main( 162 | ngx_http_request_t *r, u_char *buf); 163 | u_char *ngx_http_stream_server_traffic_status_display_set_server_node( 164 | ngx_http_request_t *r, 165 | u_char *buf, ngx_str_t *key, 166 | ngx_http_stream_server_traffic_status_node_t *stsn); 167 | u_char *ngx_http_stream_server_traffic_status_display_set_server( 168 | ngx_http_request_t *r, u_char *buf, 169 | ngx_rbtree_node_t *node); 170 | 171 | u_char *ngx_http_stream_server_traffic_status_display_set_filter_node( 172 | ngx_http_request_t *r, u_char *buf, 173 | ngx_http_stream_server_traffic_status_node_t *stsn); 174 | u_char *ngx_http_stream_server_traffic_status_display_set_filter( 175 | ngx_http_request_t *r, u_char *buf, 176 | ngx_rbtree_node_t *node); 177 | 178 | u_char *ngx_http_stream_server_traffic_status_display_set_upstream_node( 179 | ngx_http_request_t *r, u_char *buf, 180 | ngx_stream_upstream_server_t *us, 181 | #if nginx_version > 1007001 182 | ngx_http_stream_server_traffic_status_node_t *stsn 183 | #else 184 | ngx_http_stream_server_traffic_status_node_t *stsn, ngx_str_t *name 185 | #endif 186 | ); 187 | u_char *ngx_http_stream_server_traffic_status_display_set_upstream_alone( 188 | ngx_http_request_t *r, u_char *buf, ngx_rbtree_node_t *node); 189 | u_char *ngx_http_stream_server_traffic_status_display_set_upstream_group( 190 | ngx_http_request_t *r, u_char *buf); 191 | 192 | u_char *ngx_http_stream_server_traffic_status_display_set(ngx_http_request_t *r, 193 | u_char *buf); 194 | 195 | 196 | #endif /* _NGX_HTTP_STREAM_STS_DISPLAY_JSON_H_INCLUDED_ */ 197 | 198 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ 199 | -------------------------------------------------------------------------------- /src/ngx_http_stream_server_traffic_status_display_prometheus.c: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) YoungJoo Kim (vozlt) 4 | */ 5 | 6 | 7 | #include 8 | 9 | #include "ngx_http_stream_server_traffic_status_module.h" 10 | #include "ngx_http_stream_server_traffic_status_shm.h" 11 | #include "ngx_http_stream_server_traffic_status_display_prometheus.h" 12 | 13 | 14 | u_char * 15 | ngx_http_stream_server_traffic_status_display_prometheus_set_main( 16 | ngx_http_request_t *r, u_char *buf) 17 | { 18 | ngx_atomic_int_t ap, hn, ac, rq, rd, wr, wa; 19 | ngx_http_stream_server_traffic_status_loc_conf_t *stscf; 20 | ngx_http_stream_server_traffic_status_shm_info_t *shm_info; 21 | 22 | stscf = ngx_http_get_module_loc_conf(r, ngx_http_stream_server_traffic_status_module); 23 | 24 | ap = *ngx_stat_accepted; 25 | hn = *ngx_stat_handled; 26 | ac = *ngx_stat_active; 27 | rq = *ngx_stat_requests; 28 | rd = *ngx_stat_reading; 29 | wr = *ngx_stat_writing; 30 | wa = *ngx_stat_waiting; 31 | 32 | shm_info = ngx_pcalloc(r->pool, sizeof(ngx_http_stream_server_traffic_status_shm_info_t)); 33 | if (shm_info == NULL) { 34 | return buf; 35 | } 36 | 37 | ngx_http_stream_server_traffic_status_shm_info(r, shm_info); 38 | 39 | buf = ngx_sprintf(buf, NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_PROMETHEUS_FMT_MAIN, 40 | &ngx_cycle->hostname, NGINX_VERSION, 41 | (double) stscf->start_msec / 1000, 42 | ap, ac, hn, rd, rq, wa, wr, 43 | shm_info->name, shm_info->max_size, 44 | shm_info->used_size, shm_info->used_node); 45 | 46 | return buf; 47 | } 48 | 49 | 50 | u_char * 51 | ngx_http_stream_server_traffic_status_display_prometheus_set_server_node( 52 | ngx_http_request_t *r, u_char *buf, 53 | ngx_http_stream_server_traffic_status_node_t *stsn) 54 | { 55 | ngx_str_t listen, protocol; 56 | ngx_uint_t i, n; 57 | ngx_http_stream_server_traffic_status_loc_conf_t *stscf; 58 | ngx_http_stream_server_traffic_status_node_histogram_bucket_t *b; 59 | 60 | stscf = ngx_http_get_module_loc_conf(r, ngx_http_stream_server_traffic_status_module); 61 | 62 | listen.data = stsn->data; 63 | listen.len = stsn->len; 64 | 65 | (void) ngx_http_stream_server_traffic_status_node_position_key(&listen, 1); 66 | 67 | protocol.len = 3; 68 | protocol.data = (u_char *) (stsn->protocol == SOCK_DGRAM ? "UDP" : "TCP"); 69 | 70 | buf = ngx_sprintf(buf, NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_PROMETHEUS_FMT_SERVER, 71 | &listen, stsn->port, &protocol, stsn->stat_in_bytes, 72 | &listen, stsn->port, &protocol, stsn->stat_out_bytes, 73 | &listen, stsn->port, &protocol, stsn->stat_1xx_counter, 74 | &listen, stsn->port, &protocol, stsn->stat_2xx_counter, 75 | &listen, stsn->port, &protocol, stsn->stat_3xx_counter, 76 | &listen, stsn->port, &protocol, stsn->stat_4xx_counter, 77 | &listen, stsn->port, &protocol, stsn->stat_5xx_counter, 78 | &listen, stsn->port, &protocol, stsn->stat_connect_counter, 79 | &listen, stsn->port, &protocol, (double) stsn->stat_session_time_counter / 1000, 80 | &listen, stsn->port, &protocol, 81 | (double) ngx_http_stream_server_traffic_status_node_time_queue_average( 82 | &stsn->stat_session_times, stscf->average_method, 83 | stscf->average_period) / 1000); 84 | 85 | 86 | /* histogram */ 87 | b = &stsn->stat_session_buckets; 88 | 89 | n = b->len; 90 | 91 | if (n > 0) { 92 | 93 | /* histogram:bucket */ 94 | for (i = 0; i < n; i++) { 95 | buf = ngx_sprintf(buf, 96 | NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_PROMETHEUS_FMT_SERVER_HISTOGRAM_BUCKET, 97 | &listen, stsn->port, &protocol, (double) b->buckets[i].msec / 1000, 98 | b->buckets[i].counter); 99 | } 100 | 101 | buf = ngx_sprintf(buf, 102 | NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_PROMETHEUS_FMT_SERVER_HISTOGRAM_BUCKET_E, 103 | &listen, stsn->port, &protocol, stsn->stat_connect_counter); 104 | 105 | /* histogram:sum */ 106 | buf = ngx_sprintf(buf, 107 | NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_PROMETHEUS_FMT_SERVER_HISTOGRAM_SUM, 108 | &listen, stsn->port, &protocol, 109 | (double) stsn->stat_session_time_counter / 1000); 110 | 111 | /* histogram:count */ 112 | buf = ngx_sprintf(buf, 113 | NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_PROMETHEUS_FMT_SERVER_HISTOGRAM_COUNT, 114 | &listen, stsn->port, &protocol, stsn->stat_connect_counter); 115 | } 116 | 117 | return buf; 118 | } 119 | 120 | 121 | u_char * 122 | ngx_http_stream_server_traffic_status_display_prometheus_set_server( 123 | ngx_http_request_t *r, u_char *buf, ngx_rbtree_node_t *node) 124 | { 125 | ngx_http_stream_server_traffic_status_ctx_t *ctx; 126 | ngx_http_stream_server_traffic_status_node_t *stsn; 127 | 128 | ctx = ngx_http_get_module_main_conf(r, ngx_http_stream_server_traffic_status_module); 129 | 130 | if (node != ctx->rbtree->sentinel) { 131 | stsn = (ngx_http_stream_server_traffic_status_node_t *) &node->color; 132 | 133 | if (stsn->stat_upstream.type == NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_UPSTREAM_NO) { 134 | buf = ngx_http_stream_server_traffic_status_display_prometheus_set_server_node(r, buf, stsn); 135 | } 136 | 137 | buf = ngx_http_stream_server_traffic_status_display_prometheus_set_server(r, buf, node->left); 138 | buf = ngx_http_stream_server_traffic_status_display_prometheus_set_server(r, buf, node->right); 139 | } 140 | 141 | return buf; 142 | } 143 | 144 | 145 | u_char * 146 | ngx_http_stream_server_traffic_status_display_prometheus_set_filter_node( 147 | ngx_http_request_t *r, u_char *buf, 148 | ngx_http_stream_server_traffic_status_node_t *stsn) 149 | { 150 | ngx_str_t key, filter, filter_name; 151 | ngx_uint_t i, n; 152 | ngx_http_stream_server_traffic_status_loc_conf_t *stscf; 153 | ngx_http_stream_server_traffic_status_node_histogram_bucket_t *b; 154 | 155 | stscf = ngx_http_get_module_loc_conf(r, ngx_http_stream_server_traffic_status_module); 156 | 157 | key.data = stsn->data; 158 | key.len = stsn->len; 159 | 160 | filter = filter_name = key; 161 | 162 | (void) ngx_http_stream_server_traffic_status_node_position_key(&filter, 1); 163 | (void) ngx_http_stream_server_traffic_status_node_position_key(&filter_name, 2); 164 | 165 | buf = ngx_sprintf(buf, NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_PROMETHEUS_FMT_FILTER, 166 | &filter, &filter_name, stsn->stat_in_bytes, 167 | &filter, &filter_name, stsn->stat_out_bytes, 168 | &filter, &filter_name, stsn->stat_1xx_counter, 169 | &filter, &filter_name, stsn->stat_2xx_counter, 170 | &filter, &filter_name, stsn->stat_3xx_counter, 171 | &filter, &filter_name, stsn->stat_4xx_counter, 172 | &filter, &filter_name, stsn->stat_5xx_counter, 173 | &filter, &filter_name, stsn->stat_connect_counter, 174 | &filter, &filter_name, (double) stsn->stat_session_time_counter / 1000, 175 | &filter, &filter_name, 176 | (double) ngx_http_stream_server_traffic_status_node_time_queue_average( 177 | &stsn->stat_session_times, stscf->average_method, 178 | stscf->average_period) / 1000); 179 | 180 | /* histogram */ 181 | b = &stsn->stat_session_buckets; 182 | 183 | n = b->len; 184 | 185 | if (n > 0) { 186 | 187 | /* histogram:bucket */ 188 | for (i = 0; i < n; i++) { 189 | buf = ngx_sprintf(buf, 190 | NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_PROMETHEUS_FMT_FILTER_HISTOGRAM_BUCKET, 191 | &filter, &filter_name, (double) b->buckets[i].msec / 1000, 192 | b->buckets[i].counter); 193 | } 194 | 195 | buf = ngx_sprintf(buf, 196 | NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_PROMETHEUS_FMT_FILTER_HISTOGRAM_BUCKET_E, 197 | &filter, &filter_name, stsn->stat_connect_counter); 198 | 199 | /* histogram:sum */ 200 | buf = ngx_sprintf(buf, 201 | NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_PROMETHEUS_FMT_FILTER_HISTOGRAM_SUM, 202 | &filter, &filter_name, (double) stsn->stat_session_time_counter / 1000); 203 | 204 | /* histogram:count */ 205 | buf = ngx_sprintf(buf, 206 | NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_PROMETHEUS_FMT_FILTER_HISTOGRAM_COUNT, 207 | &filter, &filter_name, stsn->stat_connect_counter); 208 | } 209 | 210 | return buf; 211 | } 212 | 213 | 214 | u_char * 215 | ngx_http_stream_server_traffic_status_display_prometheus_set_filter( 216 | ngx_http_request_t *r, u_char *buf, ngx_rbtree_node_t *node) 217 | { 218 | ngx_http_stream_server_traffic_status_ctx_t *ctx; 219 | ngx_http_stream_server_traffic_status_node_t *stsn; 220 | 221 | ctx = ngx_http_get_module_main_conf(r, ngx_http_stream_server_traffic_status_module); 222 | 223 | if (node != ctx->rbtree->sentinel) { 224 | stsn = (ngx_http_stream_server_traffic_status_node_t *) &node->color; 225 | 226 | if (stsn->stat_upstream.type == NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_UPSTREAM_FG) { 227 | buf = ngx_http_stream_server_traffic_status_display_prometheus_set_filter_node(r, buf, stsn); 228 | } 229 | 230 | buf = ngx_http_stream_server_traffic_status_display_prometheus_set_filter(r, buf, node->left); 231 | buf = ngx_http_stream_server_traffic_status_display_prometheus_set_filter(r, buf, node->right); 232 | } 233 | 234 | return buf; 235 | } 236 | 237 | 238 | u_char * 239 | ngx_http_stream_server_traffic_status_display_prometheus_set_upstream_node( 240 | ngx_http_request_t *r, u_char *buf, 241 | ngx_http_stream_server_traffic_status_node_t *stsn) 242 | { 243 | ngx_str_t target, upstream, upstream_server; 244 | ngx_uint_t i, n, len; 245 | ngx_atomic_t time_counter; 246 | ngx_http_stream_server_traffic_status_loc_conf_t *stscf; 247 | ngx_http_stream_server_traffic_status_node_histogram_bucket_t *b; 248 | 249 | stscf = ngx_http_get_module_loc_conf(r, ngx_http_stream_server_traffic_status_module); 250 | 251 | upstream_server.data = stsn->data; 252 | upstream_server.len = stsn->len; 253 | 254 | upstream = upstream_server; 255 | 256 | if (stsn->stat_upstream.type == NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_UPSTREAM_UG) { 257 | (void) ngx_http_stream_server_traffic_status_node_position_key(&upstream, 1); 258 | (void) ngx_http_stream_server_traffic_status_node_position_key(&upstream_server, 2); 259 | 260 | } else if (stsn->stat_upstream.type == NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_UPSTREAM_UA) { 261 | ngx_str_set(&upstream, "::nogroups"); 262 | (void) ngx_http_stream_server_traffic_status_node_position_key(&upstream_server, 1); 263 | } 264 | 265 | buf = ngx_sprintf(buf, NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_PROMETHEUS_FMT_UPSTREAM, 266 | &upstream, &upstream_server, stsn->stat_in_bytes, 267 | &upstream, &upstream_server, stsn->stat_out_bytes, 268 | &upstream, &upstream_server, stsn->stat_1xx_counter, 269 | &upstream, &upstream_server, stsn->stat_2xx_counter, 270 | &upstream, &upstream_server, stsn->stat_3xx_counter, 271 | &upstream, &upstream_server, stsn->stat_4xx_counter, 272 | &upstream, &upstream_server, stsn->stat_5xx_counter, 273 | &upstream, &upstream_server, stsn->stat_connect_counter, 274 | &upstream, &upstream_server, (double) stsn->stat_session_time_counter / 1000, 275 | &upstream, &upstream_server, 276 | (double) ngx_http_stream_server_traffic_status_node_time_queue_average( 277 | &stsn->stat_session_times, stscf->average_method, 278 | stscf->average_period) / 1000, 279 | &upstream, &upstream_server, (double) stsn->stat_upstream.connect_time_counter / 1000, 280 | &upstream, &upstream_server, 281 | (double) ngx_http_stream_server_traffic_status_node_time_queue_average( 282 | &stsn->stat_upstream.connect_times, stscf->average_method, 283 | stscf->average_period) / 1000, 284 | &upstream, &upstream_server, (double) stsn->stat_upstream.first_byte_time_counter / 1000, 285 | &upstream, &upstream_server, 286 | (double) ngx_http_stream_server_traffic_status_node_time_queue_average( 287 | &stsn->stat_upstream.first_byte_times, stscf->average_method, 288 | stscf->average_period) / 1000, 289 | &upstream, &upstream_server, (double) stsn->stat_upstream.session_time_counter / 1000, 290 | &upstream, &upstream_server, 291 | (double) ngx_http_stream_server_traffic_status_node_time_queue_average( 292 | &stsn->stat_upstream.session_times, stscf->average_method, 293 | stscf->average_period) / 1000); 294 | 295 | /* histogram */ 296 | len = 4; 297 | 298 | while (len--) { 299 | if (len == 3) { 300 | b = &stsn->stat_session_buckets; 301 | time_counter = stsn->stat_session_time_counter; 302 | ngx_str_set(&target, "session"); 303 | 304 | } else if (len == 2) { 305 | b = &stsn->stat_upstream.connect_buckets; 306 | time_counter = stsn->stat_upstream.connect_time_counter; 307 | ngx_str_set(&target, "response_connect"); 308 | 309 | } else if (len == 1) { 310 | b = &stsn->stat_upstream.first_byte_buckets; 311 | time_counter = stsn->stat_upstream.first_byte_time_counter; 312 | ngx_str_set(&target, "response_firstbyte"); 313 | 314 | } else { 315 | b = &stsn->stat_upstream.session_buckets; 316 | time_counter = stsn->stat_upstream.session_time_counter; 317 | ngx_str_set(&target, "response_session"); 318 | } 319 | 320 | n = b->len; 321 | 322 | if (n > 0) { 323 | /* histogram:bucket */ 324 | for (i = 0; i < n; i++) { 325 | buf = ngx_sprintf(buf, 326 | NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_PROMETHEUS_FMT_UPSTREAM_HISTOGRAM_BUCKET, 327 | &target, &upstream, &upstream_server, (double) b->buckets[i].msec / 1000, 328 | b->buckets[i].counter); 329 | } 330 | 331 | buf = ngx_sprintf(buf, 332 | NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_PROMETHEUS_FMT_UPSTREAM_HISTOGRAM_BUCKET_E, 333 | &target, &upstream, &upstream_server, stsn->stat_connect_counter); 334 | 335 | /* histogram:sum */ 336 | buf = ngx_sprintf(buf, 337 | NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_PROMETHEUS_FMT_UPSTREAM_HISTOGRAM_SUM, 338 | &target, &upstream, &upstream_server, (double) time_counter / 1000); 339 | 340 | /* histogram:count */ 341 | buf = ngx_sprintf(buf, 342 | NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_PROMETHEUS_FMT_UPSTREAM_HISTOGRAM_COUNT, 343 | &target, &upstream, &upstream_server, stsn->stat_connect_counter); 344 | } 345 | 346 | } 347 | 348 | return buf; 349 | } 350 | 351 | 352 | u_char * 353 | ngx_http_stream_server_traffic_status_display_prometheus_set_upstream( 354 | ngx_http_request_t *r, u_char *buf, ngx_rbtree_node_t *node) 355 | { 356 | ngx_http_stream_server_traffic_status_ctx_t *ctx; 357 | ngx_http_stream_server_traffic_status_node_t *stsn; 358 | 359 | ctx = ngx_http_get_module_main_conf(r, ngx_http_stream_server_traffic_status_module); 360 | 361 | if (node != ctx->rbtree->sentinel) { 362 | stsn = (ngx_http_stream_server_traffic_status_node_t *) &node->color; 363 | 364 | if (stsn->stat_upstream.type == NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_UPSTREAM_UG 365 | || stsn->stat_upstream.type == NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_UPSTREAM_UA) 366 | { 367 | buf = ngx_http_stream_server_traffic_status_display_prometheus_set_upstream_node(r, buf, stsn); 368 | } 369 | 370 | buf = ngx_http_stream_server_traffic_status_display_prometheus_set_upstream(r, buf, node->left); 371 | buf = ngx_http_stream_server_traffic_status_display_prometheus_set_upstream(r, buf, node->right); 372 | } 373 | 374 | return buf; 375 | } 376 | 377 | 378 | u_char * 379 | ngx_http_stream_server_traffic_status_display_prometheus_set( 380 | ngx_http_request_t *r, u_char *buf) 381 | { 382 | u_char *o, *s; 383 | ngx_rbtree_node_t *node; 384 | ngx_http_stream_server_traffic_status_ctx_t *ctx; 385 | 386 | ctx = ngx_http_get_module_main_conf(r, ngx_http_stream_server_traffic_status_module); 387 | 388 | node = ctx->rbtree->root; 389 | 390 | /* main & connections */ 391 | buf = ngx_http_stream_server_traffic_status_display_prometheus_set_main(r, buf); 392 | 393 | /* serverZones */ 394 | o = buf; 395 | 396 | buf = ngx_sprintf(buf, NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_PROMETHEUS_FMT_SERVER_S); 397 | 398 | s = buf; 399 | 400 | buf = ngx_http_stream_server_traffic_status_display_prometheus_set_server(r, buf, node); 401 | 402 | if (s == buf) { 403 | buf = o; 404 | } 405 | 406 | /* filterZones */ 407 | o = buf; 408 | 409 | buf = ngx_sprintf(buf, NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_PROMETHEUS_FMT_FILTER_S); 410 | 411 | s = buf; 412 | 413 | buf = ngx_http_stream_server_traffic_status_display_prometheus_set_filter(r, buf, node); 414 | 415 | if (s == buf) { 416 | buf = o; 417 | } 418 | 419 | /* upstreamZones */ 420 | o = buf; 421 | 422 | buf = ngx_sprintf(buf, NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_PROMETHEUS_FMT_UPSTREAM_S); 423 | 424 | s = buf; 425 | 426 | buf = ngx_http_stream_server_traffic_status_display_prometheus_set_upstream(r, buf, node); 427 | 428 | if (s == buf) { 429 | buf = o; 430 | } 431 | 432 | return buf; 433 | } 434 | 435 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ 436 | -------------------------------------------------------------------------------- /src/ngx_http_stream_server_traffic_status_display_prometheus.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) YoungJoo Kim (vozlt) 4 | */ 5 | 6 | 7 | #ifndef _NGX_HTTP_STREAM_STS_DISPLAY_PROMETHEUS_H_INCLUDED_ 8 | #define _NGX_HTTP_STREAM_STS_DISPLAY_PROMETHEUS_H_INCLUDED_ 9 | 10 | 11 | #define NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_PROMETHEUS_FMT_MAIN \ 12 | "# HELP nginx_sts_info Nginx info\n" \ 13 | "# TYPE nginx_sts_info gauge\n" \ 14 | "nginx_sts_info{hostname=\"%V\",version=\"%s\"} 1\n" \ 15 | "# HELP nginx_sts_start_time_seconds Nginx start time\n" \ 16 | "# TYPE nginx_sts_start_time_seconds gauge\n" \ 17 | "nginx_sts_start_time_seconds %.3f\n" \ 18 | "# HELP nginx_sts_main_connections Nginx connections\n" \ 19 | "# TYPE nginx_sts_main_connections gauge\n" \ 20 | "nginx_sts_main_connections{status=\"accepted\"} %uA\n" \ 21 | "nginx_sts_main_connections{status=\"active\"} %uA\n" \ 22 | "nginx_sts_main_connections{status=\"handled\"} %uA\n" \ 23 | "nginx_sts_main_connections{status=\"reading\"} %uA\n" \ 24 | "nginx_sts_main_connections{status=\"requests\"} %uA\n" \ 25 | "nginx_sts_main_connections{status=\"waiting\"} %uA\n" \ 26 | "nginx_sts_main_connections{status=\"writing\"} %uA\n" \ 27 | "# HELP nginx_sts_main_shm_usage_bytes Shared memory [%V] info\n" \ 28 | "# TYPE nginx_sts_main_shm_usage_bytes gauge\n" \ 29 | "nginx_sts_main_shm_usage_bytes{shared=\"max_size\"} %ui\n" \ 30 | "nginx_sts_main_shm_usage_bytes{shared=\"used_size\"} %ui\n" \ 31 | "nginx_sts_main_shm_usage_bytes{shared=\"used_node\"} %ui\n" 32 | 33 | #define NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_PROMETHEUS_FMT_SERVER_S \ 34 | "# HELP nginx_sts_server_bytes_total The request/response bytes\n" \ 35 | "# TYPE nginx_sts_server_bytes_total counter\n" \ 36 | "# HELP nginx_sts_server_connects_total The connects counter\n" \ 37 | "# TYPE nginx_sts_server_connects_total counter\n" \ 38 | "# HELP nginx_sts_server_session_seconds_total The session duration " \ 39 | "time\n" \ 40 | "# TYPE nginx_sts_server_session_seconds_total counter\n" \ 41 | "# HELP nginx_sts_server_session_seconds The average of session duration " \ 42 | "time in seconds\n" \ 43 | "# TYPE nginx_sts_server_session_seconds gauge\n" \ 44 | "# HELP nginx_sts_server_session_duration_seconds The histogram of " \ 45 | "session duration in seconds\n" \ 46 | "# TYPE nginx_sts_server_session_duration_seconds histogram\n" 47 | 48 | #define NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_PROMETHEUS_FMT_SERVER \ 49 | "nginx_sts_server_bytes_total{listen=\"%V\",port=\"%ui\"," \ 50 | "protocol=\"%V\",direction=\"in\"} %uA\n" \ 51 | "nginx_sts_server_bytes_total{listen=\"%V\",port=\"%ui\"," \ 52 | "protocol=\"%V\",direction=\"out\"} %uA\n" \ 53 | "nginx_sts_server_connects_total{listen=\"%V\",port=\"%ui\"," \ 54 | "protocol=\"%V\",code=\"1xx\"} %uA\n" \ 55 | "nginx_sts_server_connects_total{listen=\"%V\",port=\"%ui\"," \ 56 | "protocol=\"%V\",code=\"2xx\"} %uA\n" \ 57 | "nginx_sts_server_connects_total{listen=\"%V\",port=\"%ui\"," \ 58 | "protocol=\"%V\",code=\"3xx\"} %uA\n" \ 59 | "nginx_sts_server_connects_total{listen=\"%V\",port=\"%ui\"," \ 60 | "protocol=\"%V\",code=\"4xx\"} %uA\n" \ 61 | "nginx_sts_server_connects_total{listen=\"%V\",port=\"%ui\"," \ 62 | "protocol=\"%V\",code=\"5xx\"} %uA\n" \ 63 | "nginx_sts_server_connects_total{listen=\"%V\",port=\"%ui\"," \ 64 | "protocol=\"%V\",code=\"total\"} %uA\n" \ 65 | "nginx_sts_server_session_seconds_total{listen=\"%V\",port=\"%ui\"," \ 66 | "protocol=\"%V\"} %.3f\n" \ 67 | "nginx_sts_server_session_seconds{listen=\"%V\",port=\"%ui\"," \ 68 | "protocol=\"%V\"} %.3f\n" 69 | 70 | #define NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_PROMETHEUS_FMT_SERVER_HISTOGRAM_BUCKET \ 71 | "nginx_sts_server_session_duration_seconds_bucket{listen=\"%V\",port=\"%ui\"" \ 72 | ",protocol=\"%V\",le=\"%.3f\"} %uA\n" 73 | 74 | #define NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_PROMETHEUS_FMT_SERVER_HISTOGRAM_BUCKET_E \ 75 | "nginx_sts_server_session_duration_seconds_bucket{listen=\"%V\",port=\"%ui\"," \ 76 | "protocol=\"%V\",le=\"+Inf\"} %uA\n" 77 | 78 | #define NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_PROMETHEUS_FMT_SERVER_HISTOGRAM_SUM \ 79 | "nginx_sts_server_session_duration_seconds_sum{listen=\"%V\",port=\"%ui\"," \ 80 | "protocol=\"%V\"} %.3f\n" 81 | 82 | #define NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_PROMETHEUS_FMT_SERVER_HISTOGRAM_COUNT \ 83 | "nginx_sts_server_session_duration_seconds_count{listen=\"%V\",port=\"%ui\"," \ 84 | "protocol=\"%V\"} %uA\n" 85 | 86 | #define NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_PROMETHEUS_FMT_FILTER_S \ 87 | "# HELP nginx_sts_filter_bytes_total The request/response bytes\n" \ 88 | "# TYPE nginx_sts_filter_bytes_total counter\n" \ 89 | "# HELP nginx_sts_filter_connects_total The connects counter\n" \ 90 | "# TYPE nginx_sts_filter_connects_total counter\n" \ 91 | "# HELP nginx_sts_filter_session_seconds_total The session duration time " \ 92 | "in seconds\n" \ 93 | "# TYPE nginx_sts_filter_session_seconds_total counter\n" \ 94 | "# HELP nginx_sts_filter_session_seconds The average of session duration " \ 95 | "time in seconds\n" \ 96 | "# TYPE nginx_sts_filter_session_seconds gauge\n" \ 97 | "# HELP nginx_sts_filter_session_duration_seconds The histogram of " \ 98 | "session duration time in seconds\n" \ 99 | "# TYPE nginx_sts_filter_session_duration_seconds histogram\n" 100 | 101 | #define NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_PROMETHEUS_FMT_FILTER \ 102 | "nginx_sts_filter_bytes_total{filter=\"%V\",filter_name=\"%V\"," \ 103 | "direction=\"in\"} %uA\n" \ 104 | "nginx_sts_filter_bytes_total{filter=\"%V\",filter_name=\"%V\"," \ 105 | "direction=\"out\"} %uA\n" \ 106 | "nginx_sts_filter_connects_total{filter=\"%V\",filter_name=\"%V\"," \ 107 | "direction=\"1xx\"} %uA\n" \ 108 | "nginx_sts_filter_connects_total{filter=\"%V\",filter_name=\"%V\"," \ 109 | "direction=\"2xx\"} %uA\n" \ 110 | "nginx_sts_filter_connects_total{filter=\"%V\",filter_name=\"%V\"," \ 111 | "direction=\"3xx\"} %uA\n" \ 112 | "nginx_sts_filter_connects_total{filter=\"%V\",filter_name=\"%V\"," \ 113 | "direction=\"4xx\"} %uA\n" \ 114 | "nginx_sts_filter_connects_total{filter=\"%V\",filter_name=\"%V\"," \ 115 | "direction=\"5xx\"} %uA\n" \ 116 | "nginx_sts_filter_connects_total{filter=\"%V\",filter_name=\"%V\"," \ 117 | "direction=\"total\"} %uA\n" \ 118 | "nginx_sts_filter_session_seconds_total{filter=\"%V\"," \ 119 | "filter_name=\"%V\"} %.3f\n" \ 120 | "nginx_sts_filter_session_seconds{filter=\"%V\",filter_name=\"%V\"} %.3f\n" 121 | 122 | #define NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_PROMETHEUS_FMT_FILTER_HISTOGRAM_BUCKET \ 123 | "nginx_sts_filter_session_duration_seconds_bucket{filter=\"%V\"," \ 124 | "filter_name=\"%V\",le=\"%.3f\"} %uA\n" 125 | 126 | #define NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_PROMETHEUS_FMT_FILTER_HISTOGRAM_BUCKET_E \ 127 | "nginx_sts_filter_session_duration_seconds_bucket{filter=\"%V\"," \ 128 | "filter_name=\"%V\",le=\"+Inf\"} %uA\n" 129 | 130 | #define NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_PROMETHEUS_FMT_FILTER_HISTOGRAM_SUM \ 131 | "nginx_sts_filter_session_duration_seconds_sum{filter=\"%V\"," \ 132 | "filter_name=\"%V\"} %.3f\n" 133 | 134 | #define NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_PROMETHEUS_FMT_FILTER_HISTOGRAM_COUNT \ 135 | "nginx_sts_filter_session_duration_seconds_count{filter=\"%V\"," \ 136 | "filter_name=\"%V\"} %uA\n" 137 | 138 | #define NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_PROMETHEUS_FMT_UPSTREAM_S \ 139 | "# HELP nginx_sts_upstream_bytes_total The request/response bytes\n" \ 140 | "# TYPE nginx_sts_upstream_bytes_total counter\n" \ 141 | "# HELP nginx_sts_upstream_connects_total The upstream connects counter\n" \ 142 | "# TYPE nginx_sts_upstream_connects_total counter\n" \ 143 | "# HELP nginx_sts_upstream_session_seconds_total The session duration " \ 144 | "time in seconds\n" \ 145 | "# TYPE nginx_sts_upstream_session_seconds_total counter\n" \ 146 | "# HELP nginx_sts_upstream_session_seconds The average of session " \ 147 | "duration in seconds\n" \ 148 | "# TYPE nginx_sts_upstream_session_seconds gauge\n" \ 149 | "# HELP nginx_sts_upstream_response_connect_seconds_total The time to " \ 150 | "connect to the upstream server\n" \ 151 | "# TYPE nginx_sts_upstream_response_connect_seconds_total counter\n" \ 152 | "# HELP nginx_sts_upstream_response_connect_seconds The average of time " \ 153 | "to connect to the upstream server\n" \ 154 | "# TYPE nginx_sts_upstream_response_connect_seconds gauge\n" \ 155 | "# HELP nginx_sts_upstream_response_firstbyte_seconds_total The time to " \ 156 | "receive the first byte of data\n" \ 157 | "# TYPE nginx_sts_upstream_response_firstbyte_seconds_total counter\n" \ 158 | "# HELP nginx_sts_upstream_response_firstbyte_seconds The average of " \ 159 | "time to receive the first byte of data \n" \ 160 | "# TYPE nginx_sts_upstream_response_firstbyte_seconds gauge\n" \ 161 | "# HELP nginx_sts_upstream_response_session_seconds_total The session " \ 162 | "duration time to the upstream server\n" \ 163 | "# TYPE nginx_sts_upstream_response_session_seconds_total counter\n" \ 164 | "# HELP nginx_sts_upstream_response_session_seconds The average of " \ 165 | "session duration time to the upstream server\n" \ 166 | "# TYPE nginx_sts_upstream_response_session_seconds gauge\n" \ 167 | "# HELP nginx_sts_upstream_session_duration_seconds The histogram of " \ 168 | "session duration time in seconds\n" \ 169 | "# TYPE nginx_sts_upstream_session_duration_seconds histogram\n" \ 170 | "# HELP nginx_sts_upstream_response_connect_duration_seconds The " \ 171 | " histogram of time to connect to the upstream server\n" \ 172 | "# TYPE nginx_sts_upstream_response_connect_duration_seconds histogram\n" \ 173 | "# HELP nginx_sts_upstream_response_firstbyte_duration_seconds The " \ 174 | "histogram of time to receive the first byte of data\n" \ 175 | "# TYPE nginx_sts_upstream_response_firstbyte_duration_seconds " \ 176 | "histogram\n" \ 177 | "# HELP nginx_sts_upstream_response_session_duration_seconds The " \ 178 | "histogram of session duration time to the upstream server\n" \ 179 | "# TYPE nginx_sts_upstream_response_session_duration_seconds histogram\n" 180 | 181 | #define NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_PROMETHEUS_FMT_UPSTREAM \ 182 | "nginx_sts_upstream_bytes_total{upstream=\"%V\",backend=\"%V\"," \ 183 | "direction=\"in\"} %uA\n" \ 184 | "nginx_sts_upstream_bytes_total{upstream=\"%V\",backend=\"%V\"," \ 185 | "direction=\"out\"} %uA\n" \ 186 | "nginx_sts_upstream_connects_total{upstream=\"%V\",backend=\"%V\"," \ 187 | "code=\"1xx\"} %uA\n" \ 188 | "nginx_sts_upstream_connects_total{upstream=\"%V\",backend=\"%V\"," \ 189 | "code=\"2xx\"} %uA\n" \ 190 | "nginx_sts_upstream_connects_total{upstream=\"%V\",backend=\"%V\"," \ 191 | "code=\"3xx\"} %uA\n" \ 192 | "nginx_sts_upstream_connects_total{upstream=\"%V\",backend=\"%V\"," \ 193 | "code=\"4xx\"} %uA\n" \ 194 | "nginx_sts_upstream_connects_total{upstream=\"%V\",backend=\"%V\"," \ 195 | "code=\"5xx\"} %uA\n" \ 196 | "nginx_sts_upstream_connects_total{upstream=\"%V\",backend=\"%V\"," \ 197 | "code=\"total\"} %uA\n" \ 198 | "nginx_sts_upstream_session_seconds_total{upstream=\"%V\"," \ 199 | "backend=\"%V\"} %.3f\n" \ 200 | "nginx_sts_upstream_session_seconds{upstream=\"%V\"," \ 201 | "backend=\"%V\"} %.3f\n" \ 202 | "nginx_sts_upstream_response_connect_seconds_total{upstream=\"%V\"," \ 203 | "backend=\"%V\"} %.3f\n" \ 204 | "nginx_sts_upstream_response_connect_seconds{upstream=\"%V\"," \ 205 | "backend=\"%V\"} %.3f\n" \ 206 | "nginx_sts_upstream_response_firstbyte_seconds_total{upstream=\"%V\"," \ 207 | "backend=\"%V\"} %.3f\n" \ 208 | "nginx_sts_upstream_response_firstbyte_seconds{upstream=\"%V\"," \ 209 | "backend=\"%V\"} %.3f\n" \ 210 | "nginx_sts_upstream_response_session_seconds_total{upstream=\"%V\"," \ 211 | "backend=\"%V\"} %.3f\n" \ 212 | "nginx_sts_upstream_response_session_seconds{upstream=\"%V\"," \ 213 | "backend=\"%V\"} %.3f\n" 214 | 215 | #define NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_PROMETHEUS_FMT_UPSTREAM_HISTOGRAM_BUCKET \ 216 | "nginx_sts_upstream_%V_duration_seconds_bucket{upstream=\"%V\"," \ 217 | "backend=\"%V\",le=\"%.3f\"} %uA\n" 218 | 219 | #define NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_PROMETHEUS_FMT_UPSTREAM_HISTOGRAM_BUCKET_E \ 220 | "nginx_sts_upstream_%V_duration_seconds_bucket{upstream=\"%V\"," \ 221 | "backend=\"%V\",le=\"+Inf\"} %uA\n" 222 | 223 | #define NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_PROMETHEUS_FMT_UPSTREAM_HISTOGRAM_SUM \ 224 | "nginx_sts_upstream_%V_duration_seconds_sum{upstream=\"%V\"," \ 225 | "backend=\"%V\"} %.3f\n" 226 | 227 | #define NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_PROMETHEUS_FMT_UPSTREAM_HISTOGRAM_COUNT \ 228 | "nginx_sts_upstream_%V_duration_seconds_count{upstream=\"%V\"," \ 229 | "backend=\"%V\"} %uA\n" 230 | 231 | 232 | u_char *ngx_http_stream_server_traffic_status_display_prometheus_set_main( 233 | ngx_http_request_t *r, u_char *buf); 234 | u_char *ngx_http_stream_server_traffic_status_display_prometheus_set_server_node( 235 | ngx_http_request_t *r, u_char *buf, 236 | ngx_http_stream_server_traffic_status_node_t *stsn); 237 | u_char *ngx_http_stream_server_traffic_status_display_prometheus_set_server( 238 | ngx_http_request_t *r, u_char *buf, 239 | ngx_rbtree_node_t *node); 240 | u_char *ngx_http_stream_server_traffic_status_display_prometheus_set_filter_node( 241 | ngx_http_request_t *r, u_char *buf, 242 | ngx_http_stream_server_traffic_status_node_t *stsn); 243 | u_char *ngx_http_stream_server_traffic_status_display_prometheus_set_filter( 244 | ngx_http_request_t *r, u_char *buf, 245 | ngx_rbtree_node_t *node); 246 | u_char *ngx_http_stream_server_traffic_status_display_prometheus_set_upstream_node( 247 | ngx_http_request_t *r, u_char *buf, 248 | ngx_http_stream_server_traffic_status_node_t *stsn); 249 | u_char *ngx_http_stream_server_traffic_status_display_prometheus_set_upstream( 250 | ngx_http_request_t *r, u_char *buf, 251 | ngx_rbtree_node_t *node); 252 | 253 | u_char *ngx_http_stream_server_traffic_status_display_prometheus_set( 254 | ngx_http_request_t *r, u_char *buf); 255 | 256 | 257 | #endif /* _NGX_HTTP_STREAM_STS_DISPLAY_PROMETHEUS_H_INCLUDED_ */ 258 | 259 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ 260 | -------------------------------------------------------------------------------- /src/ngx_http_stream_server_traffic_status_filter.c: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) YoungJoo Kim (vozlt) 4 | */ 5 | 6 | 7 | #include 8 | 9 | #include "ngx_http_stream_server_traffic_status_module.h" 10 | #include "ngx_http_stream_server_traffic_status_filter.h" 11 | 12 | 13 | int ngx_libc_cdecl 14 | ngx_http_stream_server_traffic_status_filter_cmp_keys(const void *one, const void *two) 15 | { 16 | ngx_http_stream_server_traffic_status_filter_key_t *first = 17 | (ngx_http_stream_server_traffic_status_filter_key_t *) one; 18 | ngx_http_stream_server_traffic_status_filter_key_t *second = 19 | (ngx_http_stream_server_traffic_status_filter_key_t *) two; 20 | 21 | return (int) ngx_strcmp(first->key.data, second->key.data); 22 | } 23 | 24 | 25 | ngx_int_t 26 | ngx_http_stream_server_traffic_status_filter_get_keys(ngx_http_request_t *r, 27 | ngx_array_t **filter_keys, ngx_rbtree_node_t *node) 28 | { 29 | ngx_int_t rc; 30 | ngx_str_t key; 31 | ngx_http_stream_server_traffic_status_ctx_t *ctx; 32 | ngx_http_stream_server_traffic_status_node_t *stsn; 33 | ngx_http_stream_server_traffic_status_filter_key_t *keys; 34 | 35 | ctx = ngx_http_get_module_main_conf(r, ngx_http_stream_server_traffic_status_module); 36 | 37 | if (node != ctx->rbtree->sentinel) { 38 | stsn = (ngx_http_stream_server_traffic_status_node_t *) &node->color; 39 | 40 | if (stsn->stat_upstream.type == NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_UPSTREAM_FG) { 41 | key.data = stsn->data; 42 | key.len = stsn->len; 43 | 44 | rc = ngx_http_stream_server_traffic_status_node_position_key(&key, 1); 45 | if (rc != NGX_OK) { 46 | goto next; 47 | } 48 | 49 | if (*filter_keys == NULL) { 50 | *filter_keys = ngx_array_create(r->pool, 1, 51 | sizeof(ngx_http_stream_server_traffic_status_filter_key_t)); 52 | 53 | if (*filter_keys == NULL) { 54 | ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, 55 | "filter_get_keys::ngx_array_create() failed"); 56 | return NGX_ERROR; 57 | } 58 | } 59 | 60 | keys = ngx_array_push(*filter_keys); 61 | if (keys == NULL) { 62 | ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, 63 | "filter_get_keys::ngx_array_push() failed"); 64 | return NGX_ERROR; 65 | } 66 | 67 | keys->key.len = key.len; 68 | /* 1 byte for terminating '\0' for ngx_strcmp() */ 69 | keys->key.data = ngx_pcalloc(r->pool, key.len + 1); 70 | if (keys->key.data == NULL) { 71 | ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, 72 | "filter_get_keys::ngx_pcalloc() failed"); 73 | } 74 | 75 | ngx_memcpy(keys->key.data, key.data, key.len); 76 | } 77 | next: 78 | rc = ngx_http_stream_server_traffic_status_filter_get_keys(r, filter_keys, node->left); 79 | if (rc != NGX_OK) { 80 | return rc; 81 | } 82 | 83 | rc = ngx_http_stream_server_traffic_status_filter_get_keys(r, filter_keys, node->right); 84 | if (rc != NGX_OK) { 85 | return rc; 86 | } 87 | } 88 | 89 | return NGX_OK; 90 | } 91 | 92 | 93 | ngx_int_t 94 | ngx_http_stream_server_traffic_status_filter_get_nodes(ngx_http_request_t *r, 95 | ngx_array_t **filter_nodes, ngx_str_t *name, 96 | ngx_rbtree_node_t *node) 97 | { 98 | ngx_int_t rc; 99 | ngx_str_t key; 100 | ngx_http_stream_server_traffic_status_ctx_t *ctx; 101 | ngx_http_stream_server_traffic_status_node_t *stsn; 102 | ngx_http_stream_server_traffic_status_filter_node_t *nodes; 103 | 104 | ctx = ngx_http_get_module_main_conf(r, ngx_http_stream_server_traffic_status_module); 105 | 106 | if (node != ctx->rbtree->sentinel) { 107 | stsn = (ngx_http_stream_server_traffic_status_node_t *) &node->color; 108 | 109 | if (stsn->stat_upstream.type == NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_UPSTREAM_FG) { 110 | key.data = stsn->data; 111 | key.len = stsn->len; 112 | 113 | rc = ngx_http_stream_server_traffic_status_node_position_key(&key, 1); 114 | if (rc != NGX_OK) { 115 | goto next; 116 | } 117 | 118 | if (name->len != key.len) { 119 | goto next; 120 | } 121 | 122 | if (ngx_strncmp(name->data, key.data, key.len) != 0) { 123 | goto next; 124 | } 125 | 126 | if (*filter_nodes == NULL) { 127 | *filter_nodes = ngx_array_create(r->pool, 1, 128 | sizeof(ngx_http_stream_server_traffic_status_filter_node_t)); 129 | 130 | if (*filter_nodes == NULL) { 131 | ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, 132 | "filter_get_nodes::ngx_array_create() failed"); 133 | return NGX_ERROR; 134 | } 135 | } 136 | 137 | nodes = ngx_array_push(*filter_nodes); 138 | if (nodes == NULL) { 139 | ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, 140 | "filter_get_nodes::ngx_array_push() failed"); 141 | return NGX_ERROR; 142 | } 143 | 144 | nodes->node = stsn; 145 | } 146 | next: 147 | rc = ngx_http_stream_server_traffic_status_filter_get_nodes(r, filter_nodes, name, 148 | node->left); 149 | if (rc != NGX_OK) { 150 | return rc; 151 | } 152 | 153 | rc = ngx_http_stream_server_traffic_status_filter_get_nodes(r, filter_nodes, name, 154 | node->right); 155 | if (rc != NGX_OK) { 156 | return rc; 157 | } 158 | } 159 | 160 | return NGX_OK; 161 | } 162 | 163 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ 164 | -------------------------------------------------------------------------------- /src/ngx_http_stream_server_traffic_status_filter.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) YoungJoo Kim (vozlt) 4 | */ 5 | 6 | 7 | #ifndef _NGX_HTTP_STREAM_STS_FILTER_H_INCLUDED_ 8 | #define _NGX_HTTP_STREAM_STS_FILTER_H_INCLUDED_ 9 | 10 | 11 | typedef struct { 12 | ngx_http_complex_value_t filter_key; 13 | ngx_http_complex_value_t filter_name; 14 | } ngx_http_stream_server_traffic_status_filter_t; 15 | 16 | 17 | typedef struct { 18 | ngx_str_t key; 19 | } ngx_http_stream_server_traffic_status_filter_key_t; 20 | 21 | 22 | typedef struct { 23 | uint32_t hash; 24 | ngx_uint_t index; 25 | } ngx_http_stream_server_traffic_status_filter_uniq_t; 26 | 27 | 28 | typedef struct { 29 | ngx_http_stream_server_traffic_status_node_t *node; 30 | } ngx_http_stream_server_traffic_status_filter_node_t; 31 | 32 | 33 | int ngx_libc_cdecl ngx_http_stream_server_traffic_status_filter_cmp_keys( 34 | const void *one, const void *two); 35 | ngx_int_t ngx_http_stream_server_traffic_status_filter_get_keys( 36 | ngx_http_request_t *r, ngx_array_t **filter_keys, 37 | ngx_rbtree_node_t *node); 38 | ngx_int_t ngx_http_stream_server_traffic_status_filter_get_nodes( 39 | ngx_http_request_t *r, ngx_array_t **filter_nodes, 40 | ngx_str_t *name, ngx_rbtree_node_t *node); 41 | 42 | 43 | #endif /* _NGX_HTTP_STREAM_STS_FILTER_H_INCLUDED_ */ 44 | 45 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ 46 | -------------------------------------------------------------------------------- /src/ngx_http_stream_server_traffic_status_module.c: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) YoungJoo Kim (vozlt) 4 | */ 5 | 6 | 7 | #include 8 | 9 | #include "ngx_http_stream_server_traffic_status_module.h" 10 | #include "ngx_http_stream_server_traffic_status_display.h" 11 | 12 | 13 | static char *ngx_http_stream_server_traffic_status_zone(ngx_conf_t *cf, 14 | ngx_command_t *cmd, void *conf); 15 | static char *ngx_http_stream_server_traffic_status_average_method(ngx_conf_t *cf, 16 | ngx_command_t *cmd, void *conf); 17 | 18 | static void *ngx_http_stream_server_traffic_status_create_main_conf(ngx_conf_t *cf); 19 | static char *ngx_http_stream_server_traffic_status_init_main_conf(ngx_conf_t *cf, 20 | void *conf); 21 | static void *ngx_http_stream_server_traffic_status_create_loc_conf(ngx_conf_t *cf); 22 | static char *ngx_http_stream_server_traffic_status_merge_loc_conf(ngx_conf_t *cf, 23 | void *parent, void *child); 24 | 25 | 26 | static ngx_conf_enum_t ngx_http_stream_server_traffic_status_display_format[] = { 27 | { ngx_string("json"), NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_FORMAT_JSON }, 28 | { ngx_string("html"), NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_FORMAT_HTML }, 29 | { ngx_string("jsonp"), NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_FORMAT_JSONP }, 30 | { ngx_string("prometheus"), NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_FORMAT_PROMETHEUS }, 31 | { ngx_null_string, 0 } 32 | }; 33 | 34 | 35 | static ngx_conf_enum_t ngx_http_stream_server_traffic_status_average_method_post[] = { 36 | { ngx_string("AMM"), NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_AVERAGE_METHOD_AMM }, 37 | { ngx_string("WMA"), NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_AVERAGE_METHOD_WMA }, 38 | { ngx_null_string, 0 } 39 | }; 40 | 41 | 42 | static ngx_command_t ngx_http_stream_server_traffic_status_commands[] = { 43 | 44 | { ngx_string("stream_server_traffic_status"), 45 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, 46 | ngx_conf_set_flag_slot, 47 | NGX_HTTP_LOC_CONF_OFFSET, 48 | offsetof(ngx_http_stream_server_traffic_status_loc_conf_t, enable), 49 | NULL }, 50 | 51 | { ngx_string("stream_server_traffic_status_zone"), 52 | NGX_HTTP_MAIN_CONF|NGX_CONF_NOARGS|NGX_CONF_TAKE1, 53 | ngx_http_stream_server_traffic_status_zone, 54 | 0, 55 | 0, 56 | NULL }, 57 | 58 | { ngx_string("stream_server_traffic_status_display"), 59 | NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS|NGX_CONF_TAKE1, 60 | ngx_http_stream_server_traffic_status_display, 61 | 0, 62 | 0, 63 | NULL }, 64 | 65 | { ngx_string("stream_server_traffic_status_display_format"), 66 | NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 67 | ngx_conf_set_enum_slot, 68 | NGX_HTTP_LOC_CONF_OFFSET, 69 | offsetof(ngx_http_stream_server_traffic_status_loc_conf_t, format), 70 | &ngx_http_stream_server_traffic_status_display_format }, 71 | 72 | { ngx_string("stream_server_traffic_status_display_jsonp"), 73 | NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 74 | ngx_conf_set_str_slot, 75 | NGX_HTTP_LOC_CONF_OFFSET, 76 | offsetof(ngx_http_stream_server_traffic_status_loc_conf_t, jsonp), 77 | NULL }, 78 | 79 | { ngx_string("stream_server_traffic_status_average_method"), 80 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12, 81 | ngx_http_stream_server_traffic_status_average_method, 82 | NGX_HTTP_LOC_CONF_OFFSET, 83 | 0, 84 | NULL }, 85 | 86 | ngx_null_command 87 | }; 88 | 89 | 90 | static ngx_http_module_t ngx_http_stream_server_traffic_status_module_ctx = { 91 | NULL, /* preconfiguration */ 92 | NULL, /* postconfiguration */ 93 | 94 | ngx_http_stream_server_traffic_status_create_main_conf, /* create main configuration */ 95 | ngx_http_stream_server_traffic_status_init_main_conf, /* init main configuration */ 96 | 97 | NULL, /* create server configuration */ 98 | NULL, /* merge server configuration */ 99 | 100 | ngx_http_stream_server_traffic_status_create_loc_conf, /* create location configuration */ 101 | ngx_http_stream_server_traffic_status_merge_loc_conf, /* merge location configuration */ 102 | }; 103 | 104 | 105 | ngx_module_t ngx_http_stream_server_traffic_status_module = { 106 | NGX_MODULE_V1, 107 | &ngx_http_stream_server_traffic_status_module_ctx, /* module context */ 108 | ngx_http_stream_server_traffic_status_commands, /* module directives */ 109 | NGX_HTTP_MODULE, /* module type */ 110 | NULL, /* init master */ 111 | NULL, /* init module */ 112 | NULL, /* init process */ 113 | NULL, /* init thread */ 114 | NULL, /* exit thread */ 115 | NULL, /* exit process */ 116 | NULL, /* exit master */ 117 | NGX_MODULE_V1_PADDING 118 | }; 119 | 120 | 121 | static char * 122 | ngx_http_stream_server_traffic_status_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 123 | { 124 | ngx_str_t *value, name; 125 | ngx_uint_t i; 126 | ngx_http_stream_server_traffic_status_ctx_t *ctx; 127 | 128 | value = cf->args->elts; 129 | 130 | ctx = ngx_http_conf_get_module_main_conf(cf, ngx_http_stream_server_traffic_status_module); 131 | if (ctx == NULL) { 132 | return NGX_CONF_ERROR; 133 | } 134 | 135 | ctx->enable = 1; 136 | 137 | ngx_str_set(&name, NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_DEFAULT_SHM_NAME); 138 | 139 | for (i = 1; i < cf->args->nelts; i++) { 140 | if (ngx_strncmp(value[i].data, "shared:", 7) == 0) { 141 | name.data = value[i].data + 7; 142 | name.len = value[i].len - 7; 143 | continue; 144 | } 145 | 146 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 147 | "invalid parameter \"%V\"", &value[i]); 148 | return NGX_CONF_ERROR; 149 | } 150 | 151 | ctx->shm_name = name; 152 | 153 | return NGX_CONF_OK; 154 | } 155 | 156 | 157 | static char * 158 | ngx_http_stream_server_traffic_status_average_method(ngx_conf_t *cf, 159 | ngx_command_t *cmd, void *conf) 160 | { 161 | ngx_http_stream_server_traffic_status_loc_conf_t *stscf = conf; 162 | 163 | char *rv; 164 | ngx_int_t rc; 165 | ngx_str_t *value; 166 | 167 | value = cf->args->elts; 168 | 169 | cmd->offset = offsetof(ngx_http_stream_server_traffic_status_loc_conf_t, average_method); 170 | cmd->post = &ngx_http_stream_server_traffic_status_average_method_post; 171 | 172 | rv = ngx_conf_set_enum_slot(cf, cmd, conf); 173 | if (rv != NGX_CONF_OK) { 174 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%V\"", &value[1]); 175 | goto invalid; 176 | } 177 | 178 | /* second argument process */ 179 | if (cf->args->nelts == 3) { 180 | rc = ngx_parse_time(&value[2], 0); 181 | if (rc == NGX_ERROR) { 182 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%V\"", &value[2]); 183 | goto invalid; 184 | } 185 | stscf->average_period = (ngx_msec_t) rc; 186 | } 187 | 188 | return NGX_CONF_OK; 189 | 190 | invalid: 191 | 192 | return NGX_CONF_ERROR; 193 | } 194 | 195 | 196 | static void * 197 | ngx_http_stream_server_traffic_status_create_main_conf(ngx_conf_t *cf) 198 | { 199 | ngx_http_stream_server_traffic_status_ctx_t *ctx; 200 | 201 | ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_stream_server_traffic_status_ctx_t)); 202 | if (ctx == NULL) { 203 | return NULL; 204 | } 205 | 206 | ctx->enable = NGX_CONF_UNSET; 207 | 208 | return ctx; 209 | } 210 | 211 | 212 | static char * 213 | ngx_http_stream_server_traffic_status_init_main_conf(ngx_conf_t *cf, void *conf) 214 | { 215 | ngx_http_stream_server_traffic_status_ctx_t *ctx = conf; 216 | 217 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->log, 0, 218 | "http stream sts init main conf"); 219 | 220 | ngx_conf_init_value(ctx->enable, 0); 221 | 222 | return NGX_CONF_OK; 223 | } 224 | 225 | 226 | static void * 227 | ngx_http_stream_server_traffic_status_create_loc_conf(ngx_conf_t *cf) 228 | { 229 | ngx_http_stream_server_traffic_status_loc_conf_t *conf; 230 | 231 | conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_stream_server_traffic_status_loc_conf_t)); 232 | if (conf == NULL) { 233 | return NULL; 234 | } 235 | 236 | /* 237 | * set by ngx_pcalloc(): 238 | * 239 | * conf->shm_zone = { NULL, ... }; 240 | * conf->enable = 0; 241 | * conf->shm_name = { 0, NULL }; 242 | * conf->stats = { 0, ... }; 243 | * conf->start_msec = 0; 244 | * conf->format = 0; 245 | * conf->jsonp = { 1, NULL }; 246 | * conf->average_method = 0; 247 | * conf->average_period = 0; 248 | */ 249 | 250 | conf->start_msec = ngx_http_stream_server_traffic_status_current_msec(); 251 | conf->enable = NGX_CONF_UNSET; 252 | conf->shm_zone = NGX_CONF_UNSET_PTR; 253 | conf->format = NGX_CONF_UNSET; 254 | conf->average_method = NGX_CONF_UNSET; 255 | conf->average_period = NGX_CONF_UNSET_MSEC; 256 | 257 | conf->node_caches = ngx_pcalloc(cf->pool, sizeof(ngx_rbtree_node_t *) 258 | * (NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_UPSTREAM_FG + 1)); 259 | conf->node_caches[NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_UPSTREAM_NO] = NULL; 260 | conf->node_caches[NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_UPSTREAM_UA] = NULL; 261 | conf->node_caches[NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_UPSTREAM_UG] = NULL; 262 | conf->node_caches[NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_UPSTREAM_FG] = NULL; 263 | 264 | return conf; 265 | } 266 | 267 | 268 | static char * 269 | ngx_http_stream_server_traffic_status_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) 270 | { 271 | ngx_http_stream_server_traffic_status_loc_conf_t *prev = parent; 272 | ngx_http_stream_server_traffic_status_loc_conf_t *conf = child; 273 | 274 | ngx_http_stream_server_traffic_status_ctx_t *ctx; 275 | 276 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->log, 0, 277 | "http stream sts merge loc conf"); 278 | 279 | ctx = ngx_http_conf_get_module_main_conf(cf, ngx_http_stream_server_traffic_status_module); 280 | 281 | if (!ctx->enable) { 282 | return NGX_CONF_OK; 283 | } 284 | 285 | ngx_conf_merge_value(conf->enable, prev->enable, 1); 286 | ngx_conf_merge_ptr_value(conf->shm_zone, prev->shm_zone, NULL); 287 | ngx_conf_merge_value(conf->format, prev->format, 288 | NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_FORMAT_JSON); 289 | ngx_conf_merge_str_value(conf->jsonp, prev->jsonp, 290 | NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_DEFAULT_JSONP); 291 | ngx_conf_merge_value(conf->average_method, prev->average_method, 292 | NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_AVERAGE_METHOD_AMM); 293 | ngx_conf_merge_msec_value(conf->average_period, prev->average_period, 294 | NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_DEFAULT_AVG_PERIOD * 1000); 295 | 296 | conf->shm_name = ctx->shm_name; 297 | 298 | return NGX_CONF_OK; 299 | } 300 | 301 | 302 | ngx_msec_t 303 | ngx_http_stream_server_traffic_status_current_msec(void) 304 | { 305 | time_t sec; 306 | ngx_uint_t msec; 307 | struct timeval tv; 308 | 309 | ngx_gettimeofday(&tv); 310 | 311 | sec = tv.tv_sec; 312 | msec = tv.tv_usec / 1000; 313 | 314 | return (ngx_msec_t) sec * 1000 + msec; 315 | } 316 | 317 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ 318 | -------------------------------------------------------------------------------- /src/ngx_http_stream_server_traffic_status_module.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) YoungJoo Kim (vozlt) 4 | */ 5 | 6 | 7 | #ifndef _NGX_HTTP_STREAM_STS_MODULE_H_INCLUDED_ 8 | #define _NGX_HTTP_STREAM_STS_MODULE_H_INCLUDED_ 9 | 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include "ngx_http_stream_server_traffic_status_string.h" 18 | #include "ngx_http_stream_server_traffic_status_node.h" 19 | 20 | #define NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_UPSTREAM_NO 0 21 | #define NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_UPSTREAM_UA 1 22 | #define NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_UPSTREAM_UG 2 23 | #define NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_UPSTREAM_FG 3 24 | 25 | #define NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_UPSTREAMS \ 26 | (u_char *) "NO\0UA\0UG\0FG\0" 27 | 28 | #define NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_NODE_NONE 0 29 | #define NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_NODE_FIND 1 30 | 31 | #define NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_KEY_SEPARATOR (u_char) 0x1f 32 | 33 | #define NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_FORMAT_NONE 0 34 | #define NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_FORMAT_JSON 1 35 | #define NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_FORMAT_HTML 2 36 | #define NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_FORMAT_JSONP 3 37 | #define NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_FORMAT_PROMETHEUS 4 38 | 39 | #define NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_AVERAGE_METHOD_AMM 0 40 | #define NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_AVERAGE_METHOD_WMA 1 41 | 42 | #define NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_DEFAULT_SHM_NAME \ 43 | "stream_server_traffic_status" 44 | 45 | #define NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_DEFAULT_JSONP \ 46 | "ngx_http_stream_server_traffic_status_jsonp_callback" 47 | 48 | #define NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_DEFAULT_AVG_PERIOD 60 49 | 50 | #define ngx_http_stream_server_traffic_status_add_oc(o, c) { \ 51 | if (o->stat_connect_counter > c->stat_connect_counter) { \ 52 | c->stat_connect_counter_oc++; \ 53 | } \ 54 | if (o->stat_in_bytes > c->stat_in_bytes) { \ 55 | c->stat_in_bytes_oc++; \ 56 | } \ 57 | if (o->stat_out_bytes > c->stat_out_bytes) { \ 58 | c->stat_out_bytes_oc++; \ 59 | } \ 60 | if (o->stat_1xx_counter > c->stat_1xx_counter) { \ 61 | c->stat_1xx_counter_oc++; \ 62 | } \ 63 | if (o->stat_2xx_counter > c->stat_2xx_counter) { \ 64 | c->stat_2xx_counter_oc++; \ 65 | } \ 66 | if (o->stat_3xx_counter > c->stat_3xx_counter) { \ 67 | c->stat_3xx_counter_oc++; \ 68 | } \ 69 | if (o->stat_4xx_counter > c->stat_4xx_counter) { \ 70 | c->stat_4xx_counter_oc++; \ 71 | } \ 72 | if (o->stat_5xx_counter > c->stat_5xx_counter) { \ 73 | c->stat_5xx_counter_oc++; \ 74 | } \ 75 | if (o->stat_session_time_counter > c->stat_session_time_counter) { \ 76 | c->stat_session_time_counter_oc++; \ 77 | } \ 78 | } 79 | 80 | #define ngx_http_stream_server_traffic_status_group_to_string(n) (u_char *) ( \ 81 | (n > 3) \ 82 | ? NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_UPSTREAMS \ 83 | : NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_UPSTREAMS + 3 * n \ 84 | ) 85 | 86 | #define ngx_http_stream_server_traffic_status_max_integer \ 87 | (NGX_ATOMIC_T_LEN < 12) \ 88 | ? "4294967295" \ 89 | : "18446744073709551615" 90 | 91 | #define ngx_http_stream_server_traffic_status_boolean_to_string(b) \ 92 | (b) ? "true" : "false" 93 | 94 | #define ngx_http_stream_server_traffic_status_triangle(n) (unsigned) ( \ 95 | n * (n + 1) / 2 \ 96 | ) 97 | 98 | 99 | /* must be the same as ngx_stream_server_traffic_status_ctx_t */ 100 | typedef struct { 101 | ngx_rbtree_t *rbtree; 102 | 103 | /* array of ngx_http_stream_server_traffic_status_filter_t */ 104 | ngx_array_t *filter_keys; 105 | 106 | /* array of ngx_http_stream_server_traffic_status_limit_t */ 107 | ngx_array_t *limit_traffics; 108 | 109 | /* array of ngx_http_stream_server_traffic_status_limit_t */ 110 | ngx_array_t *limit_filter_traffics; 111 | 112 | ngx_flag_t enable; 113 | ngx_flag_t filter_check_duplicate; 114 | ngx_flag_t limit_check_duplicate; 115 | 116 | ngx_stream_upstream_main_conf_t *upstream; 117 | ngx_str_t shm_name; 118 | ssize_t shm_size; 119 | } ngx_http_stream_server_traffic_status_ctx_t; 120 | 121 | 122 | typedef struct { 123 | ngx_shm_zone_t *shm_zone; 124 | ngx_flag_t enable; 125 | 126 | ngx_str_t shm_name; 127 | ngx_http_stream_server_traffic_status_node_t stats; 128 | ngx_msec_t start_msec; 129 | ngx_flag_t format; 130 | ngx_str_t jsonp; 131 | 132 | ngx_flag_t average_method; 133 | ngx_msec_t average_period; 134 | 135 | ngx_rbtree_node_t **node_caches; 136 | } ngx_http_stream_server_traffic_status_loc_conf_t; 137 | 138 | 139 | ngx_msec_t ngx_http_stream_server_traffic_status_current_msec(void); 140 | 141 | extern ngx_module_t ngx_http_stream_server_traffic_status_module; 142 | 143 | 144 | #endif /* _NGX_HTTP_STREAM_STS_MODULE_H_INCLUDED_ */ 145 | 146 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ 147 | -------------------------------------------------------------------------------- /src/ngx_http_stream_server_traffic_status_node.c: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) YoungJoo Kim (vozlt) 4 | */ 5 | 6 | 7 | #include 8 | 9 | #include "ngx_http_stream_server_traffic_status_module.h" 10 | #include "ngx_http_stream_server_traffic_status_node.h" 11 | 12 | 13 | ngx_int_t 14 | ngx_http_stream_server_traffic_status_node_generate_key(ngx_pool_t *pool, 15 | ngx_str_t *buf, ngx_str_t *dst, unsigned type) 16 | { 17 | size_t len; 18 | u_char *p; 19 | 20 | len = ngx_strlen(ngx_http_stream_server_traffic_status_group_to_string(type)); 21 | 22 | buf->len = len + sizeof("@") - 1 + dst->len; 23 | buf->data = ngx_pcalloc(pool, buf->len); 24 | if (buf->data == NULL) { 25 | *buf = *dst; 26 | return NGX_ERROR; 27 | } 28 | 29 | p = buf->data; 30 | 31 | p = ngx_cpymem(p, ngx_http_stream_server_traffic_status_group_to_string(type), len); 32 | *p++ = NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_KEY_SEPARATOR; 33 | p = ngx_cpymem(p, dst->data, dst->len); 34 | 35 | return NGX_OK; 36 | } 37 | 38 | 39 | ngx_int_t 40 | ngx_http_stream_server_traffic_status_node_position_key(ngx_str_t *buf, size_t pos) 41 | { 42 | size_t n, c, len; 43 | u_char *p, *s; 44 | 45 | n = buf->len + 1; 46 | c = len = 0; 47 | p = s = buf->data; 48 | 49 | while (--n) { 50 | if (*p == NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_KEY_SEPARATOR) { 51 | if (pos == c) { 52 | break; 53 | } 54 | s = (p + 1); 55 | c++; 56 | } 57 | p++; 58 | len = (p - s); 59 | } 60 | 61 | if (pos > c || len == 0) { 62 | return NGX_ERROR; 63 | } 64 | 65 | buf->data = s; 66 | buf->len = len; 67 | 68 | return NGX_OK; 69 | } 70 | 71 | 72 | ngx_rbtree_node_t * 73 | ngx_http_stream_server_traffic_status_find_node(ngx_http_request_t *r, 74 | ngx_str_t *key, unsigned type, uint32_t key_hash) 75 | { 76 | uint32_t hash; 77 | ngx_rbtree_node_t *node; 78 | ngx_http_stream_server_traffic_status_ctx_t *ctx; 79 | ngx_http_stream_server_traffic_status_loc_conf_t *stscf; 80 | 81 | ctx = ngx_http_get_module_main_conf(r, ngx_http_stream_server_traffic_status_module); 82 | stscf = ngx_http_get_module_loc_conf(r, ngx_http_stream_server_traffic_status_module); 83 | 84 | hash = key_hash; 85 | 86 | if (hash == 0) { 87 | hash = ngx_crc32_short(key->data, key->len); 88 | } 89 | 90 | if (stscf->node_caches[type] != NULL) { 91 | if (stscf->node_caches[type]->key == hash) { 92 | node = stscf->node_caches[type]; 93 | goto found; 94 | } 95 | } 96 | 97 | node = ngx_http_stream_server_traffic_status_node_lookup(ctx->rbtree, key, hash); 98 | 99 | found: 100 | 101 | return node; 102 | } 103 | 104 | 105 | ngx_rbtree_node_t * 106 | ngx_http_stream_server_traffic_status_node_lookup(ngx_rbtree_t *rbtree, ngx_str_t *key, 107 | uint32_t hash) 108 | { 109 | ngx_int_t rc; 110 | ngx_rbtree_node_t *node, *sentinel; 111 | ngx_http_stream_server_traffic_status_node_t *stsn; 112 | 113 | node = rbtree->root; 114 | sentinel = rbtree->sentinel; 115 | 116 | while (node != sentinel) { 117 | 118 | if (hash < node->key) { 119 | node = node->left; 120 | continue; 121 | } 122 | 123 | if (hash > node->key) { 124 | node = node->right; 125 | continue; 126 | } 127 | 128 | /* hash == node->key */ 129 | 130 | stsn = (ngx_http_stream_server_traffic_status_node_t *) &node->color; 131 | 132 | rc = ngx_memn2cmp(key->data, stsn->data, key->len, (size_t) stsn->len); 133 | if (rc == 0) { 134 | return node; 135 | } 136 | 137 | node = (rc < 0) ? node->left : node->right; 138 | } 139 | 140 | return NULL; 141 | } 142 | 143 | 144 | void 145 | ngx_http_stream_server_traffic_status_node_zero(ngx_http_stream_server_traffic_status_node_t *stsn) 146 | { 147 | stsn->stat_connect_counter = 0; 148 | stsn->stat_in_bytes = 0; 149 | stsn->stat_out_bytes = 0; 150 | stsn->stat_1xx_counter = 0; 151 | stsn->stat_2xx_counter = 0; 152 | stsn->stat_3xx_counter = 0; 153 | stsn->stat_4xx_counter = 0; 154 | stsn->stat_5xx_counter = 0; 155 | 156 | stsn->stat_session_time_counter = 0; 157 | stsn->stat_session_time = 0; 158 | 159 | stsn->stat_connect_counter_oc = 0; 160 | stsn->stat_in_bytes_oc = 0; 161 | stsn->stat_out_bytes_oc = 0; 162 | stsn->stat_1xx_counter_oc = 0; 163 | stsn->stat_2xx_counter_oc = 0; 164 | stsn->stat_3xx_counter_oc = 0; 165 | stsn->stat_4xx_counter_oc = 0; 166 | stsn->stat_5xx_counter_oc = 0; 167 | stsn->stat_session_time_counter_oc = 0; 168 | stsn->stat_u_connect_time_counter_oc = 0; 169 | stsn->stat_u_first_byte_time_counter_oc = 0; 170 | stsn->stat_u_session_time_counter_oc = 0; 171 | } 172 | 173 | 174 | void 175 | ngx_http_stream_server_traffic_status_node_time_queue_zero( 176 | ngx_http_stream_server_traffic_status_node_time_queue_t *q) 177 | { 178 | ngx_memzero(q, sizeof(ngx_http_stream_server_traffic_status_node_time_queue_t)); 179 | } 180 | 181 | 182 | void 183 | ngx_http_stream_server_traffic_status_node_time_queue_init( 184 | ngx_http_stream_server_traffic_status_node_time_queue_t *q) 185 | { 186 | ngx_http_stream_server_traffic_status_node_time_queue_zero(q); 187 | q->rear = NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_DEFAULT_QUEUE_LEN - 1; 188 | q->len = NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_DEFAULT_QUEUE_LEN; 189 | } 190 | 191 | 192 | ngx_msec_t 193 | ngx_http_stream_server_traffic_status_node_time_queue_average( 194 | ngx_http_stream_server_traffic_status_node_time_queue_t *q, 195 | ngx_int_t method, ngx_msec_t period) 196 | { 197 | ngx_msec_t avg; 198 | 199 | if (method == NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_AVERAGE_METHOD_AMM) { 200 | avg = ngx_http_stream_server_traffic_status_node_time_queue_amm(q, period); 201 | } else { 202 | avg = ngx_http_stream_server_traffic_status_node_time_queue_wma(q, period); 203 | } 204 | 205 | return avg; 206 | } 207 | 208 | 209 | ngx_msec_t 210 | ngx_http_stream_server_traffic_status_node_time_queue_amm( 211 | ngx_http_stream_server_traffic_status_node_time_queue_t *q, 212 | ngx_msec_t period) 213 | { 214 | ngx_int_t c, i, j, k; 215 | ngx_msec_t x, current_msec; 216 | 217 | current_msec = ngx_http_stream_server_traffic_status_current_msec(); 218 | 219 | c = 0; 220 | x = period ? (current_msec - period) : 0; 221 | 222 | for (i = q->front, j = 1, k = 0; i != q->rear; i = (i + 1) % q->len, j++) { 223 | if (x < q->times[i].time) { 224 | k += (ngx_int_t) q->times[i].msec; 225 | c++; 226 | } 227 | } 228 | 229 | return (c == 0) ? (ngx_msec_t) 0 : (ngx_msec_t) (k / c); 230 | } 231 | 232 | 233 | ngx_msec_t 234 | ngx_http_stream_server_traffic_status_node_time_queue_wma( 235 | ngx_http_stream_server_traffic_status_node_time_queue_t *q, 236 | ngx_msec_t period) 237 | { 238 | ngx_int_t c, i, j, k; 239 | ngx_msec_t x, current_msec; 240 | 241 | current_msec = ngx_http_stream_server_traffic_status_current_msec(); 242 | 243 | c = 0; 244 | x = period ? (current_msec - period) : 0; 245 | 246 | for (i = q->front, j = 1, k = 0; i != q->rear; i = (i + 1) % q->len, j++) { 247 | if (x < q->times[i].time) { 248 | k += (ngx_int_t) q->times[i].msec * ++c; 249 | } 250 | } 251 | 252 | return (c == 0) ? (ngx_msec_t) 0 : (ngx_msec_t) 253 | (k / (ngx_int_t) ngx_http_stream_server_traffic_status_triangle(c)); 254 | } 255 | 256 | 257 | void 258 | ngx_http_stream_server_traffic_status_node_time_queue_merge( 259 | ngx_http_stream_server_traffic_status_node_time_queue_t *a, 260 | ngx_http_stream_server_traffic_status_node_time_queue_t *b, 261 | ngx_msec_t period) 262 | { 263 | ngx_int_t i, j, k, n, len; 264 | ngx_msec_t x, current_msec; 265 | ngx_http_stream_server_traffic_status_node_time_queue_t q; 266 | 267 | ngx_http_stream_server_traffic_status_node_time_queue_init(&q); 268 | current_msec = ngx_http_stream_server_traffic_status_current_msec(); 269 | x = period ? (current_msec - period) : 0; 270 | len = q.len; 271 | 272 | for (i = a->rear, j = b->rear, k = q.rear, n = 0; n < len -1; ++n) { 273 | if (a->times[(i + len - 1) % len].time > b->times[(j + len - 1) % len].time) { 274 | if (x >= a->times[(i + len - 1) % len].time) { 275 | break; 276 | } 277 | q.times[(k + len - 1) % len].time = a->times[(i + len - 1) % len].time; 278 | q.times[(k + len - 1) % len].msec = a->times[(i + len - 1) % len].msec; 279 | i = (i + len - 1) % len; 280 | 281 | } else { 282 | if (x >= b->times[(j + len - 1) % len].time) { 283 | break; 284 | } 285 | q.times[(k + len - 1) % len].time = b->times[(j + len - 1) % len].time; 286 | q.times[(k + len - 1) % len].msec = b->times[(j + len - 1) % len].msec; 287 | j = (j + len - 1) % len; 288 | } 289 | k = (k + len - 1) % len; 290 | } 291 | (void) ngx_cpymem(a, &q, sizeof(q)); 292 | } 293 | 294 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ 295 | -------------------------------------------------------------------------------- /src/ngx_http_stream_server_traffic_status_node.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) YoungJoo Kim (vozlt) 4 | */ 5 | 6 | 7 | #ifndef _NGX_HTTP_STREAM_STS_NODE_H_INCLUDED_ 8 | #define _NGX_HTTP_STREAM_STS_NODE_H_INCLUDED_ 9 | 10 | /* The node structs must be exactly the same as nginx-module-stream-sts. */ 11 | #define NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_DEFAULT_QUEUE_LEN 64 12 | #define NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_DEFAULT_BUCKET_LEN 32 13 | 14 | 15 | typedef struct { 16 | ngx_msec_t time; 17 | ngx_msec_int_t msec; 18 | } ngx_http_stream_server_traffic_status_node_time_t; 19 | 20 | 21 | typedef struct { 22 | ngx_http_stream_server_traffic_status_node_time_t times[NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_DEFAULT_QUEUE_LEN]; 23 | ngx_int_t front; 24 | ngx_int_t rear; 25 | ngx_int_t len; 26 | } ngx_http_stream_server_traffic_status_node_time_queue_t; 27 | 28 | 29 | typedef struct { 30 | ngx_msec_int_t msec; 31 | ngx_atomic_t counter; 32 | } ngx_http_stream_server_traffic_status_node_histogram_t; 33 | 34 | 35 | typedef struct { 36 | ngx_http_stream_server_traffic_status_node_histogram_t buckets[NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_DEFAULT_BUCKET_LEN]; 37 | ngx_int_t len; 38 | } ngx_http_stream_server_traffic_status_node_histogram_bucket_t; 39 | 40 | 41 | typedef struct { 42 | /* unsigned type:5 */ 43 | unsigned type; 44 | 45 | ngx_atomic_t connect_time_counter; 46 | ngx_msec_t connect_time; 47 | ngx_http_stream_server_traffic_status_node_time_queue_t connect_times; 48 | ngx_http_stream_server_traffic_status_node_histogram_bucket_t connect_buckets; 49 | 50 | ngx_atomic_t first_byte_time_counter; 51 | ngx_msec_t first_byte_time; 52 | ngx_http_stream_server_traffic_status_node_time_queue_t first_byte_times; 53 | ngx_http_stream_server_traffic_status_node_histogram_bucket_t first_byte_buckets; 54 | 55 | ngx_atomic_t session_time_counter; 56 | ngx_msec_t session_time; 57 | ngx_http_stream_server_traffic_status_node_time_queue_t session_times; 58 | ngx_http_stream_server_traffic_status_node_histogram_bucket_t session_buckets; 59 | } ngx_http_stream_server_traffic_status_node_upstream_t; 60 | 61 | 62 | typedef struct { 63 | u_char color; 64 | ngx_atomic_t stat_connect_counter; 65 | ngx_atomic_t stat_in_bytes; 66 | ngx_atomic_t stat_out_bytes; 67 | ngx_atomic_t stat_1xx_counter; 68 | ngx_atomic_t stat_2xx_counter; 69 | ngx_atomic_t stat_3xx_counter; 70 | ngx_atomic_t stat_4xx_counter; 71 | ngx_atomic_t stat_5xx_counter; 72 | 73 | ngx_atomic_t stat_session_time_counter; 74 | ngx_msec_t stat_session_time; 75 | ngx_http_stream_server_traffic_status_node_time_queue_t stat_session_times; 76 | ngx_http_stream_server_traffic_status_node_histogram_bucket_t stat_session_buckets; 77 | 78 | /* deals with the overflow of variables */ 79 | ngx_atomic_t stat_connect_counter_oc; 80 | ngx_atomic_t stat_in_bytes_oc; 81 | ngx_atomic_t stat_out_bytes_oc; 82 | ngx_atomic_t stat_1xx_counter_oc; 83 | ngx_atomic_t stat_2xx_counter_oc; 84 | ngx_atomic_t stat_3xx_counter_oc; 85 | ngx_atomic_t stat_4xx_counter_oc; 86 | ngx_atomic_t stat_5xx_counter_oc; 87 | ngx_atomic_t stat_session_time_counter_oc; 88 | ngx_atomic_t stat_u_connect_time_counter_oc; 89 | ngx_atomic_t stat_u_first_byte_time_counter_oc; 90 | ngx_atomic_t stat_u_session_time_counter_oc; 91 | 92 | ngx_http_stream_server_traffic_status_node_upstream_t stat_upstream; 93 | 94 | ngx_uint_t port; 95 | int protocol; 96 | u_short len; 97 | u_char data[1]; 98 | } ngx_http_stream_server_traffic_status_node_t; 99 | 100 | 101 | ngx_int_t ngx_http_stream_server_traffic_status_node_generate_key(ngx_pool_t *pool, 102 | ngx_str_t *buf, ngx_str_t *dst, unsigned type); 103 | ngx_int_t ngx_http_stream_server_traffic_status_node_position_key(ngx_str_t *buf, 104 | size_t pos); 105 | 106 | ngx_rbtree_node_t *ngx_http_stream_server_traffic_status_node_lookup( 107 | ngx_rbtree_t *rbtree, ngx_str_t *key, uint32_t hash); 108 | void ngx_http_stream_server_traffic_status_node_zero( 109 | ngx_http_stream_server_traffic_status_node_t *stsn); 110 | 111 | void ngx_http_stream_server_traffic_status_node_time_queue_zero( 112 | ngx_http_stream_server_traffic_status_node_time_queue_t *q); 113 | void ngx_http_stream_server_traffic_status_node_time_queue_init( 114 | ngx_http_stream_server_traffic_status_node_time_queue_t *q); 115 | 116 | ngx_msec_t ngx_http_stream_server_traffic_status_node_time_queue_average( 117 | ngx_http_stream_server_traffic_status_node_time_queue_t *q, 118 | ngx_int_t method, ngx_msec_t period); 119 | ngx_msec_t ngx_http_stream_server_traffic_status_node_time_queue_amm( 120 | ngx_http_stream_server_traffic_status_node_time_queue_t *q, 121 | ngx_msec_t period); 122 | ngx_msec_t ngx_http_stream_server_traffic_status_node_time_queue_wma( 123 | ngx_http_stream_server_traffic_status_node_time_queue_t *q, 124 | ngx_msec_t period); 125 | void ngx_http_stream_server_traffic_status_node_time_queue_merge( 126 | ngx_http_stream_server_traffic_status_node_time_queue_t *a, 127 | ngx_http_stream_server_traffic_status_node_time_queue_t *b, 128 | ngx_msec_t period); 129 | 130 | ngx_rbtree_node_t *ngx_http_stream_server_traffic_status_find_node(ngx_http_request_t *r, 131 | ngx_str_t *key, unsigned type, uint32_t key_hash); 132 | 133 | 134 | #endif /* _NGX_HTTP_STREAM_STS_NODE_H_INCLUDED_ */ 135 | 136 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ 137 | -------------------------------------------------------------------------------- /src/ngx_http_stream_server_traffic_status_shm.c: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) YoungJoo Kim (vozlt) 4 | */ 5 | 6 | 7 | #include 8 | 9 | #include "ngx_http_stream_server_traffic_status_module.h" 10 | #include "ngx_http_stream_server_traffic_status_shm.h" 11 | 12 | 13 | void 14 | ngx_http_stream_server_traffic_status_shm_info_node(ngx_http_request_t *r, 15 | ngx_http_stream_server_traffic_status_shm_info_t *shm_info, 16 | ngx_rbtree_node_t *node) 17 | { 18 | ngx_uint_t size; 19 | ngx_http_stream_server_traffic_status_ctx_t *ctx; 20 | ngx_http_stream_server_traffic_status_node_t *stsn; 21 | 22 | ctx = ngx_http_get_module_main_conf(r, ngx_http_stream_server_traffic_status_module); 23 | 24 | if (node != ctx->rbtree->sentinel) { 25 | stsn = (ngx_http_stream_server_traffic_status_node_t *) &node->color; 26 | 27 | size = offsetof(ngx_rbtree_node_t, color) 28 | + offsetof(ngx_http_stream_server_traffic_status_node_t, data) 29 | + stsn->len; 30 | 31 | shm_info->used_size += size; 32 | shm_info->used_node++; 33 | 34 | ngx_http_stream_server_traffic_status_shm_info_node(r, shm_info, node->left); 35 | ngx_http_stream_server_traffic_status_shm_info_node(r, shm_info, node->right); 36 | } 37 | } 38 | 39 | 40 | void 41 | ngx_http_stream_server_traffic_status_shm_info(ngx_http_request_t *r, 42 | ngx_http_stream_server_traffic_status_shm_info_t *shm_info) 43 | { 44 | ngx_http_stream_server_traffic_status_ctx_t *ctx; 45 | 46 | ctx = ngx_http_get_module_main_conf(r, ngx_http_stream_server_traffic_status_module); 47 | 48 | ngx_memzero(shm_info, sizeof(ngx_http_stream_server_traffic_status_shm_info_t)); 49 | 50 | shm_info->name = &ctx->shm_name; 51 | shm_info->max_size = ctx->shm_size; 52 | 53 | ngx_http_stream_server_traffic_status_shm_info_node(r, shm_info, ctx->rbtree->root); 54 | } 55 | 56 | 57 | ngx_int_t 58 | ngx_http_stream_server_traffic_status_shm_init(ngx_http_request_t *r) 59 | { 60 | ngx_shm_zone_t *shm_zone; 61 | ngx_http_stream_server_traffic_status_ctx_t *ctx, *sctx; 62 | ngx_http_stream_server_traffic_status_loc_conf_t *stscf; 63 | 64 | ctx = ngx_http_get_module_main_conf(r, ngx_http_stream_server_traffic_status_module); 65 | 66 | stscf = ngx_http_get_module_loc_conf(r, ngx_http_stream_server_traffic_status_module); 67 | 68 | shm_zone = ngx_http_stream_server_traffic_status_shm_find_zone(r, &ctx->shm_name); 69 | if (shm_zone == NULL) { 70 | return NGX_ERROR; 71 | } 72 | 73 | sctx = shm_zone->data; 74 | 75 | stscf->shm_zone = shm_zone; 76 | ctx->rbtree = sctx->rbtree; 77 | ctx->filter_keys = sctx->filter_keys; 78 | ctx->limit_traffics = sctx->limit_traffics; 79 | ctx->limit_filter_traffics = sctx->limit_filter_traffics; 80 | ctx->shm_size = sctx->shm_size; 81 | ctx->upstream = sctx->upstream; 82 | 83 | return NGX_OK; 84 | } 85 | 86 | 87 | ngx_shm_zone_t * 88 | ngx_http_stream_server_traffic_status_shm_find_zone(ngx_http_request_t *r, ngx_str_t *name) 89 | { 90 | ngx_uint_t i; 91 | ngx_str_t *shm_name; 92 | ngx_shm_zone_t *shm_zone; 93 | volatile ngx_list_part_t *part; 94 | 95 | part = &ngx_cycle->shared_memory.part; 96 | shm_zone = part->elts; 97 | 98 | for (i = 0; /* void */ ; i++) { 99 | 100 | if (i >= part->nelts) { 101 | if (part->next == NULL) { 102 | break; 103 | } 104 | 105 | part = part->next; 106 | shm_zone = part->elts; 107 | i = 0; 108 | } 109 | 110 | if (name->len != shm_zone[i].shm.name.len) { 111 | continue; 112 | } 113 | 114 | shm_name = &shm_zone[i].shm.name; 115 | 116 | ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 117 | "http stream sts shm_find_zone(): shm_name[%V], name[%V]", 118 | shm_name, name); 119 | 120 | if (ngx_strncmp(name->data, shm_name->data, name->len) == 0) { 121 | return &shm_zone[i]; 122 | } 123 | } 124 | 125 | return NULL; 126 | } 127 | 128 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ 129 | -------------------------------------------------------------------------------- /src/ngx_http_stream_server_traffic_status_shm.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) YoungJoo Kim (vozlt) 4 | */ 5 | 6 | 7 | #ifndef _NGX_HTTP_STREAM_STS_SHM_H_INCLUDED_ 8 | #define _NGX_HTTP_STREAM_STS_SHM_H_INCLUDED_ 9 | 10 | 11 | typedef struct { 12 | ngx_str_t *name; 13 | ngx_uint_t max_size; 14 | ngx_uint_t used_size; 15 | ngx_uint_t used_node; 16 | } ngx_http_stream_server_traffic_status_shm_info_t; 17 | 18 | 19 | void ngx_http_stream_server_traffic_status_shm_info_node(ngx_http_request_t *r, 20 | ngx_http_stream_server_traffic_status_shm_info_t *shm_info, 21 | ngx_rbtree_node_t *node); 22 | void ngx_http_stream_server_traffic_status_shm_info(ngx_http_request_t *r, 23 | ngx_http_stream_server_traffic_status_shm_info_t *shm_info); 24 | 25 | ngx_int_t ngx_http_stream_server_traffic_status_shm_init(ngx_http_request_t *r); 26 | ngx_shm_zone_t *ngx_http_stream_server_traffic_status_shm_find_zone(ngx_http_request_t *r, 27 | ngx_str_t *name); 28 | 29 | 30 | #endif /* _NGX_HTTP_STREAM_STS_SHM_H_INCLUDED_ */ 31 | 32 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ 33 | -------------------------------------------------------------------------------- /src/ngx_http_stream_server_traffic_status_string.c: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) YoungJoo Kim (vozlt) 4 | */ 5 | 6 | 7 | #include 8 | #include 9 | 10 | #include "ngx_http_stream_server_traffic_status_string.h" 11 | 12 | 13 | #if !defined(nginx_version) || nginx_version < 1007009 14 | 15 | /* from src/core/ngx_string.c in v1.7.9 */ 16 | uintptr_t 17 | ngx_http_stream_server_traffic_status_escape_json(u_char *dst, u_char *src, size_t size) 18 | { 19 | u_char ch; 20 | ngx_uint_t len; 21 | 22 | if (dst == NULL) { 23 | len = 0; 24 | 25 | while (size) { 26 | ch = *src++; 27 | 28 | if (ch == '\\' || ch == '"') { 29 | len++; 30 | 31 | } else if (ch <= 0x1f) { 32 | len += sizeof("\\u001F") - 2; 33 | } 34 | 35 | size--; 36 | } 37 | 38 | return (uintptr_t) len; 39 | } 40 | 41 | while (size) { 42 | ch = *src++; 43 | 44 | if (ch > 0x1f) { 45 | 46 | if (ch == '\\' || ch == '"') { 47 | *dst++ = '\\'; 48 | } 49 | 50 | *dst++ = ch; 51 | 52 | } else { 53 | *dst++ = '\\'; *dst++ = 'u'; *dst++ = '0'; *dst++ = '0'; 54 | *dst++ = '0' + (ch >> 4); 55 | 56 | ch &= 0xf; 57 | 58 | *dst++ = (ch < 10) ? ('0' + ch) : ('A' + ch - 10); 59 | } 60 | 61 | size--; 62 | } 63 | 64 | return (uintptr_t) dst; 65 | } 66 | 67 | #endif 68 | 69 | 70 | ngx_int_t 71 | ngx_http_stream_server_traffic_status_escape_json_pool(ngx_pool_t *pool, 72 | ngx_str_t *buf, ngx_str_t *dst) 73 | { 74 | u_char *p; 75 | 76 | buf->len = dst->len * 6; 77 | buf->data = ngx_pcalloc(pool, buf->len); 78 | if (buf->data == NULL) { 79 | *buf = *dst; 80 | return NGX_ERROR; 81 | } 82 | 83 | p = buf->data; 84 | 85 | #if !defined(nginx_version) || nginx_version < 1007009 86 | p = (u_char *) ngx_http_stream_server_traffic_status_escape_json(p, dst->data, dst->len); 87 | #else 88 | p = (u_char *) ngx_escape_json(p, dst->data, dst->len); 89 | #endif 90 | 91 | buf->len = ngx_strlen(buf->data); 92 | 93 | return NGX_OK; 94 | } 95 | 96 | 97 | ngx_int_t 98 | ngx_http_stream_server_traffic_status_copy_str(ngx_pool_t *pool, 99 | ngx_str_t *buf, ngx_str_t *dst) 100 | { 101 | u_char *p; 102 | 103 | buf->len = dst->len; 104 | buf->data = ngx_pcalloc(pool, dst->len + 1); /* 1 byte for terminating '\0' */ 105 | if (buf->data == NULL) { 106 | return NGX_ERROR; 107 | } 108 | 109 | p = buf->data; 110 | 111 | ngx_memcpy(p, dst->data, dst->len); 112 | 113 | return NGX_OK; 114 | } 115 | 116 | 117 | ngx_int_t 118 | ngx_http_stream_server_traffic_status_replace_chrc(ngx_str_t *buf, 119 | u_char in, u_char to) 120 | { 121 | size_t len; 122 | u_char *p; 123 | 124 | p = buf->data; 125 | 126 | len = buf->len; 127 | 128 | while(len--) { 129 | if (*p == in) { 130 | *p = to; 131 | } 132 | p++; 133 | } 134 | 135 | return NGX_OK; 136 | } 137 | 138 | 139 | ngx_int_t 140 | ngx_http_stream_server_traffic_status_replace_strc(ngx_str_t *buf, 141 | ngx_str_t *dst, u_char c) 142 | { 143 | size_t n, len; 144 | u_char *p, *o; 145 | p = o = buf->data; 146 | n = 0; 147 | 148 | /* we need the buf's last '\0' for ngx_strstrn() */ 149 | if (*(buf->data + buf->len) != 0) { 150 | return NGX_ERROR; 151 | } 152 | 153 | while ((p = ngx_strstrn(p, (char *) dst->data, dst->len - 1)) != NULL) { 154 | n++; 155 | len = buf->len - (p - o) - (n * dst->len) + n - 1; 156 | *p++ = c; 157 | ngx_memmove(p, p + dst->len - 1, len); 158 | } 159 | 160 | if (n > 0) { 161 | buf->len = buf->len - (n * dst->len) + n; 162 | } 163 | 164 | return NGX_OK; 165 | } 166 | 167 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ 168 | -------------------------------------------------------------------------------- /src/ngx_http_stream_server_traffic_status_string.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) YoungJoo Kim (vozlt) 4 | */ 5 | 6 | 7 | #ifndef _NGX_HTTP_STREAM_STS_STRING_H_INCLUDED_ 8 | #define _NGX_HTTP_STREAM_STS_STRING_H_INCLUDED_ 9 | 10 | 11 | #if !defined(nginx_version) || nginx_version < 1007009 12 | uintptr_t ngx_http_stream_server_traffic_status_escape_json(u_char *dst, u_char *src, size_t size); 13 | #endif 14 | ngx_int_t ngx_http_stream_server_traffic_status_escape_json_pool(ngx_pool_t *pool, 15 | ngx_str_t *buf, ngx_str_t *dst); 16 | ngx_int_t ngx_http_stream_server_traffic_status_copy_str(ngx_pool_t *pool, 17 | ngx_str_t *buf, ngx_str_t *dst); 18 | ngx_int_t ngx_http_stream_server_traffic_status_replace_chrc(ngx_str_t *buf, 19 | u_char in, u_char to); 20 | ngx_int_t ngx_http_stream_server_traffic_status_replace_strc(ngx_str_t *buf, 21 | ngx_str_t *dst, u_char c); 22 | 23 | 24 | #endif /* _NGX_HTTP_STREAM_STS_STRING_H_INCLUDED_ */ 25 | 26 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ 27 | -------------------------------------------------------------------------------- /t/000.display_html.t: -------------------------------------------------------------------------------- 1 | # vi:set ft=perl ts=4 sw=4 et fdm=marker: 2 | 3 | use Test::Nginx::Socket; 4 | 5 | plan tests => repeat_each(2) * blocks() * 2; 6 | no_shuffle(); 7 | run_tests(); 8 | 9 | __DATA__ 10 | 11 | === TEST 1: /status/format/html 12 | --- main_config 13 | stream { 14 | server_traffic_status_zone; 15 | } 16 | --- http_config 17 | stream_server_traffic_status_zone; 18 | --- config 19 | location /status { 20 | stream_server_traffic_status_display; 21 | stream_server_traffic_status_display_format html; 22 | } 23 | --- request 24 | GET /status/format/html 25 | --- response_headers_like 26 | Content-Type: text/html 27 | 28 | 29 | 30 | === TEST 2: /status 31 | --- main_config 32 | stream { 33 | server_traffic_status_zone; 34 | } 35 | --- http_config 36 | stream_server_traffic_status_zone; 37 | --- config 38 | location /status { 39 | stream_server_traffic_status_display; 40 | stream_server_traffic_status_display_format html; 41 | } 42 | --- request 43 | GET /status 44 | --- response_headers_like 45 | Content-Type: text/html 46 | -------------------------------------------------------------------------------- /t/001.display_json.t: -------------------------------------------------------------------------------- 1 | # vi:set ft=perl ts=4 sw=4 et fdm=marker: 2 | 3 | use Test::Nginx::Socket; 4 | 5 | plan tests => repeat_each(2) * blocks() * 2; 6 | no_shuffle(); 7 | run_tests(); 8 | 9 | __DATA__ 10 | 11 | === TEST 1: /status/format/json 12 | --- main_config 13 | stream { 14 | server_traffic_status_zone; 15 | } 16 | --- http_config 17 | stream_server_traffic_status_zone; 18 | --- config 19 | location /status { 20 | stream_server_traffic_status_display; 21 | stream_server_traffic_status_display_format json; 22 | } 23 | --- request 24 | GET /status/format/json 25 | --- response_headers_like 26 | Content-Type: application/json 27 | 28 | 29 | 30 | === TEST 2: /status 31 | --- main_config 32 | stream { 33 | server_traffic_status_zone; 34 | } 35 | --- http_config 36 | stream_server_traffic_status_zone; 37 | --- config 38 | location /status { 39 | stream_server_traffic_status_display; 40 | stream_server_traffic_status_display_format json; 41 | } 42 | --- request 43 | GET /status 44 | --- response_headers_like 45 | Content-Type: application/json 46 | -------------------------------------------------------------------------------- /t/002.display_filter.t: -------------------------------------------------------------------------------- 1 | # vi:set ft=perl ts=4 sw=4 et fdm=marker: 2 | 3 | use Test::Nginx::Socket; 4 | 5 | plan tests => repeat_each() * blocks() * 4; 6 | no_shuffle(); 7 | run_tests(); 8 | 9 | __DATA__ 10 | 11 | === TEST 1: display_filter 12 | --- main_config 13 | stream { 14 | server_traffic_status_zone; 15 | upstream backend { 16 | server localhost:1984; 17 | } 18 | server { 19 | listen 1985; 20 | server_traffic_status_filter_by_set_key $protocol protocol; 21 | proxy_pass backend; 22 | } 23 | 24 | } 25 | --- http_config 26 | stream_server_traffic_status_zone; 27 | --- config 28 | location /status { 29 | stream_server_traffic_status_display; 30 | stream_server_traffic_status_display_format json; 31 | access_log off; 32 | } 33 | location /stream { 34 | proxy_pass http://localhost:1985/return; 35 | } 36 | --- user_files eval 37 | [ 38 | ['return/file.txt' => '{"return":"OK"}'] 39 | ] 40 | --- request eval 41 | [ 42 | 'GET /stream/file.txt', 43 | 'GET /status/format/json' 44 | ] 45 | --- response_body_like eval 46 | [ 47 | 'OK', 48 | 'streamFilterZones' 49 | ] 50 | -------------------------------------------------------------------------------- /t/003.check_json_syntax.t: -------------------------------------------------------------------------------- 1 | # vi:set ft=perl ts=4 sw=4 et fdm=marker: 2 | 3 | use Test::Nginx::Socket; 4 | 5 | add_response_body_check( 6 | sub { 7 | my ($block, $body, $req_idx, $repeated_req_idx, $dry_run) = @_; 8 | system("echo '$body' | python -m json.tool > /dev/null") == 0 or 9 | bail_out "JSON Syntax error($body)"; 10 | } 11 | ); 12 | 13 | plan tests => repeat_each() * blocks() * 6; 14 | no_shuffle(); 15 | run_tests(); 16 | 17 | __DATA__ 18 | 19 | === TEST 1: check_json_syntax 20 | --- main_config 21 | stream { 22 | server_traffic_status_zone; 23 | upstream backend { 24 | server localhost:1984; 25 | } 26 | server { 27 | listen 1985; 28 | server_traffic_status_filter_by_set_key $protocol protocol; 29 | proxy_pass backend; 30 | } 31 | 32 | } 33 | --- http_config 34 | stream_server_traffic_status_zone; 35 | --- config 36 | location /status { 37 | stream_server_traffic_status_display; 38 | stream_server_traffic_status_display_format json; 39 | access_log off; 40 | } 41 | location /stream { 42 | proxy_pass http://localhost:1985/return; 43 | } 44 | --- user_files eval 45 | [ 46 | ['return/file.txt' => '{"return":"OK"}'] 47 | ] 48 | --- request eval 49 | [ 50 | 'GET /status/format/json', 51 | 'GET /stream/file.txt', 52 | 'GET /status/format/json' 53 | ] 54 | --- response_body_like eval 55 | [ 56 | 'nginxVersion', 57 | 'OK', 58 | 'streamFilterZones' 59 | ] 60 | -------------------------------------------------------------------------------- /t/004.control_status_fully.t: -------------------------------------------------------------------------------- 1 | # vi:set ft=perl ts=4 sw=4 et fdm=marker: 2 | 3 | use Test::Nginx::Socket; 4 | 5 | plan tests => repeat_each() * blocks() * 4; 6 | no_shuffle(); 7 | run_tests(); 8 | 9 | __DATA__ 10 | 11 | === TEST 1: /status/control?cmd=status&group=* 12 | --- main_config 13 | stream { 14 | server_traffic_status_zone; 15 | upstream backend { 16 | server localhost:1984; 17 | } 18 | server { 19 | listen 1985; 20 | server_traffic_status_filter_by_set_key $protocol protocol; 21 | proxy_pass backend; 22 | } 23 | 24 | } 25 | --- http_config 26 | stream_server_traffic_status_zone; 27 | --- config 28 | location /status { 29 | stream_server_traffic_status_display; 30 | stream_server_traffic_status_display_format json; 31 | access_log off; 32 | } 33 | location /stream { 34 | proxy_pass http://localhost:1985/return; 35 | } 36 | --- user_files eval 37 | [ 38 | ['return/file.txt' => '{"return":"OK"}'] 39 | ] 40 | --- request eval 41 | [ 42 | 'GET /stream/file.txt', 43 | 'GET /status/control?cmd=status&group=*', 44 | ] 45 | --- response_body_like eval 46 | [ 47 | 'OK', 48 | 'nginxVersion' 49 | ] 50 | -------------------------------------------------------------------------------- /t/005.control_status_group.t: -------------------------------------------------------------------------------- 1 | # vi:set ft=perl ts=4 sw=4 et fdm=marker: 2 | 3 | use Test::Nginx::Socket; 4 | 5 | plan tests => repeat_each() * blocks() * 4; 6 | no_shuffle(); 7 | run_tests(); 8 | 9 | __DATA__ 10 | 11 | === TEST 1: /status/control?cmd=status&group=server&zone=* 12 | --- main_config 13 | stream { 14 | server_traffic_status_zone; 15 | upstream backend { 16 | server localhost:1984; 17 | } 18 | server { 19 | listen 1985; 20 | server_traffic_status_filter_by_set_key $protocol protocol; 21 | proxy_pass backend; 22 | } 23 | } 24 | --- http_config 25 | stream_server_traffic_status_zone; 26 | --- config 27 | location /status { 28 | stream_server_traffic_status_display; 29 | stream_server_traffic_status_display_format json; 30 | access_log off; 31 | } 32 | location /stream { 33 | proxy_pass http://localhost:1985/return; 34 | } 35 | --- user_files eval 36 | [ 37 | ['return/file.txt' => '{"return":"OK"}'] 38 | ] 39 | --- request eval 40 | [ 41 | 'GET /stream/file.txt', 42 | 'GET /status/control?cmd=status&group=server&zone=*', 43 | ] 44 | --- response_body_like eval 45 | [ 46 | 'OK', 47 | 'streamServerZones' 48 | ] 49 | 50 | 51 | 52 | === TEST 2: /status/control?cmd=status&group=filter&zone=* 53 | --- main_config 54 | stream { 55 | server_traffic_status_zone; 56 | upstream backend { 57 | server localhost:1984; 58 | } 59 | server { 60 | listen 1985; 61 | server_traffic_status_filter_by_set_key $protocol protocol; 62 | proxy_pass backend; 63 | } 64 | } 65 | --- http_config 66 | stream_server_traffic_status_zone; 67 | --- config 68 | location /status { 69 | stream_server_traffic_status_display; 70 | stream_server_traffic_status_display_format json; 71 | access_log off; 72 | } 73 | location /stream { 74 | proxy_pass http://localhost:1985/return; 75 | } 76 | --- user_files eval 77 | [ 78 | ['return/file.txt' => '{"return":"OK"}'] 79 | ] 80 | --- request eval 81 | [ 82 | 'GET /stream/file.txt', 83 | 'GET /status/control?cmd=status&group=filter&zone=*', 84 | ] 85 | --- response_body_like eval 86 | [ 87 | 'OK', 88 | 'streamFilterZones' 89 | ] 90 | 91 | 92 | 93 | === TEST 3: /status/control?cmd=status&group=upstream@group&zone=* 94 | --- main_config 95 | stream { 96 | server_traffic_status_zone; 97 | upstream backend { 98 | server localhost:1984; 99 | } 100 | server { 101 | listen 1985; 102 | server_traffic_status_filter_by_set_key $protocol protocol; 103 | proxy_pass backend; 104 | } 105 | } 106 | --- http_config 107 | stream_server_traffic_status_zone; 108 | --- config 109 | location /status { 110 | stream_server_traffic_status_display; 111 | stream_server_traffic_status_display_format json; 112 | access_log off; 113 | } 114 | location /stream { 115 | proxy_pass http://localhost:1985/return; 116 | } 117 | --- user_files eval 118 | [ 119 | ['return/file.txt' => '{"return":"OK"}'] 120 | ] 121 | --- request eval 122 | [ 123 | 'GET /stream/file.txt', 124 | 'GET /status/control?cmd=status&group=upstream@group&zone=*', 125 | ] 126 | --- response_body_like eval 127 | [ 128 | 'OK', 129 | 'streamUpstreamZones' 130 | ] 131 | 132 | 133 | 134 | === TEST 4: /status/control?cmd=status&group=upstream@alone&zone=* 135 | --- main_config 136 | stream { 137 | server_traffic_status_zone; 138 | server { 139 | listen 1985; 140 | proxy_pass localhost:1984; 141 | } 142 | } 143 | --- http_config 144 | stream_server_traffic_status_zone; 145 | --- config 146 | location /status { 147 | stream_server_traffic_status_display; 148 | stream_server_traffic_status_display_format json; 149 | access_log off; 150 | } 151 | location /stream { 152 | proxy_pass http://localhost:1985/return; 153 | } 154 | --- user_files eval 155 | [ 156 | ['return/file.txt' => '{"return":"OK"}'] 157 | ] 158 | --- request eval 159 | [ 160 | 'GET /stream/file.txt', 161 | 'GET /status/control?cmd=status&group=upstream@alone&zone=*', 162 | ] 163 | --- response_body_like eval 164 | [ 165 | 'OK', 166 | '::nogroups' 167 | ] 168 | -------------------------------------------------------------------------------- /t/006.control_status_zone.t: -------------------------------------------------------------------------------- 1 | # vi:set ft=perl ts=4 sw=4 et fdm=marker: 2 | 3 | use Test::Nginx::Socket; 4 | 5 | plan tests => repeat_each() * blocks() * 4; 6 | no_shuffle(); 7 | run_tests(); 8 | 9 | __DATA__ 10 | 11 | === TEST 1: /status/control?cmd=status&group=server&zone=TCP:1985:127.0.0.1 12 | --- main_config 13 | stream { 14 | server_traffic_status_zone; 15 | upstream backend { 16 | server localhost:1984; 17 | } 18 | server { 19 | listen 1985; 20 | server_traffic_status_filter_by_set_key $protocol protocol; 21 | proxy_pass backend; 22 | } 23 | } 24 | --- http_config 25 | stream_server_traffic_status_zone; 26 | --- config 27 | location /status { 28 | stream_server_traffic_status_display; 29 | stream_server_traffic_status_display_format json; 30 | access_log off; 31 | } 32 | location /stream { 33 | proxy_pass http://localhost:1985/return; 34 | } 35 | --- user_files eval 36 | [ 37 | ['return/file.txt' => '{"return":"OK"}'] 38 | ] 39 | --- request eval 40 | [ 41 | 'GET /stream/file.txt', 42 | 'GET /status/control?cmd=status&group=server&zone=TCP:1985:127.0.0.1' 43 | ] 44 | --- response_body_like eval 45 | [ 46 | 'OK', 47 | 'TCP' 48 | ] 49 | 50 | 51 | 52 | === TEST 2: /status/control?cmd=status&group=filter&zone=protocol@TCP 53 | --- main_config 54 | stream { 55 | server_traffic_status_zone; 56 | upstream backend { 57 | server localhost:1984; 58 | } 59 | server { 60 | listen 1985; 61 | server_traffic_status_filter_by_set_key $protocol protocol; 62 | proxy_pass backend; 63 | } 64 | } 65 | --- http_config 66 | stream_server_traffic_status_zone; 67 | --- config 68 | location /status { 69 | stream_server_traffic_status_display; 70 | stream_server_traffic_status_display_format json; 71 | access_log off; 72 | } 73 | location /stream { 74 | proxy_pass http://localhost:1985/return; 75 | } 76 | --- user_files eval 77 | [ 78 | ['return/file.txt' => '{"return":"OK"}'] 79 | ] 80 | --- request eval 81 | [ 82 | 'GET /stream/file.txt', 83 | 'GET /status/control?cmd=status&group=filter&zone=protocol@TCP', 84 | ] 85 | --- response_body_like eval 86 | [ 87 | 'OK', 88 | 'TCP' 89 | ] 90 | 91 | 92 | 93 | === TEST 3: /status/control?cmd=status&group=upstream@group&zone=backend@127.0.0.1:1984: 94 | --- main_config 95 | stream { 96 | server_traffic_status_zone; 97 | upstream backend { 98 | server localhost:1984; 99 | } 100 | server { 101 | listen 1985; 102 | server_traffic_status_filter_by_set_key $protocol protocol; 103 | proxy_pass backend; 104 | } 105 | } 106 | --- http_config 107 | stream_server_traffic_status_zone; 108 | --- config 109 | location /status { 110 | stream_server_traffic_status_display; 111 | stream_server_traffic_status_display_format json; 112 | access_log off; 113 | } 114 | location /stream { 115 | proxy_pass http://localhost:1985/return; 116 | } 117 | --- user_files eval 118 | [ 119 | ['return/file.txt' => '{"return":"OK"}'] 120 | ] 121 | --- request eval 122 | [ 123 | 'GET /stream/file.txt', 124 | 'GET /status/control?cmd=status&group=upstream@group&zone=backend@127.0.0.1:1984', 125 | ] 126 | --- response_body_like eval 127 | [ 128 | 'OK', 129 | 'connectCounter' 130 | ] 131 | 132 | 133 | 134 | === TEST 4: /status/control?cmd=status&group=upstream@alone&zone=127.0.0.1:1984 135 | --- main_config 136 | stream { 137 | server_traffic_status_zone; 138 | server { 139 | listen 1985; 140 | server_traffic_status_filter_by_set_key $protocol protocol; 141 | proxy_pass localhost:1984; 142 | } 143 | } 144 | --- http_config 145 | stream_server_traffic_status_zone; 146 | --- config 147 | location /status { 148 | stream_server_traffic_status_display; 149 | stream_server_traffic_status_display_format json; 150 | access_log off; 151 | } 152 | location /stream { 153 | proxy_pass http://localhost:1985/return; 154 | } 155 | --- user_files eval 156 | [ 157 | ['return/file.txt' => '{"return":"OK"}'] 158 | ] 159 | --- request eval 160 | [ 161 | 'GET /stream/file.txt', 162 | 'GET /status/control?cmd=status&group=upstream@alone&zone=127.0.0.1:1984', 163 | ] 164 | --- response_body_like eval 165 | [ 166 | 'OK', 167 | 'connectCounter' 168 | ] 169 | -------------------------------------------------------------------------------- /t/007.control_reset_fully.t: -------------------------------------------------------------------------------- 1 | # vi:set ft=perl ts=4 sw=4 et fdm=marker: 2 | 3 | use Test::Nginx::Socket; 4 | 5 | plan tests => repeat_each() * blocks() * 4; 6 | no_shuffle(); 7 | run_tests(); 8 | 9 | __DATA__ 10 | 11 | === TEST 1: /status/control?cmd=reset&group=* 12 | --- main_config 13 | stream { 14 | server_traffic_status_zone; 15 | upstream backend { 16 | server localhost:1984; 17 | } 18 | server { 19 | listen 1985; 20 | server_traffic_status_filter_by_set_key $protocol protocol; 21 | proxy_pass backend; 22 | } 23 | } 24 | --- http_config 25 | stream_server_traffic_status_zone; 26 | --- config 27 | location /status { 28 | stream_server_traffic_status_display; 29 | stream_server_traffic_status_display_format json; 30 | access_log off; 31 | } 32 | location /stream { 33 | proxy_pass http://localhost:1985/return; 34 | } 35 | --- user_files eval 36 | [ 37 | ['return/file.txt' => '{"return":"OK"}'] 38 | ] 39 | --- request eval 40 | [ 41 | 'GET /stream/file.txt', 42 | 'GET /status/control?cmd=reset&group=*', 43 | ] 44 | --- response_body_like eval 45 | [ 46 | 'OK', 47 | '"processingCounts":[1-9]' 48 | ] 49 | -------------------------------------------------------------------------------- /t/008.control_reset_group.t: -------------------------------------------------------------------------------- 1 | # vi:set ft=perl ts=4 sw=4 et fdm=marker: 2 | 3 | use Test::Nginx::Socket; 4 | 5 | plan tests => repeat_each() * blocks() * 4; 6 | no_shuffle(); 7 | run_tests(); 8 | 9 | __DATA__ 10 | 11 | === TEST 1: /status/control?cmd=reset&group=server&zone=* 12 | --- main_config 13 | stream { 14 | server_traffic_status_zone; 15 | upstream backend { 16 | server localhost:1984; 17 | } 18 | server { 19 | listen 1985; 20 | server_traffic_status_filter_by_set_key $protocol protocol; 21 | proxy_pass backend; 22 | } 23 | } 24 | --- http_config 25 | stream_server_traffic_status_zone; 26 | --- config 27 | location /status { 28 | stream_server_traffic_status_display; 29 | stream_server_traffic_status_display_format json; 30 | access_log off; 31 | } 32 | location /stream { 33 | proxy_pass http://localhost:1985/return; 34 | } 35 | --- user_files eval 36 | [ 37 | ['return/file.txt' => '{"return":"OK"}'] 38 | ] 39 | --- request eval 40 | [ 41 | 'GET /stream/file.txt', 42 | 'GET /status/control?cmd=reset&group=server&zone=*', 43 | ] 44 | --- response_body_like eval 45 | [ 46 | 'OK', 47 | '"processingCounts":[1-9]' 48 | ] 49 | 50 | 51 | 52 | === TEST 2: /status/control?cmd=reset&group=filter&zone=* 53 | --- main_config 54 | stream { 55 | server_traffic_status_zone; 56 | upstream backend { 57 | server localhost:1984; 58 | } 59 | server { 60 | listen 1985; 61 | server_traffic_status_filter_by_set_key $protocol protocol; 62 | proxy_pass backend; 63 | } 64 | } 65 | --- http_config 66 | stream_server_traffic_status_zone; 67 | --- config 68 | location /status { 69 | stream_server_traffic_status_display; 70 | stream_server_traffic_status_display_format json; 71 | access_log off; 72 | } 73 | location /stream { 74 | proxy_pass http://localhost:1985/return; 75 | } 76 | --- user_files eval 77 | [ 78 | ['return/file.txt' => '{"return":"OK"}'] 79 | ] 80 | --- request eval 81 | [ 82 | 'GET /stream/file.txt', 83 | 'GET /status/control?cmd=reset&group=filter&zone=*', 84 | ] 85 | --- response_body_like eval 86 | [ 87 | 'OK', 88 | '"processingCounts":[1-9]' 89 | ] 90 | 91 | 92 | 93 | === TEST 3: /status/control?cmd=reset&group=upstream@group&zone=* 94 | --- main_config 95 | stream { 96 | server_traffic_status_zone; 97 | upstream backend { 98 | server localhost:1984; 99 | } 100 | server { 101 | listen 1985; 102 | server_traffic_status_filter_by_set_key $protocol protocol; 103 | proxy_pass backend; 104 | } 105 | } 106 | --- http_config 107 | stream_server_traffic_status_zone; 108 | --- config 109 | location /status { 110 | stream_server_traffic_status_display; 111 | stream_server_traffic_status_display_format json; 112 | access_log off; 113 | } 114 | location /stream { 115 | proxy_pass http://localhost:1985/return; 116 | } 117 | --- user_files eval 118 | [ 119 | ['return/file.txt' => '{"return":"OK"}'] 120 | ] 121 | --- request eval 122 | [ 123 | 'GET /stream/file.txt', 124 | 'GET /status/control?cmd=reset&group=upstream@group&zone=*', 125 | ] 126 | --- response_body_like eval 127 | [ 128 | 'OK', 129 | '"processingCounts":[1-9]' 130 | ] 131 | 132 | 133 | 134 | === TEST 4: /status/control?cmd=reset&group=upstream@alone&zone=* 135 | --- main_config 136 | stream { 137 | server_traffic_status_zone; 138 | server { 139 | listen 1985; 140 | server_traffic_status_filter_by_set_key $protocol protocol; 141 | proxy_pass localhost:1984; 142 | } 143 | } 144 | --- http_config 145 | stream_server_traffic_status_zone; 146 | --- config 147 | location /status { 148 | stream_server_traffic_status_display; 149 | stream_server_traffic_status_display_format json; 150 | access_log off; 151 | } 152 | location /stream { 153 | proxy_pass http://localhost:1985/return; 154 | } 155 | --- user_files eval 156 | [ 157 | ['return/file.txt' => '{"return":"OK"}'] 158 | ] 159 | --- request eval 160 | [ 161 | 'GET /stream/file.txt', 162 | 'GET /status/control?cmd=reset&group=upstream@alone&zone=*', 163 | ] 164 | --- response_body_like eval 165 | [ 166 | 'OK', 167 | '"processingCounts":[1-9]' 168 | ] 169 | -------------------------------------------------------------------------------- /t/009.control_reset_zone.t: -------------------------------------------------------------------------------- 1 | # vi:set ft=perl ts=4 sw=4 et fdm=marker: 2 | 3 | use Test::Nginx::Socket; 4 | 5 | plan tests => repeat_each() * blocks() * 4; 6 | no_shuffle(); 7 | run_tests(); 8 | 9 | __DATA__ 10 | 11 | === TEST 1: /status/control?cmd=reset&group=server&zone=TCP:1985:127.0.0.1 12 | --- main_config 13 | stream { 14 | server_traffic_status_zone; 15 | upstream backend { 16 | server localhost:1984; 17 | } 18 | server { 19 | listen 1985; 20 | server_traffic_status_filter_by_set_key $protocol protocol; 21 | proxy_pass backend; 22 | } 23 | } 24 | --- http_config 25 | stream_server_traffic_status_zone; 26 | --- config 27 | location /status { 28 | stream_server_traffic_status_display; 29 | stream_server_traffic_status_display_format json; 30 | access_log off; 31 | } 32 | location /stream { 33 | proxy_pass http://localhost:1985/return; 34 | } 35 | --- user_files eval 36 | [ 37 | ['return/file.txt' => '{"return":"OK"}'] 38 | ] 39 | --- request eval 40 | [ 41 | 'GET /stream/file.txt', 42 | 'GET /status/control?cmd=reset&group=server&zone=TCP:1985:127.0.0.1', 43 | ] 44 | --- response_body_like eval 45 | [ 46 | 'OK', 47 | '"processingCounts":[1-9]' 48 | ] 49 | 50 | 51 | 52 | === TEST 2: /status/control?cmd=reset&group=filter&zone=protocol@TCP 53 | --- main_config 54 | stream { 55 | server_traffic_status_zone; 56 | upstream backend { 57 | server localhost:1984; 58 | } 59 | server { 60 | listen 1985; 61 | server_traffic_status_filter_by_set_key $protocol protocol; 62 | proxy_pass backend; 63 | } 64 | } 65 | --- http_config 66 | stream_server_traffic_status_zone; 67 | --- config 68 | location /status { 69 | stream_server_traffic_status_display; 70 | stream_server_traffic_status_display_format json; 71 | access_log off; 72 | } 73 | location /stream { 74 | proxy_pass http://localhost:1985/return; 75 | } 76 | --- user_files eval 77 | [ 78 | ['return/file.txt' => '{"return":"OK"}'] 79 | ] 80 | --- request eval 81 | [ 82 | 'GET /stream/file.txt', 83 | 'GET /status/control?cmd=reset&group=filter&zone=protocol@TCP', 84 | ] 85 | --- response_body_like eval 86 | [ 87 | 'OK', 88 | '"processingCounts":[1-9]' 89 | ] 90 | 91 | 92 | 93 | === TEST 3: /status/control?cmd=reset&group=upstream@group&zone=backend@127.0.0.1:1984 94 | --- main_config 95 | stream { 96 | server_traffic_status_zone; 97 | upstream backend { 98 | server localhost:1984; 99 | } 100 | server { 101 | listen 1985; 102 | server_traffic_status_filter_by_set_key $protocol protocol; 103 | proxy_pass backend; 104 | } 105 | } 106 | --- http_config 107 | stream_server_traffic_status_zone; 108 | --- config 109 | location /status { 110 | stream_server_traffic_status_display; 111 | stream_server_traffic_status_display_format json; 112 | access_log off; 113 | } 114 | location /stream { 115 | proxy_pass http://localhost:1985/return; 116 | } 117 | --- user_files eval 118 | [ 119 | ['return/file.txt' => '{"return":"OK"}'] 120 | ] 121 | --- request eval 122 | [ 123 | 'GET /stream/file.txt', 124 | 'GET /status/control?cmd=reset&group=upstream@group&zone=backend@127.0.0.1:1984', 125 | ] 126 | --- response_body_like eval 127 | [ 128 | 'OK', 129 | '"processingCounts":[1-9]' 130 | ] 131 | 132 | 133 | 134 | === TEST 4: /status/control?cmd=reset&group=upstream@alone&zone=127.0.0.1:1984 135 | --- main_config 136 | stream { 137 | server_traffic_status_zone; 138 | server { 139 | listen 1985; 140 | server_traffic_status_filter_by_set_key $protocol protocol; 141 | proxy_pass localhost:1984; 142 | } 143 | } 144 | --- http_config 145 | stream_server_traffic_status_zone; 146 | --- config 147 | location /status { 148 | stream_server_traffic_status_display; 149 | stream_server_traffic_status_display_format json; 150 | access_log off; 151 | } 152 | location /stream { 153 | proxy_pass http://localhost:1985/return; 154 | } 155 | --- user_files eval 156 | [ 157 | ['return/file.txt' => '{"return":"OK"}'] 158 | ] 159 | --- request eval 160 | [ 161 | 'GET /stream/file.txt', 162 | 'GET /status/control?cmd=reset&group=upstream@alone&zone=127.0.0.1:1984', 163 | ] 164 | --- response_body_like eval 165 | [ 166 | 'OK', 167 | '"processingCounts":[1-9]' 168 | ] 169 | -------------------------------------------------------------------------------- /t/010.control_delete_fully.t: -------------------------------------------------------------------------------- 1 | # vi:set ft=perl ts=4 sw=4 et fdm=marker: 2 | 3 | use Test::Nginx::Socket; 4 | 5 | plan tests => repeat_each() * blocks() * 4; 6 | no_shuffle(); 7 | run_tests(); 8 | 9 | __DATA__ 10 | 11 | === TEST 1: /status/control?cmd=delete&group=* 12 | --- main_config 13 | stream { 14 | server_traffic_status_zone; 15 | upstream backend { 16 | server localhost:1984; 17 | } 18 | server { 19 | listen 1985; 20 | server_traffic_status_filter_by_set_key $protocol protocol; 21 | proxy_pass backend; 22 | } 23 | } 24 | --- http_config 25 | stream_server_traffic_status_zone; 26 | --- config 27 | location /status { 28 | stream_server_traffic_status_display; 29 | stream_server_traffic_status_display_format json; 30 | access_log off; 31 | } 32 | location /stream { 33 | proxy_pass http://localhost:1985/return; 34 | } 35 | --- user_files eval 36 | [ 37 | ['return/file.txt' => '{"return":"OK"}'] 38 | ] 39 | --- request eval 40 | [ 41 | 'GET /stream/file.txt', 42 | 'GET /status/control?cmd=delete&group=*', 43 | ] 44 | --- response_body_like eval 45 | [ 46 | 'OK', 47 | '"processingCounts":[1-9]' 48 | ] 49 | -------------------------------------------------------------------------------- /t/011.control_delete_group.t: -------------------------------------------------------------------------------- 1 | # vi:set ft=perl ts=4 sw=4 et fdm=marker: 2 | 3 | use Test::Nginx::Socket; 4 | 5 | plan tests => repeat_each() * blocks() * 4; 6 | no_shuffle(); 7 | run_tests(); 8 | 9 | __DATA__ 10 | 11 | === TEST 1: /status/control?cmd=delete&group=server&zone=* 12 | --- main_config 13 | stream { 14 | server_traffic_status_zone; 15 | upstream backend { 16 | server localhost:1984; 17 | } 18 | server { 19 | listen 1985; 20 | server_traffic_status_filter_by_set_key $protocol protocol; 21 | proxy_pass backend; 22 | } 23 | } 24 | --- http_config 25 | stream_server_traffic_status_zone; 26 | --- config 27 | location /status { 28 | stream_server_traffic_status_display; 29 | stream_server_traffic_status_display_format json; 30 | access_log off; 31 | } 32 | location /stream { 33 | proxy_pass http://localhost:1985/return; 34 | } 35 | --- user_files eval 36 | [ 37 | ['return/file.txt' => '{"return":"OK"}'] 38 | ] 39 | --- request eval 40 | [ 41 | 'GET /stream/file.txt', 42 | "GET /status/control?cmd=delete&group=server&zone=*", 43 | ] 44 | --- response_body_like eval 45 | [ 46 | 'OK', 47 | '"processingCounts":[1-9]' 48 | ] 49 | 50 | 51 | 52 | === TEST 2: /status/control?cmd=delete&group=filter&zone=* 53 | --- main_config 54 | stream { 55 | server_traffic_status_zone; 56 | upstream backend { 57 | server localhost:1984; 58 | } 59 | server { 60 | listen 1985; 61 | server_traffic_status_filter_by_set_key $protocol protocol; 62 | proxy_pass backend; 63 | } 64 | } 65 | --- http_config 66 | stream_server_traffic_status_zone; 67 | --- config 68 | location /status { 69 | stream_server_traffic_status_display; 70 | stream_server_traffic_status_display_format json; 71 | access_log off; 72 | } 73 | location /stream { 74 | proxy_pass http://localhost:1985/return; 75 | } 76 | --- user_files eval 77 | [ 78 | ['return/file.txt' => '{"return":"OK"}'] 79 | ] 80 | --- request eval 81 | [ 82 | 'GET /stream/file.txt', 83 | 'GET /status/control?cmd=delete&group=filter&zone=*', 84 | ] 85 | --- response_body_like eval 86 | [ 87 | 'OK', 88 | '"processingCounts":[1-9]' 89 | ] 90 | 91 | 92 | 93 | === TEST 3: /status/control?cmd=delete&group=upstream@group&zone=* 94 | --- main_config 95 | stream { 96 | server_traffic_status_zone; 97 | upstream backend { 98 | server localhost:1984; 99 | } 100 | server { 101 | listen 1985; 102 | server_traffic_status_filter_by_set_key $protocol protocol; 103 | proxy_pass backend; 104 | } 105 | } 106 | --- http_config 107 | stream_server_traffic_status_zone; 108 | --- config 109 | location /status { 110 | stream_server_traffic_status_display; 111 | stream_server_traffic_status_display_format json; 112 | access_log off; 113 | } 114 | location /stream { 115 | proxy_pass http://localhost:1985/return; 116 | } 117 | --- user_files eval 118 | [ 119 | ['return/file.txt' => '{"return":"OK"}'] 120 | ] 121 | --- request eval 122 | [ 123 | 'GET /stream/file.txt', 124 | 'GET /status/control?cmd=delete&group=upstream@group&zone=*', 125 | ] 126 | --- response_body_like eval 127 | [ 128 | 'OK', 129 | '"processingCounts":[1-9]' 130 | ] 131 | 132 | 133 | 134 | === TEST 4: /status/control?cmd=delete&group=upstream@alone&zone=* 135 | --- main_config 136 | stream { 137 | server_traffic_status_zone; 138 | server { 139 | listen 1985; 140 | server_traffic_status_filter_by_set_key $protocol protocol; 141 | proxy_pass localhost:1984; 142 | } 143 | } 144 | --- http_config 145 | stream_server_traffic_status_zone; 146 | --- config 147 | location /status { 148 | stream_server_traffic_status_display; 149 | stream_server_traffic_status_display_format json; 150 | access_log off; 151 | } 152 | location /stream { 153 | proxy_pass http://localhost:1985/return; 154 | } 155 | --- user_files eval 156 | [ 157 | ['return/file.txt' => '{"return":"OK"}'] 158 | ] 159 | --- request eval 160 | [ 161 | 'GET /stream/file.txt', 162 | 'GET /status/control?cmd=delete&group=upstream@alone&zone=*', 163 | ] 164 | --- response_body_like eval 165 | [ 166 | 'OK', 167 | '"processingCounts":[1-9]' 168 | ] 169 | -------------------------------------------------------------------------------- /t/012.control_delete_zone.t: -------------------------------------------------------------------------------- 1 | # vi:set ft=perl ts=4 sw=4 et fdm=marker: 2 | 3 | use Test::Nginx::Socket; 4 | 5 | plan tests => repeat_each() * blocks() * 4; 6 | no_shuffle(); 7 | run_tests(); 8 | 9 | __DATA__ 10 | 11 | === TEST 1: /status/control?cmd=delete&group=server&zone=TCP:1985:127.0.0.1 12 | --- main_config 13 | stream { 14 | server_traffic_status_zone; 15 | upstream backend { 16 | server localhost:1984; 17 | } 18 | server { 19 | listen 1985; 20 | server_traffic_status_filter_by_set_key $protocol protocol; 21 | proxy_pass backend; 22 | } 23 | } 24 | --- http_config 25 | stream_server_traffic_status_zone; 26 | --- config 27 | location /status { 28 | stream_server_traffic_status_display; 29 | stream_server_traffic_status_display_format json; 30 | access_log off; 31 | } 32 | location /stream { 33 | proxy_pass http://localhost:1985/return; 34 | } 35 | --- user_files eval 36 | [ 37 | ['return/file.txt' => '{"return":"OK"}'] 38 | ] 39 | --- request eval 40 | [ 41 | 'GET /stream/file.txt', 42 | 'GET /status/control?cmd=delete&group=server&zone=TCP:1985:127.0.0.1', 43 | ] 44 | --- response_body_like eval 45 | [ 46 | 'OK', 47 | '"processingCounts":[1-9]' 48 | ] 49 | 50 | 51 | 52 | === TEST 2: /status/control?cmd=delete&group=filter&zone=protocol@TCP 53 | --- main_config 54 | stream { 55 | server_traffic_status_zone; 56 | upstream backend { 57 | server localhost:1984; 58 | } 59 | server { 60 | listen 1985; 61 | server_traffic_status_filter_by_set_key $protocol protocol; 62 | proxy_pass backend; 63 | } 64 | } 65 | --- http_config 66 | stream_server_traffic_status_zone; 67 | --- config 68 | location /status { 69 | stream_server_traffic_status_display; 70 | stream_server_traffic_status_display_format json; 71 | access_log off; 72 | } 73 | location /stream { 74 | proxy_pass http://localhost:1985/return; 75 | } 76 | --- user_files eval 77 | [ 78 | ['return/file.txt' => '{"return":"OK"}'] 79 | ] 80 | --- request eval 81 | [ 82 | 'GET /stream/file.txt', 83 | 'GET /status/control?cmd=delete&group=filter&zone=protocol@TCP', 84 | ] 85 | --- response_body_like eval 86 | [ 87 | 'OK', 88 | '"processingCounts":[1-9]' 89 | ] 90 | 91 | 92 | 93 | === TEST 3: /status/control?cmd=delete&group=upstream@group&zone=backend@127.0.0.1:1984 94 | --- main_config 95 | stream { 96 | server_traffic_status_zone; 97 | upstream backend { 98 | server localhost:1984; 99 | } 100 | server { 101 | listen 1985; 102 | server_traffic_status_filter_by_set_key $protocol protocol; 103 | proxy_pass backend; 104 | } 105 | } 106 | --- http_config 107 | stream_server_traffic_status_zone; 108 | --- config 109 | location /status { 110 | stream_server_traffic_status_display; 111 | stream_server_traffic_status_display_format json; 112 | access_log off; 113 | } 114 | location /stream { 115 | proxy_pass http://localhost:1985/return; 116 | } 117 | --- user_files eval 118 | [ 119 | ['return/file.txt' => '{"return":"OK"}'] 120 | ] 121 | --- request eval 122 | [ 123 | 'GET /stream/file.txt', 124 | 'GET /status/control?cmd=delete&group=upstream@group&zone=backend@127.0.0.1:1984', 125 | ] 126 | --- response_body_like eval 127 | [ 128 | 'OK', 129 | '"processingCounts":[1-9]' 130 | ] 131 | 132 | 133 | 134 | === TEST 4: /status/control?cmd=delete&group=upstream@alone&zone=127.0.0.1:1984 135 | --- main_config 136 | stream { 137 | server_traffic_status_zone; 138 | server { 139 | listen 1985; 140 | server_traffic_status_filter_by_set_key $protocol protocol; 141 | proxy_pass localhost:1984; 142 | } 143 | } 144 | --- http_config 145 | stream_server_traffic_status_zone; 146 | --- config 147 | location /status { 148 | stream_server_traffic_status_display; 149 | stream_server_traffic_status_display_format json; 150 | access_log off; 151 | } 152 | location /stream { 153 | proxy_pass http://localhost:1985/return; 154 | } 155 | --- user_files eval 156 | [ 157 | ['return/file.txt' => '{"return":"OK"}'] 158 | ] 159 | --- request eval 160 | [ 161 | 'GET /stream/file.txt', 162 | 'GET /status/control?cmd=delete&group=upstream@alone&zone=127.0.0.1:1984', 163 | ] 164 | --- response_body_like eval 165 | [ 166 | 'OK', 167 | '"processingCounts":[1-9]' 168 | ] 169 | -------------------------------------------------------------------------------- /util/fileToHex.pl: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env perl 2 | # 3 | # @file: fileToHex.pl 4 | # @brief: 5 | # @author: YoungJoo.Kim 6 | # @version: 7 | # @date: 8 | 9 | package FileToHex; 10 | 11 | use strict; 12 | use Carp; 13 | 14 | sub new{ 15 | my($class, %cnf) = @_; 16 | 17 | my $path = delete $cnf{path}; 18 | my $handle = delete $cnf{handle}; 19 | 20 | my $self = 21 | bless { 22 | path => $path, 23 | handle => $handle 24 | }, $class; 25 | 26 | return bless $self; 27 | } 28 | 29 | sub __exit { 30 | my $self = shift if ref ($_[0]); 31 | my $res = shift; 32 | Carp::carp __PACKAGE__ . ": $res->{string}"; 33 | exit($res->{return} || 1); 34 | } 35 | 36 | sub fileOpen { 37 | my $self = shift if ref ($_[0]); 38 | my $path = shift || $self->{path}; 39 | $path = $self->{path} unless defined $path; 40 | (defined $path && -e $path) || $self->__exit({string => "error: [$path] is not defined or exists!"}); 41 | open(my $handle, "<", $path) || $self->__exit({string => "error: open(): $!"}); 42 | $self->{handle} = $handle; 43 | return $self->{handle}; 44 | } 45 | 46 | sub fileClose { 47 | my $self = shift if ref ($_[0]); 48 | my $handle = shift || $self->{handle}; 49 | $handle && close($handle); 50 | } 51 | 52 | sub fileReadByte { 53 | my $self = shift if ref ($_[0]); 54 | my $buf = \shift; 55 | my $byte = shift || 1; 56 | my $handle = shift || $self->{handle}; 57 | return read($handle, $$buf, $byte); 58 | } 59 | 60 | sub DESTROY { 61 | my $self = shift if ref ($_[0]); 62 | $self->fileClose(); 63 | } 64 | 65 | 1; 66 | 67 | package main; 68 | 69 | if ($#ARGV < 0) { 70 | print "Usage: $0 {path} {max} {type}\n"; 71 | exit(2); 72 | } 73 | 74 | my $path = $ARGV[0]; 75 | my $max = $ARGV[1] || 16; 76 | my $type = $ARGV[2] || "buffer"; 77 | my $plus = ""; 78 | my $buf = ""; 79 | my $i = 0; 80 | my $fth = FileToHex->new(path => $path); 81 | 82 | $fth->fileOpen(); 83 | if ($type eq "define") { 84 | # type: define 85 | while($fth->fileReadByte(my $c)) { 86 | $i++; 87 | $buf .= '\x' . unpack("H2", $c); 88 | if (!($i % $max)) { 89 | $plus .= "\"$buf\" \\\n"; 90 | $buf = ""; 91 | } 92 | } 93 | 94 | if (!($i % $max)) { 95 | print substr($plus, 0, -3) . "\n"; 96 | 97 | } else { 98 | print $plus . "\"$buf\"\n"; 99 | } 100 | 101 | } else { 102 | # type: buffer 103 | while($fth->fileReadByte(my $c)) { 104 | $i++; 105 | $buf .= '0x' . unpack("H2", $c) . ', '; 106 | if (!($i % $max)) { 107 | $plus .= "$buf\n"; 108 | $buf = ""; 109 | } 110 | } 111 | 112 | if (!($i % $max)) { 113 | print $plus . "0x00\n"; 114 | 115 | } else { 116 | print $plus . $buf . "0x00\n"; 117 | } 118 | } 119 | $fth->fileClose(); 120 | 121 | # vi:set ft=perl ts=4 sw=4 et fdm=marker: 122 | -------------------------------------------------------------------------------- /util/tplToBuffer.sh: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | # 3 | # @file: tplToDefine.sh 4 | # @brief: 5 | # @author: YoungJoo.Kim 6 | # @version: 7 | # @date: 8 | 9 | # Set up a default search path. 10 | PATH="/sbin:/usr/sbin:/bin:/usr/bin" 11 | export PATH 12 | 13 | template=$1 14 | if [ -z "$template" ]; then 15 | echo "Usage: $0 {template.html}" 16 | exit 2 17 | fi 18 | 19 | tmp=$template.$(date '+%s') 20 | 21 | \cp -af $template $tmp 22 | 23 | if [ -f "$tmp" ]; then 24 | perl -p -i -e 's/%/%%/g' $tmp 25 | perl -p -i -e 's/{{uri}}/%V/g' $tmp 26 | fi 27 | 28 | echo "static char NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_HTML_DATA[] = {" 29 | 30 | \perl fileToHex.pl $tmp 16 buffer 31 | 32 | echo "};" 33 | 34 | \rm -f $tmp 35 | 36 | # vi:set ft=sh ts=4 sw=4 et fdm=marker: 37 | -------------------------------------------------------------------------------- /util/tplToDefine.sh: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | # 3 | # @file: tplToDefine.sh 4 | # @brief: 5 | # @author: YoungJoo.Kim 6 | # @version: 7 | # @date: 8 | 9 | # Set up a default search path. 10 | PATH="/sbin:/usr/sbin:/bin:/usr/bin" 11 | export PATH 12 | 13 | template=$1 14 | if [ -z "$template" ]; then 15 | echo "Usage: $0 {template.html}" 16 | exit 2 17 | fi 18 | 19 | tmp=$template.$(date '+%s') 20 | 21 | \cp -af $template $tmp 22 | 23 | if [ -f "$tmp" ]; then 24 | perl -p -i -e 's/%/%%/g' $tmp 25 | perl -p -i -e 's/{{uri}}/%V/g' $tmp 26 | fi 27 | 28 | echo "#define NGX_HTTP_STREAM_SERVER_TRAFFIC_STATUS_HTML_DATA \\" 29 | 30 | \perl fileToHex.pl $tmp 16 define 31 | 32 | \rm -f $tmp 33 | 34 | # vi:set ft=sh ts=4 sw=4 et fdm=marker: 35 | --------------------------------------------------------------------------------