PageRenderTime 51ms CodeModel.GetById 6ms RepoModel.GetById 1ms app.codeStats 0ms

/trafficserver-3.2.0/contrib/tstop/src/stats.h

#
C Header | 380 lines | 284 code | 56 blank | 40 comment | 84 complexity | 2f07a694978f7c018d0ef266a69da37d MD5 | raw file
Possible License(s): Apache-2.0
  1. /** @file
  2. Include file for the tstop stats.
  3. @section license License
  4. Licensed to the Apache Software Foundation (ASF) under one
  5. or more contributor license agreements. See the NOTICE file
  6. distributed with this work for additional information
  7. regarding copyright ownership. The ASF licenses this file
  8. to you under the Apache License, Version 2.0 (the
  9. "License"); you may not use this file except in compliance
  10. with the License. You may obtain a copy of the License at
  11. http://www.apache.org/licenses/LICENSE-2.0
  12. Unless required by applicable law or agreed to in writing, software
  13. distributed under the License is distributed on an "AS IS" BASIS,
  14. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. See the License for the specific language governing permissions and
  16. limitations under the License.
  17. */
  18. #include <curl/curl.h>
  19. #include <map>
  20. #include <string>
  21. #include <sys/types.h>
  22. #include <sys/stat.h>
  23. #include <fcntl.h>
  24. //#include <ts/ts.h>
  25. #include <inttypes.h>
  26. #include <ts/mgmtapi.h>
  27. using namespace std;
  28. struct LookupItem {
  29. LookupItem(const char *s, const char *n, const int t): pretty(s), name(n), type(t) {}
  30. LookupItem(const char *s, const char *n, const char *d, const int t): pretty(s), name(n), numerator(n), denominator(d), type(t) {}
  31. const char *pretty;
  32. const char *name;
  33. const char *numerator;
  34. const char *denominator;
  35. int type;
  36. };
  37. extern size_t write_data(void *ptr, size_t size, size_t nmemb, void *stream);
  38. extern char curl_error[CURL_ERROR_SIZE];
  39. extern string response;
  40. namespace constant {
  41. const char global[] = "\"global\": {\n";
  42. const char start[] = "\"proxy.process.";
  43. const char seperator[] = "\": \"";
  44. const char end[] = "\",\n";
  45. };
  46. //----------------------------------------------------------------------------
  47. class Stats {
  48. public:
  49. Stats(const string &host) {
  50. _host = host;
  51. _stats = NULL;
  52. _old_stats = NULL;
  53. _absolute = false;
  54. lookup_table.insert(make_pair("version", LookupItem("Version", "proxy.process.version.server.short", 1)));
  55. lookup_table.insert(make_pair("disk_used", LookupItem("Disk Used", "proxy.process.cache.bytes_used", 1)));
  56. lookup_table.insert(make_pair("disk_total", LookupItem("Disk Total", "proxy.process.cache.bytes_total", 1)));
  57. lookup_table.insert(make_pair("ram_used", LookupItem("Ram Used", "proxy.process.cache.ram_cache.bytes_used", 1)));
  58. lookup_table.insert(make_pair("ram_total", LookupItem("Ram Total", "proxy.process.cache.ram_cache.total_bytes", 1)));
  59. lookup_table.insert(make_pair("lookups", LookupItem("Lookups", "proxy.process.http.cache_lookups", 2)));
  60. lookup_table.insert(make_pair("cache_writes", LookupItem("Writes", "proxy.process.http.cache_writes", 2)));
  61. lookup_table.insert(make_pair("cache_updates", LookupItem("Updates", "proxy.process.http.cache_updates", 2)));
  62. lookup_table.insert(make_pair("cache_deletes", LookupItem("Deletes", "proxy.process.http.cache_deletes", 2)));
  63. lookup_table.insert(make_pair("read_active", LookupItem("Read Active", "proxy.process.cache.read.active", 1)));
  64. lookup_table.insert(make_pair("write_active", LookupItem("Writes Active", "proxy.process.cache.write.active", 1)));
  65. lookup_table.insert(make_pair("update_active", LookupItem("Update Active", "proxy.process.cache.update.active", 1)));
  66. lookup_table.insert(make_pair("entries", LookupItem("Entries", "proxy.process.cache.direntries.used", 1)));
  67. lookup_table.insert(make_pair("avg_size", LookupItem("Avg Size", "disk_total", "entries", 3)));
  68. lookup_table.insert(make_pair("client_req", LookupItem("Requests", "proxy.process.http.incoming_requests", 2)));
  69. lookup_table.insert(make_pair("client_conn", LookupItem("New Conn", "proxy.process.http.total_client_connections", 2)));
  70. lookup_table.insert(make_pair("client_req_conn", LookupItem("Req/Conn", "client_req", "client_conn", 3)));
  71. lookup_table.insert(make_pair("client_curr_conn", LookupItem("Curr Conn", "proxy.process.http.current_client_connections", 1)));
  72. lookup_table.insert(make_pair("client_actv_conn", LookupItem("Active Con", "proxy.process.http.current_active_client_connections", 1)));
  73. lookup_table.insert(make_pair("server_req", LookupItem("Requests", "proxy.process.http.outgoing_requests", 2)));
  74. lookup_table.insert(make_pair("server_conn", LookupItem("New Conn", "proxy.process.http.total_server_connections", 2)));
  75. lookup_table.insert(make_pair("server_req_conn", LookupItem("Req/Conn", "server_req", "server_conn", 3)));
  76. lookup_table.insert(make_pair("server_curr_conn", LookupItem("Curr Conn", "proxy.process.http.current_server_connections", 1)));
  77. lookup_table.insert(make_pair("client_head", LookupItem("Head Bytes", "proxy.process.http.user_agent_response_header_total_size", 2)));
  78. lookup_table.insert(make_pair("client_body", LookupItem("Body Bytes", "proxy.process.http.user_agent_response_document_total_size", 2)));
  79. lookup_table.insert(make_pair("server_head", LookupItem("Head Bytes", "proxy.process.http.origin_server_response_header_total_size", 2)));
  80. lookup_table.insert(make_pair("server_body", LookupItem("Body Bytes", "proxy.process.http.origin_server_response_document_total_size", 2)));
  81. // not used directly
  82. lookup_table.insert(make_pair("ram_hit", LookupItem("Ram Hit", "proxy.process.cache.ram_cache.hits", 2)));
  83. lookup_table.insert(make_pair("ram_miss", LookupItem("Ram Misses", "proxy.process.cache.ram_cache.misses", 2)));
  84. lookup_table.insert(make_pair("client_abort", LookupItem("Clnt Abort", "proxy.process.http.err_client_abort_count_stat", 2)));
  85. lookup_table.insert(make_pair("conn_fail", LookupItem("Conn Fail", "proxy.process.http.err_connect_fail_count_stat", 2)));
  86. lookup_table.insert(make_pair("abort", LookupItem("Abort", "proxy.process.http.transaction_counts.errors.aborts", 2)));
  87. lookup_table.insert(make_pair("t_conn_fail", LookupItem("Conn Fail", "proxy.process.http.transaction_counts.errors.connect_failed", 2)));
  88. lookup_table.insert(make_pair("other_err", LookupItem("Other Err", "proxy.process.http.transaction_counts.errors.other", 2)));
  89. // percentage
  90. lookup_table.insert(make_pair("ram_ratio", LookupItem("Ram Hit", "ram_hit", "ram_hit_miss", 4)));
  91. // percetage of requests
  92. lookup_table.insert(make_pair("fresh", LookupItem("Fresh", "proxy.process.http.transaction_counts.hit_fresh", 5)));
  93. lookup_table.insert(make_pair("reval", LookupItem("Revalidate", "proxy.process.http.transaction_counts.hit_revalidated", 5)));
  94. lookup_table.insert(make_pair("cold", LookupItem("Cold", "proxy.process.http.transaction_counts.miss_cold", 5)));
  95. lookup_table.insert(make_pair("changed", LookupItem("Changed", "proxy.process.http.transaction_counts.miss_changed", 5)));
  96. lookup_table.insert(make_pair("not", LookupItem("Not Cache", "proxy.process.http.transaction_counts.miss_not_cacheable", 5)));
  97. lookup_table.insert(make_pair("no", LookupItem("No Cache", "proxy.process.http.transaction_counts.miss_client_no_cache", 5)));
  98. lookup_table.insert(make_pair("fresh_time", LookupItem("Fresh (ms)", "proxy.process.http.transaction_totaltime.hit_fresh", "fresh", 8)));
  99. lookup_table.insert(make_pair("reval_time", LookupItem("Reval (ms)", "proxy.process.http.transaction_totaltime.hit_revalidated", "reval", 8)));
  100. lookup_table.insert(make_pair("cold_time", LookupItem("Cold (ms)", "proxy.process.http.transaction_totaltime.miss_cold", "cold", 8)));
  101. lookup_table.insert(make_pair("changed_time", LookupItem("Chang (ms)", "proxy.process.http.transaction_totaltime.miss_changed", "changed", 8)));
  102. lookup_table.insert(make_pair("not_time", LookupItem("Not (ms)", "proxy.process.http.transaction_totaltime.miss_not_cacheable", "not", 8)));
  103. lookup_table.insert(make_pair("no_time", LookupItem("No (no)", "proxy.process.http.transaction_totaltime.miss_client_no_cache", "no", 8)));
  104. lookup_table.insert(make_pair("get", LookupItem("GET", "proxy.process.http.get_requests", 5)));
  105. lookup_table.insert(make_pair("head", LookupItem("HEAD", "proxy.process.http.head_requests", 5)));
  106. lookup_table.insert(make_pair("post", LookupItem("POST", "proxy.process.http.post_requests", 5)));
  107. lookup_table.insert(make_pair("2xx", LookupItem("2xx", "proxy.process.http.2xx_responses", 5)));
  108. lookup_table.insert(make_pair("3xx", LookupItem("3xx", "proxy.process.http.3xx_responses", 5)));
  109. lookup_table.insert(make_pair("4xx", LookupItem("4xx", "proxy.process.http.4xx_responses", 5)));
  110. lookup_table.insert(make_pair("5xx", LookupItem("5xx", "proxy.process.http.5xx_responses", 5)));
  111. lookup_table.insert(make_pair("200", LookupItem("200", "proxy.process.http.200_responses", 5)));
  112. lookup_table.insert(make_pair("206", LookupItem("206", "proxy.process.http.206_responses", 5)));
  113. lookup_table.insert(make_pair("301", LookupItem("301", "proxy.process.http.301_responses", 5)));
  114. lookup_table.insert(make_pair("302", LookupItem("302", "proxy.process.http.302_responses", 5)));
  115. lookup_table.insert(make_pair("304", LookupItem("304", "proxy.process.http.304_responses", 5)));
  116. lookup_table.insert(make_pair("404", LookupItem("404", "proxy.process.http.404_responses", 5)));
  117. lookup_table.insert(make_pair("502", LookupItem("502", "proxy.process.http.502_responses", 5)));
  118. lookup_table.insert(make_pair("s_100", LookupItem("100 B", "proxy.process.http.response_document_size_100", 5)));
  119. lookup_table.insert(make_pair("s_1k", LookupItem("1 KB", "proxy.process.http.response_document_size_1K", 5)));
  120. lookup_table.insert(make_pair("s_3k", LookupItem("3 KB", "proxy.process.http.response_document_size_3K", 5)));
  121. lookup_table.insert(make_pair("s_5k", LookupItem("5 KB", "proxy.process.http.response_document_size_5K", 5)));
  122. lookup_table.insert(make_pair("s_10k", LookupItem("10 KB", "proxy.process.http.response_document_size_10K", 5)));
  123. lookup_table.insert(make_pair("s_1m", LookupItem("1 MB", "proxy.process.http.response_document_size_1M", 5)));
  124. lookup_table.insert(make_pair("s_>1m", LookupItem("> 1 MB", "proxy.process.http.response_document_size_inf", 5)));
  125. // sum together
  126. lookup_table.insert(make_pair("ram_hit_miss", LookupItem("Ram Hit+Miss", "ram_hit", "ram_miss", 6)));
  127. lookup_table.insert(make_pair("client_net", LookupItem("Net (bits)", "client_head", "client_body", 7)));
  128. lookup_table.insert(make_pair("client_size", LookupItem("Total Size", "client_head", "client_body", 6)));
  129. lookup_table.insert(make_pair("client_avg_size", LookupItem("Avg Size", "client_size", "client_req", 3)));
  130. lookup_table.insert(make_pair("server_net", LookupItem("Net (bits)", "server_head", "server_body", 7)));
  131. lookup_table.insert(make_pair("server_size", LookupItem("Total Size", "server_head", "server_body", 6)));
  132. lookup_table.insert(make_pair("server_avg_size", LookupItem("Avg Size", "server_size", "server_req", 3)));
  133. lookup_table.insert(make_pair("total_time", LookupItem("Total Time", "proxy.process.http.total_transactions_time", 2)));
  134. lookup_table.insert(make_pair("client_req_time", LookupItem("Resp (ms)", "total_time", "client_req", 3)));
  135. }
  136. void getStats() {
  137. if (_host == "") {
  138. int64_t value;
  139. if (_old_stats != NULL) {
  140. delete _old_stats;
  141. _old_stats = NULL;
  142. }
  143. _old_stats = _stats;
  144. _stats = new map<string, string>;
  145. gettimeofday(&_time, NULL);
  146. double now = _time.tv_sec + (double)_time.tv_usec / 1000000;
  147. for (map<string, LookupItem>::const_iterator lookup_it = lookup_table.begin();
  148. lookup_it != lookup_table.end(); ++lookup_it) {
  149. const LookupItem &item = lookup_it->second;
  150. if (item.type == 1 || item.type == 2 || item.type == 5 || item.type == 8) {
  151. assert(TSRecordGetInt(item.name, &value) == TS_ERR_OKAY);
  152. //cerr << "name" << item.name << " value: " << value << endl;
  153. string key = item.name;
  154. char buffer[32];
  155. sprintf(buffer, "%lld", value);
  156. string foo = buffer;
  157. (*_stats)[key] = foo;
  158. }
  159. }
  160. _old_time = _now;
  161. _now = now;
  162. _time_diff = _now - _old_time;
  163. } else {
  164. CURL *curl;
  165. CURLcode res;
  166. curl = curl_easy_init();
  167. if (curl) {
  168. string url = "http://" + _host + "/_stats";
  169. curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
  170. curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
  171. curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, curl_error);
  172. // update time
  173. gettimeofday(&_time, NULL);
  174. double now = _time.tv_sec + (double)_time.tv_usec / 1000000;
  175. response.clear();
  176. response.reserve(32768); // should hopefully be smaller then 32KB
  177. res = curl_easy_perform(curl);
  178. // only if success update stats and time information
  179. if (res == 0) {
  180. if (_old_stats != NULL) {
  181. delete _old_stats;
  182. _old_stats = NULL;
  183. }
  184. _old_stats = _stats;
  185. _stats = new map<string, string>;
  186. // parse
  187. parseResponse(response);
  188. _old_time = _now;
  189. _now = now;
  190. _time_diff = _now - _old_time;
  191. }
  192. /* always cleanup */
  193. curl_easy_cleanup(curl);
  194. }
  195. }
  196. }
  197. int64_t getValue(const string &key, const map<string, string> *stats) const {
  198. map<string, string>::const_iterator stats_it = stats->find(key);
  199. assert(stats_it != stats->end());
  200. int64_t value = atoll(stats_it->second.c_str());
  201. return value;
  202. }
  203. void getStat(const string &key, double &value, int overrideType = 0) {
  204. string strtmp;
  205. int typetmp;
  206. getStat(key, value, strtmp, typetmp, overrideType);
  207. }
  208. void getStat(const string &key, string &value) {
  209. map<string, LookupItem>::const_iterator lookup_it = lookup_table.find(key);
  210. assert(lookup_it != lookup_table.end());
  211. const LookupItem &item = lookup_it->second;
  212. map<string, string>::const_iterator stats_it = _stats->find(item.name);
  213. assert(stats_it != _stats->end());
  214. value = stats_it->second.c_str();
  215. }
  216. void getStat(const string &key, double &value, string &prettyName, int &type, int overrideType = 0) {
  217. map<string, LookupItem>::const_iterator lookup_it = lookup_table.find(key);
  218. assert(lookup_it != lookup_table.end());
  219. const LookupItem &item = lookup_it->second;
  220. prettyName = item.pretty;
  221. if (overrideType != 0)
  222. type = overrideType;
  223. else
  224. type = item.type;
  225. if (type == 1 || type == 2 || type == 5 || type == 8) {
  226. value = getValue(item.name, _stats);
  227. if (key == "total_time") {
  228. value = value / 10000000;
  229. }
  230. if ((type == 2 || type == 5 || type == 8) && _old_stats != NULL && _absolute == false) {
  231. double old = getValue(item.name, _old_stats);
  232. if (key == "total_time") {
  233. old = old / 10000000;
  234. }
  235. value = (value - old) / _time_diff;
  236. }
  237. } else if (type == 3 || type == 4) {
  238. double numerator;
  239. double denominator;
  240. getStat(item.numerator, numerator);
  241. getStat(item.denominator, denominator);
  242. if (denominator == 0)
  243. value = 0;
  244. else
  245. value = numerator / denominator;
  246. if (type == 4) {
  247. value *= 100;
  248. }
  249. } else if (type == 6 || type == 7) {
  250. double numerator;
  251. double denominator;
  252. getStat(item.numerator, numerator, 2);
  253. getStat(item.denominator, denominator, 2);
  254. value = numerator + denominator;
  255. if (type == 7)
  256. value *= 8;
  257. }
  258. if (type == 8) {
  259. double denominator;
  260. getStat(item.denominator, denominator, 2);
  261. if (denominator == 0)
  262. value = 0;
  263. else
  264. value = value / denominator * 1000;
  265. }
  266. if (type == 5) {
  267. double denominator;
  268. getStat("client_req", denominator);
  269. value = value / denominator * 100;
  270. }
  271. }
  272. bool toggleAbsolute() {
  273. if (_absolute == true)
  274. _absolute = false;
  275. else
  276. _absolute = true;
  277. return _absolute;
  278. }
  279. void parseResponse(const string &response) {
  280. // move past global
  281. size_t pos = response.find(constant::global);
  282. pos += sizeof(constant::global) - 1;
  283. // find parts of the line
  284. while (1) {
  285. size_t start = response.find(constant::start, pos);
  286. size_t seperator = response.find(constant::seperator, pos);
  287. size_t end = response.find(constant::end, pos);
  288. if (start == string::npos || seperator == string::npos || end == string::npos)
  289. return;
  290. //cout << constant::start << " " << start << endl;
  291. //cout << constant::seperator << " " << seperator << endl;
  292. //cout << constant::end << " " << end << endl;
  293. string key = response.substr(start + 1, seperator - start - 1);
  294. string value = response.substr(seperator + sizeof(constant::seperator) - 1, end - seperator - sizeof(constant::seperator) + 1);
  295. (*_stats)[key] = value;
  296. //cout << "key " << key << " " << "value " << value << endl;
  297. pos = end + sizeof(constant::end) - 1;
  298. //cout << "pos: " << pos << endl;
  299. }
  300. }
  301. ~Stats() {
  302. if (_stats != NULL) {
  303. delete _stats;
  304. }
  305. if (_old_stats != NULL) {
  306. delete _old_stats;
  307. }
  308. }
  309. private:
  310. map<string, string> *_stats;
  311. map<string, string> *_old_stats;
  312. map<string, LookupItem> lookup_table;
  313. string _host;
  314. double _old_time;
  315. double _now;
  316. double _time_diff;
  317. struct timeval _time;
  318. bool _absolute;
  319. };