├── README.md ├── config └── ngx_cache_status_module.c /README.md: -------------------------------------------------------------------------------- 1 | # cache_status 2 | 3 | Модуль собирает статистику по кэшированию запросов и предоставляет 4 | доступ к этой статистике. 5 | 6 | ## Сборка 7 | 8 | ``` 9 | ./configure ..... --add-module=PATH_TO_MODULE/ngx_cache_status_module 10 | make 11 | ``` 12 | 13 | ## Директивы 14 | 15 | ``` 16 | Синтаксис: cache_status; 17 | Значение по умолчанию: --- 18 | Контекст: location 19 | ``` 20 | Предоставляет статистику кэширования. 21 | 22 | ## Пример конфигурации 23 | 24 | ``` 25 | location /cache-stat { 26 | cache_status; 27 | } 28 | ``` 29 | 30 | ## Пример данных 31 | 32 | ``` 33 | Cache statistics: 34 | Requests: 15 35 | Uncached: 10 36 | Miss: 2 37 | Bypass: 0 38 | Expired: 1 39 | Stale: 0 40 | Updating: 0 41 | Revalidated: 0 42 | Hit: 2 43 | Misc: 0 44 | ``` -------------------------------------------------------------------------------- /config: -------------------------------------------------------------------------------- 1 | ngx_addon_name=ngx_cache_status_module 2 | HTTP_AUX_FILTER_MODULES="$HTTP_AUX_FILTER_MODULES ngx_cache_status_module" 3 | NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_cache_status_module.c" 4 | -------------------------------------------------------------------------------- /ngx_cache_status_module.c: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Viktor Suprun 4 | */ 5 | 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #define TOTAL_REQUESTS_SLOT 0 12 | #define UNCACHED_REQUESTS_SLOT 1 13 | #define NGX_HTTP_CACHE_MISS_SLOT 2 14 | #define NGX_HTTP_CACHE_BYPASS 3 15 | #define NGX_HTTP_CACHE_EXPIRED 4 16 | #define NGX_HTTP_CACHE_STALE 5 17 | #define NGX_HTTP_CACHE_UPDATING 6 18 | #define NGX_HTTP_CACHE_REVALIDATED 7 19 | #define NGX_HTTP_CACHE_HIT 8 20 | #define MISC_SLOT 9 21 | 22 | static ngx_atomic_uint_t cache_status[] = { 23 | 0, //TOTAL_REQUESTS_SLOT 24 | 0, //UNCACHED_REQUESTS_SLOT 25 | 0, //NGX_HTTP_CACHE_MISS, 26 | 0, //NGX_HTTP_CACHE_BYPASS 27 | 0, //NGX_HTTP_CACHE_EXPIRED 28 | 0, //NGX_HTTP_CACHE_STALE 29 | 0, //NGX_HTTP_CACHE_UPDATING 30 | 0, //NGX_HTTP_CACHE_REVALIDATED 31 | 0, //NGX_HTTP_CACHE_HIT 32 | 0 //MISC_SLOT 33 | }; 34 | 35 | static ngx_http_output_header_filter_pt ngx_original_filter_ptr; 36 | 37 | static char *ngx_set_status(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); 38 | static ngx_int_t ngx_cache_status_filter(ngx_http_request_t *r); 39 | static ngx_int_t ngx_cache_status_filter_init(ngx_conf_t *cf); 40 | 41 | static ngx_command_t ngx_status_commands[] = { 42 | 43 | { ngx_string("cache_status"), 44 | NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS|NGX_CONF_TAKE1, 45 | ngx_set_status, 46 | 0, 47 | 0, 48 | NULL }, 49 | 50 | ngx_null_command 51 | }; 52 | 53 | 54 | static ngx_http_module_t ngx_cache_status_module_ctx = { 55 | NULL, /* preconfiguration */ 56 | ngx_cache_status_filter_init, /* postconfiguration */ 57 | 58 | NULL, /* create main configuration */ 59 | NULL, /* init main configuration */ 60 | 61 | NULL, /* create server configuration */ 62 | NULL, /* merge server configuration */ 63 | 64 | NULL, /* create location configuration */ 65 | NULL /* merge location configuration */ 66 | }; 67 | 68 | 69 | ngx_module_t ngx_cache_status_module = { 70 | NGX_MODULE_V1, 71 | &ngx_cache_status_module_ctx, /* module context */ 72 | ngx_status_commands, /* module directives */ 73 | NGX_HTTP_MODULE, /* module type */ 74 | NULL, /* init master */ 75 | NULL, /* init module */ 76 | NULL, /* init process */ 77 | NULL, /* init thread */ 78 | NULL, /* exit thread */ 79 | NULL, /* exit process */ 80 | NULL, /* exit master */ 81 | NGX_MODULE_V1_PADDING 82 | }; 83 | 84 | static ngx_int_t ngx_status_handler(ngx_http_request_t *r) 85 | { 86 | size_t size; 87 | ngx_int_t rc; 88 | ngx_buf_t *b; 89 | ngx_chain_t out; 90 | 91 | if (r->method != NGX_HTTP_GET && r->method != NGX_HTTP_HEAD) { 92 | return NGX_HTTP_NOT_ALLOWED; 93 | } 94 | 95 | rc = ngx_http_discard_request_body(r); 96 | 97 | if (rc != NGX_OK) { 98 | return rc; 99 | } 100 | 101 | r->headers_out.content_type_len = sizeof("text/plain") - 1; 102 | ngx_str_set(&r->headers_out.content_type, "text/plain"); 103 | r->headers_out.content_type_lowcase = NULL; 104 | 105 | if (r->method == NGX_HTTP_HEAD) { 106 | r->headers_out.status = NGX_HTTP_OK; 107 | 108 | rc = ngx_http_send_header(r); 109 | 110 | if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { 111 | return rc; 112 | } 113 | } 114 | 115 | size = sizeof("Cache statistics:\n") 116 | + sizeof("Requests: \n") + NGX_ATOMIC_T_LEN 117 | + sizeof("Uncached: \n") + NGX_ATOMIC_T_LEN 118 | + sizeof("Miss: \n") + NGX_ATOMIC_T_LEN 119 | + sizeof("Bypass: \n") + NGX_ATOMIC_T_LEN 120 | + sizeof("Expired: \n") + NGX_ATOMIC_T_LEN 121 | + sizeof("Stale: \n") + NGX_ATOMIC_T_LEN 122 | + sizeof("Updating: \n") + NGX_ATOMIC_T_LEN 123 | + sizeof("Revalidated: \n") + NGX_ATOMIC_T_LEN 124 | + sizeof("Hit: \n") + NGX_ATOMIC_T_LEN 125 | + sizeof("Misc: ") + NGX_ATOMIC_T_LEN; 126 | 127 | b = ngx_create_temp_buf(r->pool, size); 128 | if (b == NULL) { 129 | return NGX_HTTP_INTERNAL_SERVER_ERROR; 130 | } 131 | 132 | out.buf = b; 133 | out.next = NULL; 134 | 135 | b->last = ngx_cpymem(b->last, "Cache statistics:\n", 136 | sizeof("Cache statistics:\n") - 1); 137 | b->last = ngx_sprintf(b->last, "Requests: %uA\n", cache_status[0]); 138 | b->last = ngx_sprintf(b->last, "Uncached: %uA\n", cache_status[1]); 139 | b->last = ngx_sprintf(b->last, "Miss: %uA\n", cache_status[2]); 140 | b->last = ngx_sprintf(b->last, "Bypass: %uA\n", cache_status[3]); 141 | b->last = ngx_sprintf(b->last, "Expired: %uA\n", cache_status[4]); 142 | b->last = ngx_sprintf(b->last, "Stale: %uA\n", cache_status[5]); 143 | b->last = ngx_sprintf(b->last, "Updating: %uA\n", cache_status[6]); 144 | b->last = ngx_sprintf(b->last, "Revalidated: %uA\n", cache_status[7]); 145 | b->last = ngx_sprintf(b->last, "Hit: %uA\n", cache_status[8]); 146 | b->last = ngx_sprintf(b->last, "Misc: %uA", cache_status[9]); 147 | 148 | r->headers_out.status = NGX_HTTP_OK; 149 | r->headers_out.content_length_n = b->last - b->pos; 150 | 151 | b->last_buf = (r == r->main) ? 1 : 0; 152 | b->last_in_chain = 1; 153 | 154 | rc = ngx_http_send_header(r); 155 | 156 | if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { 157 | return rc; 158 | } 159 | 160 | return ngx_http_output_filter(r, &out); 161 | } 162 | 163 | static char *ngx_set_status(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 164 | { 165 | ngx_http_core_loc_conf_t *clcf; 166 | 167 | clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); 168 | clcf->handler = ngx_status_handler; 169 | 170 | return NGX_CONF_OK; 171 | } 172 | 173 | static ngx_int_t ngx_cache_status_filter_init(ngx_conf_t *cf) 174 | { 175 | ngx_original_filter_ptr = ngx_http_top_header_filter; 176 | ngx_http_top_header_filter = ngx_cache_status_filter; 177 | 178 | return NGX_OK; 179 | } 180 | 181 | static ngx_int_t ngx_cache_status_filter(ngx_http_request_t *r) 182 | { 183 | cache_status[TOTAL_REQUESTS_SLOT]++; 184 | #if (NGX_HTTP_CACHE) 185 | if (r->upstream == NULL || r->upstream->cache_status == 0) { 186 | cache_status[UNCACHED_REQUESTS_SLOT]++; 187 | return ngx_original_filter_ptr(r); 188 | } 189 | 190 | if (r->upstream->cache_status > 7) { //greater than NGX_HTTP_CACHE_HIT 191 | cache_status[MISC_SLOT]++; 192 | } else { 193 | cache_status[r->upstream->cache_status+1]++; 194 | } 195 | #else 196 | cache_status[UNCACHED_REQUESTS_SLOT]++; 197 | #endif 198 | 199 | return ngx_original_filter_ptr(r); 200 | } --------------------------------------------------------------------------------