PageRenderTime 54ms CodeModel.GetById 0ms RepoModel.GetById 0ms app.codeStats 0ms

/trafficserver-3.2.0/contrib/tstop/tstop

#
Perl | 460 lines | 438 code | 5 blank | 17 comment | 0 complexity | 1ef62107c8d956a8ac9914bacfa2f197 MD5 | raw file
Possible License(s): Apache-2.0
  1. #!/usr/bin/perl
  2. # Licensed to the Apache Software Foundation (ASF) under one
  3. # or more contributor license agreements. See the NOTICE file
  4. # distributed with this work for additional information
  5. # regarding copyright ownership. The ASF licenses this file
  6. # to you under the Apache License, Version 2.0 (the
  7. # "License"); you may not use this file except in compliance
  8. # with the License. You may obtain a copy of the License at
  9. #
  10. # http://www.apache.org/licenses/LICENSE-2.0
  11. #
  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. use strict;
  18. use warnings;
  19. use JSON;
  20. use LWP::Simple;
  21. use Data::Dumper;
  22. use Curses;
  23. use Getopt::Std;
  24. #open(LOG, ">/tmp/tstop.log");
  25. my $sleep = 5;
  26. my $server;
  27. my $os; # old stats
  28. my $w;
  29. my %lookup = (
  30. disk_total => { name => "Disk Total",
  31. stat => "proxy.process.cache.bytes_total",
  32. type => "sum",
  33. },
  34. disk_used => { name => "Disk Used",
  35. stat => "proxy.process.cache.bytes_used",
  36. type => "sum",
  37. },
  38. ram_total => { name => "Ram Total",
  39. stat => "proxy.process.cache.ram_cache.total_bytes",
  40. type => "sum",
  41. },
  42. ram_used => { name => "Ram Used",
  43. stat => "proxy.process.cache.ram_cache.bytes_used",
  44. type => "sum",
  45. },
  46. cache_lookup => { name => "Lookups",
  47. stat => "proxy.process.http.cache_lookups",
  48. },
  49. cache_writes => { name => "Writes",
  50. stat => "proxy.process.http.cache_writes",
  51. },
  52. cache_updates => { name => "Updates",
  53. stat => "proxy.process.http.cache_updates",
  54. },
  55. cache_deletes => { name => "Deletes",
  56. stat => "proxy.process.http.cache_deletes",
  57. },
  58. cache_read_active => { name => "Read Activ",
  59. stat => "proxy.process.cache.read.active",
  60. type => "sum",
  61. },
  62. cache_write_active => { name => "Write Acti",
  63. stat => "proxy.process.cache.write.active",
  64. type => "sum",
  65. },
  66. cache_update_active => { name => "Update Act",
  67. stat => "proxy.process.cache.update.active",
  68. type => "sum",
  69. },
  70. get => { name => "GET",
  71. stat => "proxy.process.http.get_requests",
  72. type => 'percent'
  73. },
  74. head => { name => "HEAD",
  75. stat => "proxy.process.http.head_requests",
  76. type => 'percent'
  77. },
  78. post => { name => "POST",
  79. stat => "proxy.process.http.post_requests",
  80. type => 'percent'
  81. },
  82. '2xx' => { name => "2xx",
  83. stat => "proxy.process.http.2xx_responses",
  84. type => 'percent'
  85. },
  86. '200' => { name => "200",
  87. stat => "proxy.process.http.200_responses",
  88. type => 'percent'
  89. },
  90. '206' => { name => "206",
  91. stat => "proxy.process.http.206_responses",
  92. type => 'percent'
  93. },
  94. '3xx' => { name => "3xx",
  95. stat => "proxy.process.http.3xx_responses",
  96. type => 'percent'
  97. },
  98. '301' => { name => "301",
  99. stat => "proxy.process.http.301_responses",
  100. type => 'percent'
  101. },
  102. '302' => { name => "302",
  103. stat => "proxy.process.http.302_responses",
  104. type => 'percent'
  105. },
  106. '304' => { name => "304",
  107. stat => "proxy.process.http.304_responses",
  108. type => 'percent'
  109. },
  110. '4xx' => { name => "4xx",
  111. stat => "proxy.process.http.4xx_responses",
  112. type => 'percent'
  113. },
  114. '404' => { name => "404",
  115. stat => "proxy.process.http.404_responses",
  116. type => 'percent'
  117. },
  118. '5xx' => { name => "5xx",
  119. stat => "proxy.process.http.5xx_responses",
  120. type => 'percent'
  121. },
  122. '502' => { name => "502",
  123. stat => "proxy.process.http.502_responses",
  124. type => 'percent'
  125. },
  126. client_req => { name => "Requests",
  127. stat => "proxy.process.http.incoming_requests",
  128. },
  129. mean_req_size => { name => "Avg Size",
  130. },
  131. mean_res_size => { name => "Avg Size",
  132. },
  133. client_req_time => { name => "Resp (ms)",
  134. },
  135. server_req_time => { name => "Resp (ms)",
  136. },
  137. client_req_conn => { name => "Req/Conn",
  138. },
  139. client_conn => { name => "New Conn",
  140. stat => "proxy.process.http.total_client_connections",
  141. },
  142. client_cconn => { name => "Curr Conn",
  143. stat => "proxy.process.http.current_client_connections",
  144. type => "sum",
  145. },
  146. client_aconn => { name => "Active Con",
  147. stat => "proxy.process.http.current_active_client_connections",
  148. type => "sum",
  149. },
  150. client_head => { name => "Head Bytes",
  151. stat => "proxy.process.http.user_agent_response_header_total_size",
  152. },
  153. client_body => { name => "Body Bytes",
  154. stat => "proxy.process.http.user_agent_response_document_total_size",
  155. },
  156. client_net => { name => "Network",
  157. },
  158. server_req => { name => "Requests",
  159. stat => "proxy.process.http.outgoing_requests",
  160. },
  161. server_req_conn => { name => "Req/Conn",
  162. },
  163. server_conn => { name => "New Conn",
  164. stat => "proxy.process.http.total_server_connections",
  165. },
  166. server_cconn => { name => "Curr Conn",
  167. stat => "proxy.process.http.current_server_connections",
  168. type => "sum",
  169. },
  170. server_head => { name => "Head Bytes",
  171. stat => "proxy.process.http.origin_server_response_header_total_size",
  172. },
  173. server_body => { name => "Body Bytes",
  174. stat => "proxy.process.http.origin_server_response_document_total_size",
  175. },
  176. server_net => { name => "Network",
  177. },
  178. total_time => { name => "Time",
  179. stat => "proxy.process.http.total_transactions_time",
  180. },
  181. hit_fresh => { name => "Fresh",
  182. stat => "proxy.process.http.transaction_counts.hit_fresh",
  183. type => 'percent'
  184. },
  185. hit_fresh_time => { name => "Fresh (ms)",
  186. stat => "proxy.process.http.transaction_totaltime.hit_fresh",
  187. },
  188. hit_reval_time => { name => "Reval (ms)",
  189. stat => "proxy.process.http.transaction_totaltime.hit_revalidated",
  190. },
  191. miss_cold_time => { name => "Cold (ms)",
  192. stat => "proxy.process.http.transaction_totaltime.miss_cold",
  193. },
  194. miss_changed_time => { name => "Chang (ms)",
  195. stat => "proxy.process.http.transaction_totaltime.miss_changed",
  196. },
  197. miss_not_cacheable_time => { name => "Not (ms)",
  198. stat => "proxy.process.http.transaction_totaltime.miss_not_cacheable",
  199. },
  200. miss_no_cache_time => { name => "No (ms)",
  201. stat => "proxy.process.http.transaction_totaltime.miss_client_no_cache",
  202. },
  203. ram_hit => { name => "Ram Hit",
  204. stat => "proxy.process.cache.ram_cache.hits",
  205. },
  206. ram_miss => { name => "Ram Misses",
  207. stat => "proxy.process.cache.ram_cache.misses",
  208. },
  209. hit_reval => { name => "Revalidate",
  210. stat => "proxy.process.http.transaction_counts.hit_revalidated",
  211. type => 'percent'
  212. },
  213. miss_cold => { name => "Cold",
  214. stat => "proxy.process.http.transaction_counts.miss_cold",
  215. type => 'percent'
  216. },
  217. miss_changed => { name => "Changed",
  218. stat => "proxy.process.http.transaction_counts.miss_changed",
  219. type => 'percent'
  220. },
  221. miss_not_cacheable => { name => "Not Cache",
  222. stat => "proxy.process.http.transaction_counts.miss_not_cacheable",
  223. type => 'percent'
  224. },
  225. miss_no_cache => { name => "No Cache",
  226. stat => "proxy.process.http.transaction_counts.miss_client_no_cache",
  227. type => 'percent'
  228. },
  229. client_abort => { name => "Clnt Abort",
  230. stat => "proxy.process.http.err_client_abort_count_stat",
  231. },
  232. client_fail => { name => "Clnt Fail",
  233. stat => "proxy.process.http.err_connect_fail_count_stat",
  234. },
  235. error_abort => { name => "Abort",
  236. stat => "proxy.process.http.transaction_counts.errors.aborts",
  237. },
  238. error_fail => { name => "Conn Fail",
  239. stat => "proxy.process.http.transaction_counts.errors.connect_failed",
  240. },
  241. error_other => { name => "ERR Other",
  242. stat => "proxy.process.http.transaction_counts.errors.other",
  243. },
  244. size_100 => { name => "100 B",
  245. stat => "proxy.process.http.response_document_size_100",
  246. type => 'percent'
  247. },
  248. size_1k => { name => "1 KB",
  249. stat => "proxy.process.http.response_document_size_1K",
  250. type => 'percent'
  251. },
  252. size_3k => { name => "3 KB",
  253. stat => "proxy.process.http.response_document_size_3K",
  254. type => 'percent'
  255. },
  256. size_5k => { name => "5 KB",
  257. stat => "proxy.process.http.response_document_size_5K",
  258. type => 'percent'
  259. },
  260. size_10k => { name => "10 KB",
  261. stat => "proxy.process.http.response_document_size_10K",
  262. type => 'percent'
  263. },
  264. size_1m => { name => "1 MB",
  265. stat => "proxy.process.http.response_document_size_1M",
  266. type => 'percent'
  267. },
  268. size_inf => { name => "> 1 MB",
  269. stat => "proxy.process.http.response_document_size_inf",
  270. type => 'percent'
  271. },
  272. cache_entries => { name => "Entries",
  273. stat => "proxy.process.cache.direntries.used",
  274. type => 'sum'
  275. },
  276. cache_avg_size => { name => "Avg Size",
  277. },
  278. );
  279. sub getStats() {
  280. my $content = get("http://$server/_stats");
  281. die "can't get stats from server" if (!defined $content);
  282. my $data = decode_json($content);
  283. # $stats = $data;
  284. #print Dumper($stats);
  285. # print $data->{global}, "\n";
  286. #return $data->{global};
  287. return $data;
  288. }
  289. sub prettyPrint($) {
  290. my($number) = @_;
  291. if ($number / 1_000_000_000_000 > 1) {
  292. $number = sprintf("%6.1fT", $number / 1_000_000_000_000);
  293. } elsif ($number / 1_000_000_000 > 1) {
  294. $number = sprintf("%6.1fG", $number / 1_000_000_000);
  295. } elsif ($number / 1_000_000 > 1) {
  296. $number = sprintf("%6.1fM", $number / 1_000_000);
  297. } elsif ($number / 1_000 > 1) {
  298. $number = sprintf("%6.1fK", $number / 1_000);
  299. } else {
  300. $number = sprintf("%6.1f ", $number);
  301. }
  302. return $number;
  303. }
  304. sub printStat($$) {
  305. my($stat, $name) = @_;
  306. my $delta = 0;
  307. if ($name eq 'client_req_conn') {
  308. my $d1 = ($stat->{$lookup{client_req}->{stat}} - $os->{$lookup{client_req}->{stat}}) / $sleep;
  309. my $d2 = ($stat->{$lookup{client_conn}->{stat}} - $os->{$lookup{client_conn}->{stat}}) / $sleep;
  310. $delta = $d1 / $d2 if $d2 > 0;
  311. } elsif ($name eq 'server_req_conn') {
  312. my $d1 = ($stat->{$lookup{server_req}->{stat}} - $os->{$lookup{server_req}->{stat}}) / $sleep;
  313. my $d2 = ($stat->{$lookup{server_conn}->{stat}} - $os->{$lookup{server_conn}->{stat}}) / $sleep;
  314. $delta = $d1 / $d2 if $d2 > 0;
  315. } elsif ($name eq 'mean_req_size') {
  316. my $d1 = ($stat->{$lookup{client_head}->{stat}} + $stat->{$lookup{client_body}->{stat}}) * 8;
  317. my $d2 = ($os->{$lookup{client_head}->{stat}} + $os->{$lookup{client_body}->{stat}}) * 8;
  318. my $bytes = ($d1 - $d2);
  319. my $req = $stat->{$lookup{client_req}->{stat}} - $os->{$lookup{client_req}->{stat}};
  320. $delta = $bytes / $req;
  321. } elsif ($name eq 'mean_res_size') {
  322. my $d1 = ($stat->{$lookup{server_head}->{stat}} + $stat->{$lookup{server_body}->{stat}}) * 8;
  323. my $d2 = ($os->{$lookup{server_head}->{stat}} + $os->{$lookup{server_body}->{stat}}) * 8;
  324. my $bytes = ($d1 - $d2);
  325. my $req = $stat->{$lookup{server_req}->{stat}} - $os->{$lookup{server_req}->{stat}};
  326. $delta = $bytes / $req;
  327. } elsif ($name eq 'client_net') {
  328. my $d1 = ($stat->{$lookup{client_head}->{stat}} + $stat->{$lookup{client_body}->{stat}}) * 8;
  329. my $d2 = ($os->{$lookup{client_head}->{stat}} + $os->{$lookup{client_body}->{stat}}) * 8;
  330. $delta = ($d1 - $d2) / $sleep;
  331. } elsif ($name eq 'server_net') {
  332. my $d1 = ($stat->{$lookup{server_head}->{stat}} + $stat->{$lookup{server_body}->{stat}}) * 8;
  333. my $d2 = ($os->{$lookup{server_head}->{stat}} + $os->{$lookup{server_body}->{stat}}) * 8;
  334. $delta = ($d1 - $d2) / $sleep;
  335. } elsif ($name eq 'client_req_time') {
  336. my $d1 = ($stat->{$lookup{total_time}->{stat}} - $os->{$lookup{total_time}->{stat}}) / $sleep / 10_000_000;
  337. my $d2 = ($stat->{$lookup{client_req}->{stat}} - $os->{$lookup{client_req}->{stat}}) / $sleep;
  338. $delta = $d1 / $d2 if $d2 > 0;
  339. } elsif ($name eq 'hit_fresh_time') {
  340. my $d1 = ($stat->{$lookup{hit_fresh}->{stat}} - $os->{$lookup{hit_fresh}->{stat}}) / $sleep;
  341. my $d2 = ($stat->{$lookup{hit_fresh_time}->{stat}} - $os->{$lookup{hit_fresh_time}->{stat}}) / $sleep;
  342. $delta = $d2 / $d1 * 1000 if $d1 > 0;
  343. } elsif ($name eq 'hit_reval_time') {
  344. my $d1 = ($stat->{$lookup{hit_reval}->{stat}} - $os->{$lookup{hit_reval}->{stat}}) / $sleep;
  345. my $d2 = ($stat->{$lookup{hit_reval_time}->{stat}} - $os->{$lookup{hit_reval_time}->{stat}}) / $sleep;
  346. $delta = $d2 / $d1 * 1000 if $d1 > 0;
  347. } elsif ($name eq 'miss_cold_time') {
  348. my $d1 = ($stat->{$lookup{miss_cold}->{stat}} - $os->{$lookup{miss_cold}->{stat}}) / $sleep;
  349. my $d2 = ($stat->{$lookup{miss_cold_time}->{stat}} - $os->{$lookup{miss_cold_time}->{stat}}) / $sleep;
  350. $delta = $d2 / $d1 * 1000 if $d1 > 0;
  351. } elsif ($name eq 'miss_changed_time') {
  352. my $d1 = ($stat->{$lookup{miss_changed}->{stat}} - $os->{$lookup{miss_changed}->{stat}}) / $sleep;
  353. my $d2 = ($stat->{$lookup{miss_changed_time}->{stat}} - $os->{$lookup{miss_changed_time}->{stat}}) / $sleep;
  354. $delta = $d2 / $d1 * 1000 if $d1 > 0;
  355. } elsif ($name eq 'miss_not_cacheable_time') {
  356. my $d1 = ($stat->{$lookup{miss_not_cacheable}->{stat}} - $os->{$lookup{miss_not_cacheable}->{stat}}) / $sleep;
  357. my $d2 = ($stat->{$lookup{miss_not_cacheable_time}->{stat}} - $os->{$lookup{miss_not_cacheable_time}->{stat}}) / $sleep;
  358. $delta = $d2 / $d1 * 1000 if $d1 > 0;
  359. } elsif ($name eq 'miss_no_cache_time') {
  360. my $d1 = ($stat->{$lookup{miss_no_cache}->{stat}} - $os->{$lookup{miss_no_cache}->{stat}}) / $sleep;
  361. my $d2 = ($stat->{$lookup{miss_no_cache_time}->{stat}} - $os->{$lookup{miss_no_cache_time}->{stat}}) / $sleep;
  362. $delta = $d2 / $d1 * 1000 if $d1 > 0;
  363. } elsif ($name eq 'ram_ratio') {
  364. my $d1 = ($stat->{$lookup{ram_hit}->{stat}} - $os->{$lookup{ram_hit}->{stat}}) / $sleep;
  365. my $d2 = ($stat->{$lookup{ram_miss}->{stat}} - $os->{$lookup{ram_miss}->{stat}}) / $sleep;
  366. $delta = $d1 / ($d1 + $d2) * 100 if ($d1 != 0 && $d2 != 0);
  367. return sprintf("%10s %6.1f%%", "Ram Hit", $delta);
  368. return;
  369. } elsif ($name eq 'cache_avg_size') {
  370. $delta = $stat->{$lookup{disk_total}->{stat}} / $stat->{$lookup{cache_entries}->{stat}};
  371. } elsif (!defined $lookup{$name}->{type}) {
  372. $delta = ($stat->{$lookup{$name}->{stat}} - $os->{$lookup{$name}->{stat}}) / $sleep;
  373. } elsif ($lookup{$name}->{type} eq 'sum') {
  374. $delta = $stat->{$lookup{$name}->{stat}};
  375. } elsif ($lookup{$name}->{type} eq 'percent') {
  376. my $d1 = ($stat->{$lookup{$name}->{stat}} - $os->{$lookup{$name}->{stat}}) / $sleep;
  377. my $d2 = ($stat->{$lookup{client_req}->{stat}} - $os->{$lookup{client_req}->{stat}}) / $sleep;
  378. $delta = $d1 / $d2 * 100 if $d2 > 0;
  379. return sprintf("%10s %6.1f%%", $lookup{$name}->{name}, $delta);
  380. return;
  381. }
  382. return sprintf("%10s %7s", $lookup{$name}->{name}, prettyPrint($delta));
  383. }
  384. sub makeTable($$$$$) {
  385. my($w, $s, $x, $y, $info) = @_;
  386. $w->addstr($x++, $y + 10, $info->{title});
  387. foreach (@{$info->{items}}) {
  388. $w->addstr($x, $y, printStat($s, $_));
  389. $x++;
  390. }
  391. }
  392. sub help() {
  393. print STDERR "USAGE: tstop [-s seconds] server_host|server_host:port\n\n";
  394. print STDERR "NOTE: be default it will update every 5 seconds...\n";
  395. exit;
  396. }
  397. {
  398. my %opts;
  399. getopts("s:", \%opts);
  400. $sleep = $opts{s} if (defined $opts{s});
  401. help() if (! defined $ARGV[0]);
  402. $server = $ARGV[0];
  403. my $s = getStats();
  404. $s = $s->{global};
  405. print "Sleeping for $sleep before gathering stats again...\n";
  406. sleep $sleep;
  407. initscr;
  408. $w = newwin(80, COLS(), 0, 0);
  409. while (1) {
  410. $os = $s;
  411. $s = getStats();
  412. $s = $s->{global};
  413. #print Dumper($s);
  414. #-------------------------
  415. # grid
  416. foreach (1..22) {
  417. $w->addstr($_, 39, "|");
  418. }
  419. foreach ((0,16,23)) {
  420. $w->addstr($_, 0, "-" x 80);
  421. }
  422. # data
  423. makeTable($w, $s, 1, 0, {title => 'CACHE INFORMATION', items => [qw(disk_used disk_total ram_used ram_total cache_lookup cache_writes cache_updates cache_deletes cache_write_active cache_read_active cache_update_active cache_entries cache_avg_size)],});
  424. makeTable($w, $s, 1, 21, {title => '', items => [qw(ram_ratio hit_fresh hit_reval miss_cold miss_changed miss_not_cacheable miss_no_cache hit_fresh_time hit_reval_time miss_cold_time miss_changed_time miss_not_cacheable_time miss_no_cache_time)],});
  425. makeTable($w, $s, 1, 40, {title => 'CLIENT REQUEST & RESPONSE', items => [qw(get head post 2xx 3xx 4xx 5xx client_abort client_fail error_abort error_fail error_other)],});
  426. makeTable($w, $s, 1, 60, {title => '', items => [qw(200 206 301 302 304 404 502 size_100 size_1k size_3k size_5k size_10k size_1m size_inf)],});
  427. makeTable($w, $s, 17, 0, {title => 'CLIENT', items => [qw(client_req client_req_conn client_conn client_cconn client_aconn)],});
  428. makeTable($w, $s, 17, 21, {title => '', items => [qw(client_head client_body client_net mean_req_size client_req_time)],});
  429. makeTable($w, $s, 17, 40, {title => 'ORIGIN SERVER', items => [qw(server_req server_req_conn server_conn server_cconn)],});
  430. makeTable($w, $s, 17, 61, {title => '', items => [qw(server_head server_body server_net mean_res_size)],});
  431. #-------------------------
  432. $w->refresh();
  433. sleep $sleep;
  434. $w->clear();
  435. }
  436. endwin;
  437. }