Updated Branches: refs/heads/master 09d85f6cd -> 9c0f0ef94
Top type program for traffic server. Shows statistical information. Project: http://git-wip-us.apache.org/repos/asf/trafficserver/repo Commit: http://git-wip-us.apache.org/repos/asf/trafficserver/commit/9c0f0ef9 Tree: http://git-wip-us.apache.org/repos/asf/trafficserver/tree/9c0f0ef9 Diff: http://git-wip-us.apache.org/repos/asf/trafficserver/diff/9c0f0ef9 Branch: refs/heads/master Commit: 9c0f0ef94bfb8a2e5d904097a7a64cae20268bf5 Parents: 09d85f6 Author: Bryan Call <[email protected]> Authored: Fri Apr 27 14:35:19 2012 -0700 Committer: Bryan Call <[email protected]> Committed: Fri Apr 27 14:35:19 2012 -0700 ---------------------------------------------------------------------- contrib/tstop/.#README | 1 + contrib/tstop/README | 4 + contrib/tstop/tstop | 445 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 450 insertions(+), 0 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/trafficserver/blob/9c0f0ef9/contrib/tstop/.#README ---------------------------------------------------------------------- diff --git a/contrib/tstop/.#README b/contrib/tstop/.#README new file mode 120000 index 0000000..eda3bff --- /dev/null +++ b/contrib/tstop/.#README @@ -0,0 +1 @@ [email protected]:1334785067 \ No newline at end of file http://git-wip-us.apache.org/repos/asf/trafficserver/blob/9c0f0ef9/contrib/tstop/README ---------------------------------------------------------------------- diff --git a/contrib/tstop/README b/contrib/tstop/README new file mode 100644 index 0000000..10f33b7 --- /dev/null +++ b/contrib/tstop/README @@ -0,0 +1,4 @@ +Top type program for Apache Traffic Server that displays common +statistical information about the server. Requires the server to be +running the stats_over_http plugin. + http://git-wip-us.apache.org/repos/asf/trafficserver/blob/9c0f0ef9/contrib/tstop/tstop ---------------------------------------------------------------------- diff --git a/contrib/tstop/tstop b/contrib/tstop/tstop new file mode 100755 index 0000000..bf72ab7 --- /dev/null +++ b/contrib/tstop/tstop @@ -0,0 +1,445 @@ +#!/usr/bin/perl + +use strict; +use warnings; +use JSON; +use LWP::Simple; +use Data::Dumper; +use Curses; +use Getopt::Std; + +#open(LOG, ">/tmp/tstop.log"); + +my $sleep = 5; +my $server; +my $os; # old stats +my $w; +my %lookup = ( + disk_total => { name => "Disk Total", + stat => "proxy.process.cache.bytes_total", + type => "sum", + }, + disk_used => { name => "Disk Used", + stat => "proxy.process.cache.bytes_used", + type => "sum", + }, + ram_total => { name => "Ram Total", + stat => "proxy.process.cache.ram_cache.total_bytes", + type => "sum", + }, + ram_used => { name => "Ram Used", + stat => "proxy.process.cache.ram_cache.bytes_used", + type => "sum", + }, + cache_lookup => { name => "Lookups", + stat => "proxy.process.http.cache_lookups", + }, + cache_writes => { name => "Writes", + stat => "proxy.process.http.cache_writes", + }, + cache_updates => { name => "Updates", + stat => "proxy.process.http.cache_updates", + }, + cache_deletes => { name => "Deletes", + stat => "proxy.process.http.cache_deletes", + }, + cache_read_active => { name => "Read Activ", + stat => "proxy.process.cache.read.active", + type => "sum", + }, + cache_write_active => { name => "Write Acti", + stat => "proxy.process.cache.write.active", + type => "sum", + }, + cache_update_active => { name => "Update Act", + stat => "proxy.process.cache.update.active", + type => "sum", + }, + get => { name => "GET", + stat => "proxy.process.http.get_requests", + type => 'percent' + }, + head => { name => "HEAD", + stat => "proxy.process.http.head_requests", + type => 'percent' + }, + post => { name => "POST", + stat => "proxy.process.http.post_requests", + type => 'percent' + }, + '2xx' => { name => "2xx", + stat => "proxy.process.http.2xx_responses", + type => 'percent' + }, + '200' => { name => "200", + stat => "proxy.process.http.200_responses", + type => 'percent' + }, + '206' => { name => "206", + stat => "proxy.process.http.206_responses", + type => 'percent' + }, + '3xx' => { name => "3xx", + stat => "proxy.process.http.3xx_responses", + type => 'percent' + }, + '301' => { name => "301", + stat => "proxy.process.http.301_responses", + type => 'percent' + }, + '302' => { name => "302", + stat => "proxy.process.http.302_responses", + type => 'percent' + }, + '304' => { name => "304", + stat => "proxy.process.http.304_responses", + type => 'percent' + }, + '4xx' => { name => "4xx", + stat => "proxy.process.http.4xx_responses", + type => 'percent' + }, + '404' => { name => "404", + stat => "proxy.process.http.404_responses", + type => 'percent' + }, + '5xx' => { name => "5xx", + stat => "proxy.process.http.5xx_responses", + type => 'percent' + }, + '502' => { name => "502", + stat => "proxy.process.http.502_responses", + type => 'percent' + }, + client_req => { name => "Requests", + stat => "proxy.process.http.incoming_requests", + }, + mean_req_size => { name => "Avg Size", + }, + mean_res_size => { name => "Avg Size", + }, + client_req_time => { name => "Resp (ms)", + }, + server_req_time => { name => "Resp (ms)", + }, + client_req_conn => { name => "Req/Conn", + }, + client_conn => { name => "New Conn", + stat => "proxy.process.http.total_client_connections", + }, + client_cconn => { name => "Curr Conn", + stat => "proxy.process.http.current_client_connections", + type => "sum", + }, + client_aconn => { name => "Active Con", + stat => "proxy.process.http.current_active_client_connections", + type => "sum", + }, + client_head => { name => "Head Bytes", + stat => "proxy.process.http.user_agent_response_header_total_size", + }, + client_body => { name => "Body Bytes", + stat => "proxy.process.http.user_agent_response_document_total_size", + }, + client_net => { name => "Network", + }, + server_req => { name => "Requests", + stat => "proxy.process.http.outgoing_requests", + }, + server_req_conn => { name => "Req/Conn", + }, + server_conn => { name => "New Conn", + stat => "proxy.process.http.total_server_connections", + }, + server_cconn => { name => "Curr Conn", + stat => "proxy.process.http.current_server_connections", + type => "sum", + }, + server_head => { name => "Head Bytes", + stat => "proxy.process.http.origin_server_response_header_total_size", + }, + server_body => { name => "Body Bytes", + stat => "proxy.process.http.origin_server_response_document_total_size", + }, + server_net => { name => "Network", + }, + total_time => { name => "Time", + stat => "proxy.process.http.total_transactions_time", + }, + hit_fresh => { name => "Fresh", + stat => "proxy.process.http.transaction_counts.hit_fresh", + type => 'percent' + }, + hit_fresh_time => { name => "Fresh (ms)", + stat => "proxy.process.http.transaction_totaltime.hit_fresh", + }, + hit_reval_time => { name => "Reval (ms)", + stat => "proxy.process.http.transaction_totaltime.hit_revalidated", + }, + miss_cold_time => { name => "Cold (ms)", + stat => "proxy.process.http.transaction_totaltime.miss_cold", + }, + miss_changed_time => { name => "Chang (ms)", + stat => "proxy.process.http.transaction_totaltime.miss_changed", + }, + miss_not_cacheable_time => { name => "Not (ms)", + stat => "proxy.process.http.transaction_totaltime.miss_not_cacheable", + }, + miss_no_cache_time => { name => "No (ms)", + stat => "proxy.process.http.transaction_totaltime.miss_client_no_cache", + }, + ram_hit => { name => "Ram Hit", + stat => "proxy.process.cache.ram_cache.hits", + }, + ram_miss => { name => "Ram Misses", + stat => "proxy.process.cache.ram_cache.misses", + }, + hit_reval => { name => "Revalidate", + stat => "proxy.process.http.transaction_counts.hit_revalidated", + type => 'percent' + }, + miss_cold => { name => "Cold", + stat => "proxy.process.http.transaction_counts.miss_cold", + type => 'percent' + }, + miss_changed => { name => "Changed", + stat => "proxy.process.http.transaction_counts.miss_changed", + type => 'percent' + }, + miss_not_cacheable => { name => "Not Cache", + stat => "proxy.process.http.transaction_counts.miss_not_cacheable", + type => 'percent' + }, + miss_no_cache => { name => "No Cache", + stat => "proxy.process.http.transaction_counts.miss_client_no_cache", + type => 'percent' + }, + client_abort => { name => "Clnt Abort", + stat => "proxy.process.http.err_client_abort_count_stat", + }, + client_fail => { name => "Clnt Fail", + stat => "proxy.process.http.err_connect_fail_count_stat", + }, + error_abort => { name => "Abort", + stat => "proxy.process.http.transaction_counts.errors.aborts", + }, + error_fail => { name => "Conn Fail", + stat => "proxy.process.http.transaction_counts.errors.connect_failed", + }, + error_other => { name => "ERR Other", + stat => "proxy.process.http.transaction_counts.errors.other", + }, + size_100 => { name => "100 B", + stat => "proxy.process.http.response_document_size_100", + type => 'percent' + }, + size_1k => { name => "1 KB", + stat => "proxy.process.http.response_document_size_1K", + type => 'percent' + }, + size_3k => { name => "3 KB", + stat => "proxy.process.http.response_document_size_3K", + type => 'percent' + }, + size_5k => { name => "5 KB", + stat => "proxy.process.http.response_document_size_5K", + type => 'percent' + }, + size_10k => { name => "10 KB", + stat => "proxy.process.http.response_document_size_10K", + type => 'percent' + }, + size_1m => { name => "1 MB", + stat => "proxy.process.http.response_document_size_1M", + type => 'percent' + }, + size_inf => { name => "> 1 MB", + stat => "proxy.process.http.response_document_size_inf", + type => 'percent' + }, + cache_entries => { name => "Entries", + stat => "proxy.process.cache.direntries.used", + type => 'sum' + }, + cache_avg_size => { name => "Avg Size", + }, + ); + +sub getStats() { + + my $content = get("http://$server/_stats"); + die "can't get stats from server" if (!defined $content); + my $data = decode_json($content); + # $stats = $data; + #print Dumper($stats); + # print $data->{global}, "\n"; + #return $data->{global}; + return $data; +} + +sub prettyPrint($) { + my($number) = @_; + + if ($number / 1_000_000_000_000 > 1) { + $number = sprintf("%6.1fT", $number / 1_000_000_000_000); + } elsif ($number / 1_000_000_000 > 1) { + $number = sprintf("%6.1fG", $number / 1_000_000_000); + } elsif ($number / 1_000_000 > 1) { + $number = sprintf("%6.1fM", $number / 1_000_000); + } elsif ($number / 1_000 > 1) { + $number = sprintf("%6.1fK", $number / 1_000); + } else { + $number = sprintf("%6.1f ", $number); + } + + return $number; +} + +sub printStat($$) { + my($stat, $name) = @_; + my $delta = 0; + + if ($name eq 'client_req_conn') { + my $d1 = ($stat->{$lookup{client_req}->{stat}} - $os->{$lookup{client_req}->{stat}}) / $sleep; + my $d2 = ($stat->{$lookup{client_conn}->{stat}} - $os->{$lookup{client_conn}->{stat}}) / $sleep; + $delta = $d1 / $d2 if $d2 > 0; + } elsif ($name eq 'server_req_conn') { + my $d1 = ($stat->{$lookup{server_req}->{stat}} - $os->{$lookup{server_req}->{stat}}) / $sleep; + my $d2 = ($stat->{$lookup{server_conn}->{stat}} - $os->{$lookup{server_conn}->{stat}}) / $sleep; + $delta = $d1 / $d2 if $d2 > 0; + } elsif ($name eq 'mean_req_size') { + my $d1 = ($stat->{$lookup{client_head}->{stat}} + $stat->{$lookup{client_body}->{stat}}) * 8; + my $d2 = ($os->{$lookup{client_head}->{stat}} + $os->{$lookup{client_body}->{stat}}) * 8; + my $bytes = ($d1 - $d2); + my $req = $stat->{$lookup{client_req}->{stat}} - $os->{$lookup{client_req}->{stat}}; + $delta = $bytes / $req; + } elsif ($name eq 'mean_res_size') { + my $d1 = ($stat->{$lookup{server_head}->{stat}} + $stat->{$lookup{server_body}->{stat}}) * 8; + my $d2 = ($os->{$lookup{server_head}->{stat}} + $os->{$lookup{server_body}->{stat}}) * 8; + my $bytes = ($d1 - $d2); + my $req = $stat->{$lookup{server_req}->{stat}} - $os->{$lookup{server_req}->{stat}}; + $delta = $bytes / $req; + } elsif ($name eq 'client_net') { + my $d1 = ($stat->{$lookup{client_head}->{stat}} + $stat->{$lookup{client_body}->{stat}}) * 8; + my $d2 = ($os->{$lookup{client_head}->{stat}} + $os->{$lookup{client_body}->{stat}}) * 8; + $delta = ($d1 - $d2) / $sleep; + } elsif ($name eq 'server_net') { + my $d1 = ($stat->{$lookup{server_head}->{stat}} + $stat->{$lookup{server_body}->{stat}}) * 8; + my $d2 = ($os->{$lookup{server_head}->{stat}} + $os->{$lookup{server_body}->{stat}}) * 8; + $delta = ($d1 - $d2) / $sleep; + } elsif ($name eq 'client_req_time') { + my $d1 = ($stat->{$lookup{total_time}->{stat}} - $os->{$lookup{total_time}->{stat}}) / $sleep / 10_000_000; + my $d2 = ($stat->{$lookup{client_req}->{stat}} - $os->{$lookup{client_req}->{stat}}) / $sleep; + $delta = $d1 / $d2 if $d2 > 0; + } elsif ($name eq 'hit_fresh_time') { + my $d1 = ($stat->{$lookup{hit_fresh}->{stat}} - $os->{$lookup{hit_fresh}->{stat}}) / $sleep; + my $d2 = ($stat->{$lookup{hit_fresh_time}->{stat}} - $os->{$lookup{hit_fresh_time}->{stat}}) / $sleep; + $delta = $d2 / $d1 * 1000 if $d1 > 0; + } elsif ($name eq 'hit_reval_time') { + my $d1 = ($stat->{$lookup{hit_reval}->{stat}} - $os->{$lookup{hit_reval}->{stat}}) / $sleep; + my $d2 = ($stat->{$lookup{hit_reval_time}->{stat}} - $os->{$lookup{hit_reval_time}->{stat}}) / $sleep; + $delta = $d2 / $d1 * 1000 if $d1 > 0; + } elsif ($name eq 'miss_cold_time') { + my $d1 = ($stat->{$lookup{miss_cold}->{stat}} - $os->{$lookup{miss_cold}->{stat}}) / $sleep; + my $d2 = ($stat->{$lookup{miss_cold_time}->{stat}} - $os->{$lookup{miss_cold_time}->{stat}}) / $sleep; + $delta = $d2 / $d1 * 1000 if $d1 > 0; + } elsif ($name eq 'miss_changed_time') { + my $d1 = ($stat->{$lookup{miss_changed}->{stat}} - $os->{$lookup{miss_changed}->{stat}}) / $sleep; + my $d2 = ($stat->{$lookup{miss_changed_time}->{stat}} - $os->{$lookup{miss_changed_time}->{stat}}) / $sleep; + $delta = $d2 / $d1 * 1000 if $d1 > 0; + } elsif ($name eq 'miss_not_cacheable_time') { + my $d1 = ($stat->{$lookup{miss_not_cacheable}->{stat}} - $os->{$lookup{miss_not_cacheable}->{stat}}) / $sleep; + my $d2 = ($stat->{$lookup{miss_not_cacheable_time}->{stat}} - $os->{$lookup{miss_not_cacheable_time}->{stat}}) / $sleep; + $delta = $d2 / $d1 * 1000 if $d1 > 0; + } elsif ($name eq 'miss_no_cache_time') { + my $d1 = ($stat->{$lookup{miss_no_cache}->{stat}} - $os->{$lookup{miss_no_cache}->{stat}}) / $sleep; + my $d2 = ($stat->{$lookup{miss_no_cache_time}->{stat}} - $os->{$lookup{miss_no_cache_time}->{stat}}) / $sleep; + $delta = $d2 / $d1 * 1000 if $d1 > 0; + } elsif ($name eq 'ram_ratio') { + my $d1 = ($stat->{$lookup{ram_hit}->{stat}} - $os->{$lookup{ram_hit}->{stat}}) / $sleep; + my $d2 = ($stat->{$lookup{ram_miss}->{stat}} - $os->{$lookup{ram_miss}->{stat}}) / $sleep; + $delta = $d1 / ($d1 + $d2) * 100 if ($d1 != 0 && $d2 != 0); + return sprintf("%10s %6.1f%%", "Ram Hit", $delta); + return; + } elsif ($name eq 'cache_avg_size') { + $delta = $stat->{$lookup{disk_total}->{stat}} / $stat->{$lookup{cache_entries}->{stat}}; + } elsif (!defined $lookup{$name}->{type}) { + $delta = ($stat->{$lookup{$name}->{stat}} - $os->{$lookup{$name}->{stat}}) / $sleep; + } elsif ($lookup{$name}->{type} eq 'sum') { + $delta = $stat->{$lookup{$name}->{stat}}; + } elsif ($lookup{$name}->{type} eq 'percent') { + my $d1 = ($stat->{$lookup{$name}->{stat}} - $os->{$lookup{$name}->{stat}}) / $sleep; + my $d2 = ($stat->{$lookup{client_req}->{stat}} - $os->{$lookup{client_req}->{stat}}) / $sleep; + $delta = $d1 / $d2 * 100 if $d2 > 0; + return sprintf("%10s %6.1f%%", $lookup{$name}->{name}, $delta); + return; + } + + return sprintf("%10s %7s", $lookup{$name}->{name}, prettyPrint($delta)); +} + +sub makeTable($$$$$) { + my($w, $s, $x, $y, $info) = @_; + $w->addstr($x++, $y + 10, $info->{title}); + + foreach (@{$info->{items}}) { + $w->addstr($x, $y, printStat($s, $_)); + $x++; + } +} + +sub help() { + print STDERR "USAGE: tstop [-s seconds] server_host|server_host:port\n\n"; + print STDERR "NOTE: be default it will update every 5 seconds...\n"; + exit; +} + +{ + my %opts; + getopts("s:", \%opts); + $sleep = $opts{s} if (defined $opts{s}); + help() if (! defined $ARGV[0]); + $server = $ARGV[0]; + + my $s = getStats(); + $s = $s->{global}; + + print "Sleeping for $sleep before gathering stats again...\n"; + sleep $sleep; + initscr; + $w = newwin(80, COLS(), 0, 0); + while (1) { + $os = $s; + $s = getStats(); + $s = $s->{global}; + #print Dumper($s); + + #------------------------- + # grid + foreach (1..22) { + $w->addstr($_, 39, "|"); + } + foreach ((0,16,23)) { + $w->addstr($_, 0, "-" x 80); + } + + # data + 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)],}); + 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)],}); + 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)],}); + 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)],}); + + makeTable($w, $s, 17, 0, {title => 'CLIENT', items => [qw(client_req client_req_conn client_conn client_cconn client_aconn)],}); + makeTable($w, $s, 17, 21, {title => '', items => [qw(client_head client_body client_net mean_req_size client_req_time)],}); + makeTable($w, $s, 17, 40, {title => 'ORIGIN SERVER', items => [qw(server_req server_req_conn server_conn server_cconn)],}); + makeTable($w, $s, 17, 61, {title => '', items => [qw(server_head server_body server_net mean_res_size)],}); + + #------------------------- + + $w->refresh(); + sleep $sleep; + $w->clear(); + } + + endwin; +}
