You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by jp...@apache.org on 2013/03/07 19:24:22 UTC

git commit: Move tstop from contrib to tools

Updated Branches:
  refs/heads/master 163627956 -> d992c005f


Move tstop from contrib to tools


Project: http://git-wip-us.apache.org/repos/asf/trafficserver/repo
Commit: http://git-wip-us.apache.org/repos/asf/trafficserver/commit/d992c005
Tree: http://git-wip-us.apache.org/repos/asf/trafficserver/tree/d992c005
Diff: http://git-wip-us.apache.org/repos/asf/trafficserver/diff/d992c005

Branch: refs/heads/master
Commit: d992c005fab89a040c01474a86fcece4b700ed99
Parents: 1636279
Author: James Peach <jp...@apache.org>
Authored: Thu Mar 7 10:22:09 2013 -0800
Committer: James Peach <jp...@apache.org>
Committed: Thu Mar 7 10:22:20 2013 -0800

----------------------------------------------------------------------
 contrib/tstop/.gitignore |    1 -
 contrib/tstop/Makefile   |    5 -
 contrib/tstop/README     |    4 -
 contrib/tstop/stats.h    |  392 -----------------------------------------
 contrib/tstop/tstop.cc   |  379 ---------------------------------------
 tools/tstop/.gitignore   |    1 +
 tools/tstop/Makefile     |    5 +
 tools/tstop/README       |    4 +
 tools/tstop/stats.h      |  392 +++++++++++++++++++++++++++++++++++++++++
 tools/tstop/tstop.cc     |  379 +++++++++++++++++++++++++++++++++++++++
 10 files changed, 781 insertions(+), 781 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/trafficserver/blob/d992c005/contrib/tstop/.gitignore
----------------------------------------------------------------------
diff --git a/contrib/tstop/.gitignore b/contrib/tstop/.gitignore
deleted file mode 100644
index c518e71..0000000
--- a/contrib/tstop/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-tstop

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/d992c005/contrib/tstop/Makefile
----------------------------------------------------------------------
diff --git a/contrib/tstop/Makefile b/contrib/tstop/Makefile
deleted file mode 100644
index 6b9a7e6..0000000
--- a/contrib/tstop/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-all: tstop.cc
-	$(CXX) $^ -o tstop -lcurl -lcurses -g -ltsutil -ltsmgmt -ltsutil -lpthread -Wl,-rpath,/usr/local/lib
-
-clean:
-	rm -f tstop

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/d992c005/contrib/tstop/README
----------------------------------------------------------------------
diff --git a/contrib/tstop/README b/contrib/tstop/README
deleted file mode 100644
index 10f33b7..0000000
--- a/contrib/tstop/README
+++ /dev/null
@@ -1,4 +0,0 @@
-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/d992c005/contrib/tstop/stats.h
----------------------------------------------------------------------
diff --git a/contrib/tstop/stats.h b/contrib/tstop/stats.h
deleted file mode 100644
index 8e535bc..0000000
--- a/contrib/tstop/stats.h
+++ /dev/null
@@ -1,392 +0,0 @@
-/** @file
-
-    Include file for the tstop stats.
-
-    @section license License
-
-    Licensed to the Apache Software Foundation (ASF) under one
-    or more contributor license agreements.  See the NOTICE file
-    distributed with this work for additional information
-    regarding copyright ownership.  The ASF licenses this file
-    to you under the Apache License, Version 2.0 (the
-    "License"); you may not use this file except in compliance
-    with the License.  You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
-*/
-
-#include <curl/curl.h>
-#include <map>
-#include <string>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-//#include <ts/ts.h>
-#include <inttypes.h>
-#include <ts/mgmtapi.h>
-
-using namespace std;
-
-struct LookupItem {
-  LookupItem(const char *s, const char *n, const int t): pretty(s), name(n), type(t) {}
-  LookupItem(const char *s, const char *n, const char *d, const int t): pretty(s), name(n), numerator(n), denominator(d), type(t) {}
-  const char *pretty;
-  const char *name;
-  const char *numerator;
-  const char *denominator;
-  int type;
-};
-extern size_t write_data(void *ptr, size_t size, size_t nmemb, void *stream);
-extern char curl_error[CURL_ERROR_SIZE];
-extern string response;
-
-namespace constant {
-  const char global[] = "\"global\": {\n";
-  const char start[] = "\"proxy.process.";
-  const char seperator[] = "\": \"";
-  const char end[] = "\",\n";
-};
-
-//----------------------------------------------------------------------------
-class Stats {
-public:
-  Stats(const string &host) {
-    _host = host;
-    _stats = NULL;
-    _old_stats = NULL;
-    _absolute = false;
-    lookup_table.insert(make_pair("version", LookupItem("Version", "proxy.process.version.server.short", 1)));
-    lookup_table.insert(make_pair("disk_used", LookupItem("Disk Used", "proxy.process.cache.bytes_used", 1)));
-    lookup_table.insert(make_pair("disk_total", LookupItem("Disk Total", "proxy.process.cache.bytes_total", 1)));
-    lookup_table.insert(make_pair("ram_used", LookupItem("Ram Used", "proxy.process.cache.ram_cache.bytes_used", 1)));
-    lookup_table.insert(make_pair("ram_total", LookupItem("Ram Total", "proxy.process.cache.ram_cache.total_bytes", 1)));
-    lookup_table.insert(make_pair("lookups", LookupItem("Lookups", "proxy.process.http.cache_lookups", 2)));
-    lookup_table.insert(make_pair("cache_writes", LookupItem("Writes", "proxy.process.http.cache_writes", 2)));
-    lookup_table.insert(make_pair("cache_updates", LookupItem("Updates", "proxy.process.http.cache_updates", 2)));
-    lookup_table.insert(make_pair("cache_deletes", LookupItem("Deletes", "proxy.process.http.cache_deletes", 2)));
-    lookup_table.insert(make_pair("read_active", LookupItem("Read Active", "proxy.process.cache.read.active", 1)));
-    lookup_table.insert(make_pair("write_active", LookupItem("Writes Active", "proxy.process.cache.write.active", 1)));
-    lookup_table.insert(make_pair("update_active", LookupItem("Update Active", "proxy.process.cache.update.active", 1)));
-    lookup_table.insert(make_pair("entries", LookupItem("Entries", "proxy.process.cache.direntries.used", 1)));
-    lookup_table.insert(make_pair("avg_size", LookupItem("Avg Size", "disk_used", "entries", 3)));
-
-    lookup_table.insert(make_pair("dns_time", LookupItem("DNS Time", "proxy.node.dns.lookup_avg_time_ms", 2)));
-    lookup_table.insert(make_pair("dns_hits", LookupItem("DNS hits", "proxy.node.hostdb.total_hits", 2)));
-    lookup_table.insert(make_pair("dns_lookups", LookupItem("DNS lookups", "proxy.node.hostdb.total_lookups", 2)));
-    lookup_table.insert(make_pair("client_req", LookupItem("Requests", "proxy.process.http.incoming_requests", 2)));
-    lookup_table.insert(make_pair("client_conn", LookupItem("New Conn", "proxy.process.http.total_client_connections", 2)));
-    lookup_table.insert(make_pair("client_req_conn", LookupItem("Req/Conn", "client_req", "client_conn", 3)));
-    lookup_table.insert(make_pair("client_curr_conn", LookupItem("Curr Conn", "proxy.process.http.current_client_connections", 1)));
-    lookup_table.insert(make_pair("client_actv_conn", LookupItem("Active Con", "proxy.process.http.current_active_client_connections", 1)));
-
-    lookup_table.insert(make_pair("server_req", LookupItem("Requests", "proxy.process.http.outgoing_requests", 2)));
-    lookup_table.insert(make_pair("server_conn", LookupItem("New Conn", "proxy.process.http.total_server_connections", 2)));
-    lookup_table.insert(make_pair("server_req_conn", LookupItem("Req/Conn", "server_req", "server_conn", 3)));
-    lookup_table.insert(make_pair("server_curr_conn", LookupItem("Curr Conn", "proxy.process.http.current_server_connections", 1)));
-
-
-    lookup_table.insert(make_pair("client_head", LookupItem("Head Bytes", "proxy.process.http.user_agent_response_header_total_size", 2)));
-    lookup_table.insert(make_pair("client_body", LookupItem("Body Bytes", "proxy.process.http.user_agent_response_document_total_size", 2)));
-    lookup_table.insert(make_pair("server_head", LookupItem("Head Bytes", "proxy.process.http.origin_server_response_header_total_size", 2)));
-    lookup_table.insert(make_pair("server_body", LookupItem("Body Bytes", "proxy.process.http.origin_server_response_document_total_size", 2)));
-
-    // not used directly
-    lookup_table.insert(make_pair("ram_hit", LookupItem("Ram Hit", "proxy.process.cache.ram_cache.hits", 2)));
-    lookup_table.insert(make_pair("ram_miss", LookupItem("Ram Misses", "proxy.process.cache.ram_cache.misses", 2)));
-
-
-
-    lookup_table.insert(make_pair("client_abort", LookupItem("Clnt Abort", "proxy.process.http.err_client_abort_count_stat", 2)));
-    lookup_table.insert(make_pair("conn_fail", LookupItem("Conn Fail", "proxy.process.http.err_connect_fail_count_stat", 2)));
-    lookup_table.insert(make_pair("abort", LookupItem("Abort", "proxy.process.http.transaction_counts.errors.aborts", 2)));
-    lookup_table.insert(make_pair("t_conn_fail", LookupItem("Conn Fail", "proxy.process.http.transaction_counts.errors.connect_failed", 2)));
-    lookup_table.insert(make_pair("other_err", LookupItem("Other Err", "proxy.process.http.transaction_counts.errors.other", 2)));
-    // percentage
-    lookup_table.insert(make_pair("ram_ratio", LookupItem("Ram Hit", "ram_hit", "ram_hit_miss", 4)));
-    lookup_table.insert(make_pair("dns_ratio", LookupItem("DNS Hit", "dns_hits", "dns_lookups", 4)));
-
-    // percetage of requests
-    lookup_table.insert(make_pair("fresh", LookupItem("Fresh", "proxy.process.http.transaction_counts.hit_fresh", 5)));
-    lookup_table.insert(make_pair("reval", LookupItem("Revalidate", "proxy.process.http.transaction_counts.hit_revalidated", 5)));
-    lookup_table.insert(make_pair("cold", LookupItem("Cold", "proxy.process.http.transaction_counts.miss_cold", 5)));
-    lookup_table.insert(make_pair("changed", LookupItem("Changed", "proxy.process.http.transaction_counts.miss_changed", 5)));
-    lookup_table.insert(make_pair("not", LookupItem("Not Cache", "proxy.process.http.transaction_counts.miss_not_cacheable", 5)));
-    lookup_table.insert(make_pair("no", LookupItem("No Cache", "proxy.process.http.transaction_counts.miss_client_no_cache", 5)));
-
-    lookup_table.insert(make_pair("fresh_time", LookupItem("Fresh (ms)", "proxy.process.http.transaction_totaltime.hit_fresh", "fresh", 8)));
-    lookup_table.insert(make_pair("reval_time", LookupItem("Reval (ms)", "proxy.process.http.transaction_totaltime.hit_revalidated", "reval", 8)));
-    lookup_table.insert(make_pair("cold_time", LookupItem("Cold (ms)", "proxy.process.http.transaction_totaltime.miss_cold", "cold", 8)));
-    lookup_table.insert(make_pair("changed_time", LookupItem("Chang (ms)", "proxy.process.http.transaction_totaltime.miss_changed", "changed", 8)));
-    lookup_table.insert(make_pair("not_time", LookupItem("Not (ms)", "proxy.process.http.transaction_totaltime.miss_not_cacheable", "not", 8)));
-    lookup_table.insert(make_pair("no_time", LookupItem("No (ms)", "proxy.process.http.transaction_totaltime.miss_client_no_cache", "no", 8)));
-
-    lookup_table.insert(make_pair("get", LookupItem("GET", "proxy.process.http.get_requests", 5)));
-    lookup_table.insert(make_pair("head", LookupItem("HEAD", "proxy.process.http.head_requests", 5)));
-    lookup_table.insert(make_pair("post", LookupItem("POST", "proxy.process.http.post_requests", 5)));
-    lookup_table.insert(make_pair("2xx", LookupItem("2xx", "proxy.process.http.2xx_responses", 5)));
-    lookup_table.insert(make_pair("3xx", LookupItem("3xx", "proxy.process.http.3xx_responses", 5)));
-    lookup_table.insert(make_pair("4xx", LookupItem("4xx", "proxy.process.http.4xx_responses", 5)));
-    lookup_table.insert(make_pair("5xx", LookupItem("5xx", "proxy.process.http.5xx_responses", 5)));
-
-    lookup_table.insert(make_pair("200", LookupItem("200", "proxy.process.http.200_responses", 5)));
-    lookup_table.insert(make_pair("206", LookupItem("206", "proxy.process.http.206_responses", 5)));
-    lookup_table.insert(make_pair("301", LookupItem("301", "proxy.process.http.301_responses", 5)));
-    lookup_table.insert(make_pair("302", LookupItem("302", "proxy.process.http.302_responses", 5)));
-    lookup_table.insert(make_pair("304", LookupItem("304", "proxy.process.http.304_responses", 5)));
-    lookup_table.insert(make_pair("404", LookupItem("404", "proxy.process.http.404_responses", 5)));
-    lookup_table.insert(make_pair("502", LookupItem("502", "proxy.process.http.502_responses", 5)));
-
-    lookup_table.insert(make_pair("s_100", LookupItem("100 B", "proxy.process.http.response_document_size_100", 5)));
-    lookup_table.insert(make_pair("s_1k", LookupItem("1 KB", "proxy.process.http.response_document_size_1K", 5)));
-    lookup_table.insert(make_pair("s_3k", LookupItem("3 KB", "proxy.process.http.response_document_size_3K", 5)));
-    lookup_table.insert(make_pair("s_5k", LookupItem("5 KB", "proxy.process.http.response_document_size_5K", 5)));
-    lookup_table.insert(make_pair("s_10k", LookupItem("10 KB", "proxy.process.http.response_document_size_10K", 5)));
-    lookup_table.insert(make_pair("s_1m", LookupItem("1 MB", "proxy.process.http.response_document_size_1M", 5)));
-    lookup_table.insert(make_pair("s_>1m", LookupItem("> 1 MB", "proxy.process.http.response_document_size_inf", 5)));
-
-
-    // sum together
-    lookup_table.insert(make_pair("ram_hit_miss", LookupItem("Ram Hit+Miss", "ram_hit", "ram_miss", 6)));
-    lookup_table.insert(make_pair("client_net", LookupItem("Net (bits)", "client_head", "client_body", 7)));
-    lookup_table.insert(make_pair("client_size", LookupItem("Total Size", "client_head", "client_body", 6)));
-    lookup_table.insert(make_pair("client_avg_size", LookupItem("Avg Size", "client_size", "client_req", 3)));
-
-    lookup_table.insert(make_pair("server_net", LookupItem("Net (bits)", "server_head", "server_body", 7)));
-    lookup_table.insert(make_pair("server_size", LookupItem("Total Size", "server_head", "server_body", 6)));
-    lookup_table.insert(make_pair("server_avg_size", LookupItem("Avg Size", "server_size", "server_req", 3)));
-
-
-    lookup_table.insert(make_pair("total_time", LookupItem("Total Time", "proxy.process.http.total_transactions_time", 2)));
-    lookup_table.insert(make_pair("client_req_time", LookupItem("Resp (ms)", "total_time", "client_req", 3)));
-  }
-
-  void getStats() {
-
-    if (_host == "") {
-      int64_t value;
-      if (_old_stats != NULL) {
-        delete _old_stats;
-        _old_stats = NULL;
-      }
-      _old_stats = _stats;
-      _stats = new map<string, string>;
-
-      gettimeofday(&_time, NULL);
-      double now = _time.tv_sec + (double)_time.tv_usec / 1000000;
-
-      for (map<string, LookupItem>::const_iterator lookup_it = lookup_table.begin();
-           lookup_it != lookup_table.end(); ++lookup_it) {
-        const LookupItem &item = lookup_it->second;
-
-        if (item.type == 1 || item.type == 2 || item.type == 5 || item.type == 8) {
-          if (strcmp(item.pretty, "Version") == 0) {
-            // special case for Version informaion
-            TSString strValue = NULL;
-            assert(TSRecordGetString(item.name, &strValue) == TS_ERR_OKAY);
-            string key = item.name;
-            (*_stats)[key] = strValue;
-          } else {
-            assert(TSRecordGetInt(item.name, &value) == TS_ERR_OKAY);
-            string key = item.name;
-            char buffer[32];
-            sprintf(buffer, "%lld", value);
-            string foo = buffer;
-            (*_stats)[key] = foo;
-          }
-        }
-      } 
-      _old_time = _now;
-      _now = now;
-      _time_diff = _now - _old_time;
-    } else {
-      CURL *curl;
-      CURLcode res;
-
-      curl = curl_easy_init();
-      if (curl) {
-        string url = "http://" + _host + "/_stats";
-        curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
-        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
-        curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, curl_error);
-
-        // update time
-        gettimeofday(&_time, NULL);
-        double now = _time.tv_sec + (double)_time.tv_usec / 1000000;
-
-        response.clear();
-        response.reserve(32768); // should hopefully be smaller then 32KB
-        res = curl_easy_perform(curl);
-
-        // only if success update stats and time information
-        if (res == 0) {
-          if (_old_stats != NULL) {
-            delete _old_stats;
-            _old_stats = NULL;
-          }
-          _old_stats = _stats;
-          _stats = new map<string, string>;
-
-          // parse
-          parseResponse(response);
-          _old_time = _now;
-          _now = now;
-          _time_diff = _now - _old_time;
-        }
-
-        /* always cleanup */ 
-        curl_easy_cleanup(curl);
-      }
-    }
-  }
-
-  int64_t getValue(const string &key, const map<string, string> *stats) const {
-    map<string, string>::const_iterator stats_it = stats->find(key);
-    assert(stats_it != stats->end());
-    int64_t value = atoll(stats_it->second.c_str());
-    return value;
-  }
-
-  void getStat(const string &key, double &value, int overrideType = 0) {
-    string strtmp;
-    int typetmp;
-    getStat(key, value, strtmp, typetmp, overrideType);
-  }
-
-
-  void getStat(const string &key, string &value) {
-    map<string, LookupItem>::const_iterator lookup_it = lookup_table.find(key);
-    assert(lookup_it != lookup_table.end());
-    const LookupItem &item = lookup_it->second;
-    
-    map<string, string>::const_iterator stats_it = _stats->find(item.name);
-    assert(stats_it != _stats->end());
-    value = stats_it->second.c_str();
-  }
-
-  void getStat(const string &key, double &value, string &prettyName, int &type, int overrideType = 0) {
-    map<string, LookupItem>::const_iterator lookup_it = lookup_table.find(key);
-    assert(lookup_it != lookup_table.end());
-    const LookupItem &item = lookup_it->second;
-    prettyName = item.pretty;
-    if (overrideType != 0)
-      type = overrideType;
-    else
-      type = item.type;
-
-    if (type == 1 || type == 2 || type == 5 || type == 8) {
-      value = getValue(item.name, _stats);
-      if (key == "total_time") {
-        value = value / 10000000;
-      }
-
-      if ((type == 2 || type == 5 || type == 8) && _old_stats != NULL && _absolute == false) {
-        double old = getValue(item.name, _old_stats);
-        if (key == "total_time") {
-          old = old / 10000000;
-        }
-        value = (value - old) / _time_diff;
-      }
-    } else if (type == 3 || type == 4) {
-      double numerator;
-      double denominator;
-      getStat(item.numerator, numerator);
-      getStat(item.denominator, denominator);
-      if (denominator == 0)
-        value = 0;
-      else
-        value = numerator / denominator;
-      if (type == 4) {
-        value *= 100;
-      }
-    } else if (type == 6 || type == 7) {
-      double numerator;
-      double denominator;
-      getStat(item.numerator, numerator, 2);
-      getStat(item.denominator, denominator, 2);
-      value = numerator + denominator;
-      if (type == 7)
-        value *= 8;
-    }
-
-    if (type == 8) {
-      double denominator;
-      getStat(item.denominator, denominator, 2);
-      if (denominator == 0)
-        value = 0;
-      else
-        value = value / denominator * 1000;
-    }
-
-    if (type == 5) {
-      double denominator;
-      getStat("client_req", denominator);
-      if (denominator == 0)
-        value = 0;
-      else
-        value = value / denominator * 100;
-    }
-  }
-
-  bool toggleAbsolute() {
-    if (_absolute == true)
-      _absolute = false;
-    else
-      _absolute = true;
-
-    return _absolute;
-  }
-
-  void parseResponse(const string &response) {
-    // move past global
-    size_t pos = response.find(constant::global);
-    pos += sizeof(constant::global) - 1;
-
-    // find parts of the line
-    while (1) {
-      size_t start = response.find(constant::start, pos);
-      size_t seperator = response.find(constant::seperator, pos);
-      size_t end = response.find(constant::end, pos);
-  
-      if (start == string::npos || seperator == string::npos || end == string::npos)
-        return;
-
-      //cout << constant::start << " " << start << endl;
-      //cout << constant::seperator << " " << seperator << endl;
-      //cout << constant::end << " " << end << endl;
-
-      string key = response.substr(start + 1, seperator - start - 1);
-      string value = response.substr(seperator + sizeof(constant::seperator) - 1, end - seperator - sizeof(constant::seperator) + 1);
-
-      (*_stats)[key] = value;
-      //cout << "key " << key << " " << "value " << value << endl;
-      pos = end + sizeof(constant::end) - 1;
-      //cout << "pos: " << pos << endl;
-    }
-  }
-
-  ~Stats() {
-    if (_stats != NULL) {
-      delete _stats;
-    }
-    if (_old_stats != NULL) {
-      delete _old_stats;
-    }
-  }
-
-private:
-  map<string, string> *_stats;
-  map<string, string> *_old_stats;
-  map<string, LookupItem> lookup_table;
-  string _host;
-  double _old_time;
-  double _now;
-  double _time_diff;
-  struct timeval _time;
-  bool _absolute;
-};

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/d992c005/contrib/tstop/tstop.cc
----------------------------------------------------------------------
diff --git a/contrib/tstop/tstop.cc b/contrib/tstop/tstop.cc
deleted file mode 100644
index d368530..0000000
--- a/contrib/tstop/tstop.cc
+++ /dev/null
@@ -1,379 +0,0 @@
-/** @file
-
-    Main file for the tstop application.
-
-    @section license License
-
-    Licensed to the Apache Software Foundation (ASF) under one
-    or more contributor license agreements.  See the NOTICE file
-    distributed with this work for additional information
-    regarding copyright ownership.  The ASF licenses this file
-    to you under the Apache License, Version 2.0 (the
-    "License"); you may not use this file except in compliance
-    with the License.  You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
-*/
-#include <ncurses.h>
-#include <list>
-#include <string.h>
-#include <string>
-#include <iostream>
-#include <assert.h>
-#include <map>
-#include <stdlib.h>
-#include "stats.h"
-#include <unistd.h>
-#include <getopt.h>
-
-using namespace std;
-char curl_error[CURL_ERROR_SIZE];
-string response;
-
-
-namespace colorPair {
-  const short red = 1;
-  const short yellow = 2;
-  const short green = 3;
-  const short blue = 4;
-  const short black = 5;
-  const short grey = 6;
-  const short cyan = 7;
-  const short border = 8;
-};
-
-
-//----------------------------------------------------------------------------
-int printGraphLabels(int x, int y, int width, list<const char*> lables) {
-  char buffer[256];
-  for (list<const char*>::const_iterator it = lables.begin();
-       it != lables.end(); ++it) {
-
-    char *pos = buffer;
-    pos += snprintf(buffer, 256, "%7s [", *it);
-    memset(pos, ' ', width);
-    pos += width - 1;
-    
-    strncat(pos, "]", buffer - pos);
-    
-    mvprintw(y++, x, buffer);
-  }
-  
-  //  mvprintw(x, y, 
-}
-
-
-//----------------------------------------------------------------------------
-void prettyPrint(const int x, const int y, const double number, const int type) {
-  char buffer[32];
-  char exp = ' ';
-  double my_number = number;
-  short color;
-  if (number > 1000000000000LL) {
-    my_number = number / 1000000000000;
-    exp = 'T';
-    color = colorPair::red;
-  } else if (number > 1000000000) {
-    my_number = number / 1000000000;
-    exp = 'G';
-    color = colorPair::red;
-  } else if (number > 1000000) {
-    my_number = number / 1000000;
-    exp = 'M';
-    color = colorPair::yellow;
-  } else if (number > 1000) {
-    my_number = number / 1000;
-    exp = 'K';
-    color = colorPair::cyan;
-  } else if (my_number <= .09) {
-    color = colorPair::grey;
-  } else {
-    color = colorPair::green;
-  }
-
-  if (type == 4 || type == 5) {
-    if (number > 90) {
-      color = colorPair::red;
-    } else if (number > 80) {
-      color = colorPair::yellow;
-    } else if (number > 50) {
-      color = colorPair::blue;
-    } else if (my_number <= .09) {
-      color = colorPair::grey;
-    } else {
-      color = colorPair::green;
-    }
-    snprintf(buffer, sizeof(buffer), "%6.1f%%%%", (double)my_number);
-  } else
-    snprintf(buffer, sizeof(buffer), "%6.1f%c", (double)my_number, exp);
-  attron(COLOR_PAIR(color));
-  attron(A_BOLD);
-  mvprintw(y, x, buffer);
-  attroff(COLOR_PAIR(color));
-  attroff(A_BOLD);
-}
-
-//----------------------------------------------------------------------------
-void makeTable(const int x, const int y, const list<string> &items, Stats &stats) {
-  int my_y = y;
-
-  for (list<string>::const_iterator it = items.begin(); it != items.end(); ++it) {
-    string prettyName;
-    double value;
-    int type;
-
-    stats.getStat(*it, value, prettyName, type);
-    mvprintw(my_y, x, prettyName.c_str());
-    prettyPrint(x + 10, my_y++, value, type);
-  }
-}
-
-//----------------------------------------------------------------------------
-size_t write_data(void *ptr, size_t size, size_t nmemb, void *stream)
-{
-  response.append((char*)ptr, size * nmemb);
-  //cout << "appending: " << size * nmemb << endl;
-  //int written = fwrite(ptr, size, nmemb, (FILE *)stream);
-  return size * nmemb;
-}
-
-//----------------------------------------------------------------------------
-void help(const string &host, const string &version) {
-
-  timeout(1000);
-
-  while(1) {
-    clear();
-    time_t now = time(NULL);
-    struct tm *nowtm = localtime(&now);
-    char timeBuf[32];
-    strftime(timeBuf, sizeof(timeBuf), "%H:%M:%S", nowtm);
-
-    //clear();
-    attron(A_BOLD); mvprintw(0, 0, "Overview:"); attroff(A_BOLD); 
-    mvprintw(1, 0, "tstop is a top like program for Apache Traffic Server (ATS).  There is a lot of statistical information gathered by ATS.  This program tries to show some of the more important stats and gives a good overview of what the proxy server is doing.  Hopefully this can be used as a tool to diagnosing the proxy server is there are problems.");
-
-    attron(A_BOLD); mvprintw(7, 0, "Definitions:"); attroff(A_BOLD); 
-    mvprintw(8, 0, "Fresh      => Requests that were servered by fresh entries in cache");
-    mvprintw(9, 0, "Revalidate => Requests that contacted the origin to verify if still valid");
-    mvprintw(10, 0, "Cold       => Requests that were not in cache at all");
-    mvprintw(11, 0, "Changed    => Requests that required entries in cache to be updated");
-    mvprintw(12, 0, "Changed    => Requests that can't be cached for some reason");
-    mvprintw(12, 0, "No Cache   => Requests that the client sent Cache-Control: no-cache header");
-
-    attron(COLOR_PAIR(colorPair::border));
-    attron(A_BOLD);
-    mvprintw(23, 0, "%s - %.12s - %.12s      (b)ack                            ", timeBuf, version.c_str(), host.c_str());
-    attroff(COLOR_PAIR(colorPair::border));
-    attroff(A_BOLD);
-    refresh();
-    int x = getch();
-    if (x == 'b')
-      break;
-  }
-}
-
-void usage(char **argv) {
-  fprintf(stderr, "Usage: %s [-s seconds] hostname|hostname:port\n", argv[0]);
-  exit(1);
-}
-
-
-//----------------------------------------------------------------------------
-int main(int argc, char **argv)
-{
-  int sleep_time = 5000;
-  bool absolute = false;
-  int opt;
-  while ((opt = getopt(argc, argv, "s:")) != -1) {
-    switch(opt) {
-    case 's':
-      sleep_time = atoi(optarg) * 1000;
-      break;
-    default:
-      usage(argv);
-    }
-  }
-
-  string host = "";
-  if (optind >= argc) {
-    if (TS_ERR_OKAY != TSInit(NULL, static_cast<TSInitOptionT>(TS_MGMT_OPT_NO_EVENTS | TS_MGMT_OPT_NO_SOCK_TESTS))) {
-      fprintf(stderr, "Error: missing hostname on command line or error connecting to the local manager\n");
-      usage(argv);
-    }
-  } else {
-    host = argv[optind];
-  }
-  Stats stats(host);
-
-  if (host == "") {
-    char hostname[25];
-    hostname[sizeof(hostname) - 1] = '\0';
-    gethostname(hostname, sizeof(hostname) - 1);
-    host = hostname;
-  }
-
-  initscr();
-  curs_set(0);
-  
-
-  start_color();			/* Start color functionality	*/
-  
-  init_pair(colorPair::red, COLOR_RED, COLOR_BLACK);
-  init_pair(colorPair::yellow, COLOR_YELLOW, COLOR_BLACK);
-  init_pair(colorPair::grey, COLOR_BLACK, COLOR_BLACK);
-  init_pair(colorPair::green, COLOR_GREEN, COLOR_BLACK);
-  init_pair(colorPair::blue, COLOR_BLUE, COLOR_BLACK);
-  init_pair(colorPair::cyan, COLOR_CYAN, COLOR_BLACK);
-  init_pair(colorPair::border, COLOR_WHITE, COLOR_BLUE);
-  //  mvchgat(0, 0, -1, A_BLINK, 1, NULL);
-
-  stats.getStats();
-  while(1) {
-    attron(COLOR_PAIR(colorPair::border));
-    attron(A_BOLD);
-    for (int i = 0; i <= 22; ++i) {
-      mvprintw(i, 39, " ");
-    }
-    string version;
-    time_t now = time(NULL);
-    struct tm *nowtm = localtime(&now);
-    char timeBuf[32];
-    strftime(timeBuf, sizeof(timeBuf), "%H:%M:%S", nowtm);
-    stats.getStat("version", version);
-    mvprintw(0, 0, "         CACHE INFORMATION             ");
-    mvprintw(0, 40, "       CLIENT REQUEST & RESPONSE        ");
-    mvprintw(16, 0, "             CLIENT                    ");
-    mvprintw(16, 40, "           ORIGIN SERVER                ");
-    mvprintw(23, 0, "%8.8s - %-10.10s - %-24.24s      (q)uit (h)elp (%c)bsolute  ", timeBuf, version.c_str(), host.c_str(), absolute ? 'A' : 'a');
-    attroff(COLOR_PAIR(colorPair::border));
-    attroff(A_BOLD);
-
-    list<string> cache1;
-    cache1.push_back("disk_used");
-    cache1.push_back("disk_total");
-    cache1.push_back("ram_used");
-    cache1.push_back("ram_total");
-    cache1.push_back("lookups");
-    cache1.push_back("cache_writes");
-    cache1.push_back("cache_updates");
-    cache1.push_back("cache_deletes");
-    cache1.push_back("read_active");
-    cache1.push_back("write_active");
-    cache1.push_back("update_active");
-    cache1.push_back("entries");
-    cache1.push_back("avg_size");
-    cache1.push_back("dns_lookups");
-    cache1.push_back("dns_hits");
-    makeTable(0, 1, cache1, stats);
-
-
-    list<string> cache2;
-    cache2.push_back("ram_ratio");
-    cache2.push_back("fresh");
-    cache2.push_back("reval");
-    cache2.push_back("cold");
-    cache2.push_back("changed");
-    cache2.push_back("not");
-    cache2.push_back("no");
-    cache2.push_back("fresh_time");
-    cache2.push_back("reval_time");
-    cache2.push_back("cold_time");
-    cache2.push_back("changed_time");
-    cache2.push_back("not_time");
-    cache2.push_back("no_time");
-    cache2.push_back("dns_ratio");
-    cache2.push_back("dns_time");
-    makeTable(21, 1, cache2, stats);
-
-    list<string> response1;
-    response1.push_back("get");
-    response1.push_back("head");
-    response1.push_back("post");
-    response1.push_back("2xx");
-    response1.push_back("3xx");
-    response1.push_back("4xx");
-    response1.push_back("5xx");
-    response1.push_back("conn_fail");
-    response1.push_back("other_err");
-    response1.push_back("abort");
-    makeTable(41, 1, response1, stats);
-
-
-    list<string> response2;
-    response2.push_back("200");
-    response2.push_back("206");
-    response2.push_back("301");
-    response2.push_back("302");
-    response2.push_back("304");
-    response2.push_back("404");
-    response2.push_back("502");
-    response2.push_back("s_100");
-    response2.push_back("s_1k");
-    response2.push_back("s_3k");
-    response2.push_back("s_5k");
-    response2.push_back("s_10k");
-    response2.push_back("s_1m");
-    response2.push_back("s_>1m");
-    makeTable(62, 1, response2, stats);
-
-    list<string> client1;
-    client1.push_back("client_req");
-    client1.push_back("client_req_conn");
-    client1.push_back("client_conn");
-    client1.push_back("client_curr_conn");
-    client1.push_back("client_actv_conn");
-    makeTable(0, 17, client1, stats);
-
-
-    list<string> client2;
-    client2.push_back("client_head");
-    client2.push_back("client_body");
-    client2.push_back("client_avg_size");
-    client2.push_back("client_net");
-    client2.push_back("client_req_time");
-    makeTable(21, 17, client2, stats);
-
-    list<string> server1;
-    server1.push_back("server_req");
-    server1.push_back("server_req_conn");
-    server1.push_back("server_conn");
-    server1.push_back("server_curr_conn");
-    makeTable(41, 17, server1, stats);
-
-
-    list<string> server2;
-    server2.push_back("server_head");
-    server2.push_back("server_body");
-    server2.push_back("server_avg_size");
-    server2.push_back("server_net");
-    makeTable(62, 17, server2, stats);
-
-
-    curs_set(0);
-    refresh();
-    timeout(sleep_time);
-  loop:
-    int x = getch();
-    if (x == 'q')
-      break;
-    if (x == 'h') {
-      help(host, version);
-    }
-    if (x == 'a') {
-      absolute = stats.toggleAbsolute();
-    }
-    if (x == -1)
-      stats.getStats();
-    clear();
-  }
-  endwin();
-
-  return 0;
-}

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/d992c005/tools/tstop/.gitignore
----------------------------------------------------------------------
diff --git a/tools/tstop/.gitignore b/tools/tstop/.gitignore
new file mode 100644
index 0000000..c518e71
--- /dev/null
+++ b/tools/tstop/.gitignore
@@ -0,0 +1 @@
+tstop

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/d992c005/tools/tstop/Makefile
----------------------------------------------------------------------
diff --git a/tools/tstop/Makefile b/tools/tstop/Makefile
new file mode 100644
index 0000000..6b9a7e6
--- /dev/null
+++ b/tools/tstop/Makefile
@@ -0,0 +1,5 @@
+all: tstop.cc
+	$(CXX) $^ -o tstop -lcurl -lcurses -g -ltsutil -ltsmgmt -ltsutil -lpthread -Wl,-rpath,/usr/local/lib
+
+clean:
+	rm -f tstop

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/d992c005/tools/tstop/README
----------------------------------------------------------------------
diff --git a/tools/tstop/README b/tools/tstop/README
new file mode 100644
index 0000000..10f33b7
--- /dev/null
+++ b/tools/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/d992c005/tools/tstop/stats.h
----------------------------------------------------------------------
diff --git a/tools/tstop/stats.h b/tools/tstop/stats.h
new file mode 100644
index 0000000..8e535bc
--- /dev/null
+++ b/tools/tstop/stats.h
@@ -0,0 +1,392 @@
+/** @file
+
+    Include file for the tstop stats.
+
+    @section license License
+
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+*/
+
+#include <curl/curl.h>
+#include <map>
+#include <string>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+//#include <ts/ts.h>
+#include <inttypes.h>
+#include <ts/mgmtapi.h>
+
+using namespace std;
+
+struct LookupItem {
+  LookupItem(const char *s, const char *n, const int t): pretty(s), name(n), type(t) {}
+  LookupItem(const char *s, const char *n, const char *d, const int t): pretty(s), name(n), numerator(n), denominator(d), type(t) {}
+  const char *pretty;
+  const char *name;
+  const char *numerator;
+  const char *denominator;
+  int type;
+};
+extern size_t write_data(void *ptr, size_t size, size_t nmemb, void *stream);
+extern char curl_error[CURL_ERROR_SIZE];
+extern string response;
+
+namespace constant {
+  const char global[] = "\"global\": {\n";
+  const char start[] = "\"proxy.process.";
+  const char seperator[] = "\": \"";
+  const char end[] = "\",\n";
+};
+
+//----------------------------------------------------------------------------
+class Stats {
+public:
+  Stats(const string &host) {
+    _host = host;
+    _stats = NULL;
+    _old_stats = NULL;
+    _absolute = false;
+    lookup_table.insert(make_pair("version", LookupItem("Version", "proxy.process.version.server.short", 1)));
+    lookup_table.insert(make_pair("disk_used", LookupItem("Disk Used", "proxy.process.cache.bytes_used", 1)));
+    lookup_table.insert(make_pair("disk_total", LookupItem("Disk Total", "proxy.process.cache.bytes_total", 1)));
+    lookup_table.insert(make_pair("ram_used", LookupItem("Ram Used", "proxy.process.cache.ram_cache.bytes_used", 1)));
+    lookup_table.insert(make_pair("ram_total", LookupItem("Ram Total", "proxy.process.cache.ram_cache.total_bytes", 1)));
+    lookup_table.insert(make_pair("lookups", LookupItem("Lookups", "proxy.process.http.cache_lookups", 2)));
+    lookup_table.insert(make_pair("cache_writes", LookupItem("Writes", "proxy.process.http.cache_writes", 2)));
+    lookup_table.insert(make_pair("cache_updates", LookupItem("Updates", "proxy.process.http.cache_updates", 2)));
+    lookup_table.insert(make_pair("cache_deletes", LookupItem("Deletes", "proxy.process.http.cache_deletes", 2)));
+    lookup_table.insert(make_pair("read_active", LookupItem("Read Active", "proxy.process.cache.read.active", 1)));
+    lookup_table.insert(make_pair("write_active", LookupItem("Writes Active", "proxy.process.cache.write.active", 1)));
+    lookup_table.insert(make_pair("update_active", LookupItem("Update Active", "proxy.process.cache.update.active", 1)));
+    lookup_table.insert(make_pair("entries", LookupItem("Entries", "proxy.process.cache.direntries.used", 1)));
+    lookup_table.insert(make_pair("avg_size", LookupItem("Avg Size", "disk_used", "entries", 3)));
+
+    lookup_table.insert(make_pair("dns_time", LookupItem("DNS Time", "proxy.node.dns.lookup_avg_time_ms", 2)));
+    lookup_table.insert(make_pair("dns_hits", LookupItem("DNS hits", "proxy.node.hostdb.total_hits", 2)));
+    lookup_table.insert(make_pair("dns_lookups", LookupItem("DNS lookups", "proxy.node.hostdb.total_lookups", 2)));
+    lookup_table.insert(make_pair("client_req", LookupItem("Requests", "proxy.process.http.incoming_requests", 2)));
+    lookup_table.insert(make_pair("client_conn", LookupItem("New Conn", "proxy.process.http.total_client_connections", 2)));
+    lookup_table.insert(make_pair("client_req_conn", LookupItem("Req/Conn", "client_req", "client_conn", 3)));
+    lookup_table.insert(make_pair("client_curr_conn", LookupItem("Curr Conn", "proxy.process.http.current_client_connections", 1)));
+    lookup_table.insert(make_pair("client_actv_conn", LookupItem("Active Con", "proxy.process.http.current_active_client_connections", 1)));
+
+    lookup_table.insert(make_pair("server_req", LookupItem("Requests", "proxy.process.http.outgoing_requests", 2)));
+    lookup_table.insert(make_pair("server_conn", LookupItem("New Conn", "proxy.process.http.total_server_connections", 2)));
+    lookup_table.insert(make_pair("server_req_conn", LookupItem("Req/Conn", "server_req", "server_conn", 3)));
+    lookup_table.insert(make_pair("server_curr_conn", LookupItem("Curr Conn", "proxy.process.http.current_server_connections", 1)));
+
+
+    lookup_table.insert(make_pair("client_head", LookupItem("Head Bytes", "proxy.process.http.user_agent_response_header_total_size", 2)));
+    lookup_table.insert(make_pair("client_body", LookupItem("Body Bytes", "proxy.process.http.user_agent_response_document_total_size", 2)));
+    lookup_table.insert(make_pair("server_head", LookupItem("Head Bytes", "proxy.process.http.origin_server_response_header_total_size", 2)));
+    lookup_table.insert(make_pair("server_body", LookupItem("Body Bytes", "proxy.process.http.origin_server_response_document_total_size", 2)));
+
+    // not used directly
+    lookup_table.insert(make_pair("ram_hit", LookupItem("Ram Hit", "proxy.process.cache.ram_cache.hits", 2)));
+    lookup_table.insert(make_pair("ram_miss", LookupItem("Ram Misses", "proxy.process.cache.ram_cache.misses", 2)));
+
+
+
+    lookup_table.insert(make_pair("client_abort", LookupItem("Clnt Abort", "proxy.process.http.err_client_abort_count_stat", 2)));
+    lookup_table.insert(make_pair("conn_fail", LookupItem("Conn Fail", "proxy.process.http.err_connect_fail_count_stat", 2)));
+    lookup_table.insert(make_pair("abort", LookupItem("Abort", "proxy.process.http.transaction_counts.errors.aborts", 2)));
+    lookup_table.insert(make_pair("t_conn_fail", LookupItem("Conn Fail", "proxy.process.http.transaction_counts.errors.connect_failed", 2)));
+    lookup_table.insert(make_pair("other_err", LookupItem("Other Err", "proxy.process.http.transaction_counts.errors.other", 2)));
+    // percentage
+    lookup_table.insert(make_pair("ram_ratio", LookupItem("Ram Hit", "ram_hit", "ram_hit_miss", 4)));
+    lookup_table.insert(make_pair("dns_ratio", LookupItem("DNS Hit", "dns_hits", "dns_lookups", 4)));
+
+    // percetage of requests
+    lookup_table.insert(make_pair("fresh", LookupItem("Fresh", "proxy.process.http.transaction_counts.hit_fresh", 5)));
+    lookup_table.insert(make_pair("reval", LookupItem("Revalidate", "proxy.process.http.transaction_counts.hit_revalidated", 5)));
+    lookup_table.insert(make_pair("cold", LookupItem("Cold", "proxy.process.http.transaction_counts.miss_cold", 5)));
+    lookup_table.insert(make_pair("changed", LookupItem("Changed", "proxy.process.http.transaction_counts.miss_changed", 5)));
+    lookup_table.insert(make_pair("not", LookupItem("Not Cache", "proxy.process.http.transaction_counts.miss_not_cacheable", 5)));
+    lookup_table.insert(make_pair("no", LookupItem("No Cache", "proxy.process.http.transaction_counts.miss_client_no_cache", 5)));
+
+    lookup_table.insert(make_pair("fresh_time", LookupItem("Fresh (ms)", "proxy.process.http.transaction_totaltime.hit_fresh", "fresh", 8)));
+    lookup_table.insert(make_pair("reval_time", LookupItem("Reval (ms)", "proxy.process.http.transaction_totaltime.hit_revalidated", "reval", 8)));
+    lookup_table.insert(make_pair("cold_time", LookupItem("Cold (ms)", "proxy.process.http.transaction_totaltime.miss_cold", "cold", 8)));
+    lookup_table.insert(make_pair("changed_time", LookupItem("Chang (ms)", "proxy.process.http.transaction_totaltime.miss_changed", "changed", 8)));
+    lookup_table.insert(make_pair("not_time", LookupItem("Not (ms)", "proxy.process.http.transaction_totaltime.miss_not_cacheable", "not", 8)));
+    lookup_table.insert(make_pair("no_time", LookupItem("No (ms)", "proxy.process.http.transaction_totaltime.miss_client_no_cache", "no", 8)));
+
+    lookup_table.insert(make_pair("get", LookupItem("GET", "proxy.process.http.get_requests", 5)));
+    lookup_table.insert(make_pair("head", LookupItem("HEAD", "proxy.process.http.head_requests", 5)));
+    lookup_table.insert(make_pair("post", LookupItem("POST", "proxy.process.http.post_requests", 5)));
+    lookup_table.insert(make_pair("2xx", LookupItem("2xx", "proxy.process.http.2xx_responses", 5)));
+    lookup_table.insert(make_pair("3xx", LookupItem("3xx", "proxy.process.http.3xx_responses", 5)));
+    lookup_table.insert(make_pair("4xx", LookupItem("4xx", "proxy.process.http.4xx_responses", 5)));
+    lookup_table.insert(make_pair("5xx", LookupItem("5xx", "proxy.process.http.5xx_responses", 5)));
+
+    lookup_table.insert(make_pair("200", LookupItem("200", "proxy.process.http.200_responses", 5)));
+    lookup_table.insert(make_pair("206", LookupItem("206", "proxy.process.http.206_responses", 5)));
+    lookup_table.insert(make_pair("301", LookupItem("301", "proxy.process.http.301_responses", 5)));
+    lookup_table.insert(make_pair("302", LookupItem("302", "proxy.process.http.302_responses", 5)));
+    lookup_table.insert(make_pair("304", LookupItem("304", "proxy.process.http.304_responses", 5)));
+    lookup_table.insert(make_pair("404", LookupItem("404", "proxy.process.http.404_responses", 5)));
+    lookup_table.insert(make_pair("502", LookupItem("502", "proxy.process.http.502_responses", 5)));
+
+    lookup_table.insert(make_pair("s_100", LookupItem("100 B", "proxy.process.http.response_document_size_100", 5)));
+    lookup_table.insert(make_pair("s_1k", LookupItem("1 KB", "proxy.process.http.response_document_size_1K", 5)));
+    lookup_table.insert(make_pair("s_3k", LookupItem("3 KB", "proxy.process.http.response_document_size_3K", 5)));
+    lookup_table.insert(make_pair("s_5k", LookupItem("5 KB", "proxy.process.http.response_document_size_5K", 5)));
+    lookup_table.insert(make_pair("s_10k", LookupItem("10 KB", "proxy.process.http.response_document_size_10K", 5)));
+    lookup_table.insert(make_pair("s_1m", LookupItem("1 MB", "proxy.process.http.response_document_size_1M", 5)));
+    lookup_table.insert(make_pair("s_>1m", LookupItem("> 1 MB", "proxy.process.http.response_document_size_inf", 5)));
+
+
+    // sum together
+    lookup_table.insert(make_pair("ram_hit_miss", LookupItem("Ram Hit+Miss", "ram_hit", "ram_miss", 6)));
+    lookup_table.insert(make_pair("client_net", LookupItem("Net (bits)", "client_head", "client_body", 7)));
+    lookup_table.insert(make_pair("client_size", LookupItem("Total Size", "client_head", "client_body", 6)));
+    lookup_table.insert(make_pair("client_avg_size", LookupItem("Avg Size", "client_size", "client_req", 3)));
+
+    lookup_table.insert(make_pair("server_net", LookupItem("Net (bits)", "server_head", "server_body", 7)));
+    lookup_table.insert(make_pair("server_size", LookupItem("Total Size", "server_head", "server_body", 6)));
+    lookup_table.insert(make_pair("server_avg_size", LookupItem("Avg Size", "server_size", "server_req", 3)));
+
+
+    lookup_table.insert(make_pair("total_time", LookupItem("Total Time", "proxy.process.http.total_transactions_time", 2)));
+    lookup_table.insert(make_pair("client_req_time", LookupItem("Resp (ms)", "total_time", "client_req", 3)));
+  }
+
+  void getStats() {
+
+    if (_host == "") {
+      int64_t value;
+      if (_old_stats != NULL) {
+        delete _old_stats;
+        _old_stats = NULL;
+      }
+      _old_stats = _stats;
+      _stats = new map<string, string>;
+
+      gettimeofday(&_time, NULL);
+      double now = _time.tv_sec + (double)_time.tv_usec / 1000000;
+
+      for (map<string, LookupItem>::const_iterator lookup_it = lookup_table.begin();
+           lookup_it != lookup_table.end(); ++lookup_it) {
+        const LookupItem &item = lookup_it->second;
+
+        if (item.type == 1 || item.type == 2 || item.type == 5 || item.type == 8) {
+          if (strcmp(item.pretty, "Version") == 0) {
+            // special case for Version informaion
+            TSString strValue = NULL;
+            assert(TSRecordGetString(item.name, &strValue) == TS_ERR_OKAY);
+            string key = item.name;
+            (*_stats)[key] = strValue;
+          } else {
+            assert(TSRecordGetInt(item.name, &value) == TS_ERR_OKAY);
+            string key = item.name;
+            char buffer[32];
+            sprintf(buffer, "%lld", value);
+            string foo = buffer;
+            (*_stats)[key] = foo;
+          }
+        }
+      } 
+      _old_time = _now;
+      _now = now;
+      _time_diff = _now - _old_time;
+    } else {
+      CURL *curl;
+      CURLcode res;
+
+      curl = curl_easy_init();
+      if (curl) {
+        string url = "http://" + _host + "/_stats";
+        curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
+        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
+        curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, curl_error);
+
+        // update time
+        gettimeofday(&_time, NULL);
+        double now = _time.tv_sec + (double)_time.tv_usec / 1000000;
+
+        response.clear();
+        response.reserve(32768); // should hopefully be smaller then 32KB
+        res = curl_easy_perform(curl);
+
+        // only if success update stats and time information
+        if (res == 0) {
+          if (_old_stats != NULL) {
+            delete _old_stats;
+            _old_stats = NULL;
+          }
+          _old_stats = _stats;
+          _stats = new map<string, string>;
+
+          // parse
+          parseResponse(response);
+          _old_time = _now;
+          _now = now;
+          _time_diff = _now - _old_time;
+        }
+
+        /* always cleanup */ 
+        curl_easy_cleanup(curl);
+      }
+    }
+  }
+
+  int64_t getValue(const string &key, const map<string, string> *stats) const {
+    map<string, string>::const_iterator stats_it = stats->find(key);
+    assert(stats_it != stats->end());
+    int64_t value = atoll(stats_it->second.c_str());
+    return value;
+  }
+
+  void getStat(const string &key, double &value, int overrideType = 0) {
+    string strtmp;
+    int typetmp;
+    getStat(key, value, strtmp, typetmp, overrideType);
+  }
+
+
+  void getStat(const string &key, string &value) {
+    map<string, LookupItem>::const_iterator lookup_it = lookup_table.find(key);
+    assert(lookup_it != lookup_table.end());
+    const LookupItem &item = lookup_it->second;
+    
+    map<string, string>::const_iterator stats_it = _stats->find(item.name);
+    assert(stats_it != _stats->end());
+    value = stats_it->second.c_str();
+  }
+
+  void getStat(const string &key, double &value, string &prettyName, int &type, int overrideType = 0) {
+    map<string, LookupItem>::const_iterator lookup_it = lookup_table.find(key);
+    assert(lookup_it != lookup_table.end());
+    const LookupItem &item = lookup_it->second;
+    prettyName = item.pretty;
+    if (overrideType != 0)
+      type = overrideType;
+    else
+      type = item.type;
+
+    if (type == 1 || type == 2 || type == 5 || type == 8) {
+      value = getValue(item.name, _stats);
+      if (key == "total_time") {
+        value = value / 10000000;
+      }
+
+      if ((type == 2 || type == 5 || type == 8) && _old_stats != NULL && _absolute == false) {
+        double old = getValue(item.name, _old_stats);
+        if (key == "total_time") {
+          old = old / 10000000;
+        }
+        value = (value - old) / _time_diff;
+      }
+    } else if (type == 3 || type == 4) {
+      double numerator;
+      double denominator;
+      getStat(item.numerator, numerator);
+      getStat(item.denominator, denominator);
+      if (denominator == 0)
+        value = 0;
+      else
+        value = numerator / denominator;
+      if (type == 4) {
+        value *= 100;
+      }
+    } else if (type == 6 || type == 7) {
+      double numerator;
+      double denominator;
+      getStat(item.numerator, numerator, 2);
+      getStat(item.denominator, denominator, 2);
+      value = numerator + denominator;
+      if (type == 7)
+        value *= 8;
+    }
+
+    if (type == 8) {
+      double denominator;
+      getStat(item.denominator, denominator, 2);
+      if (denominator == 0)
+        value = 0;
+      else
+        value = value / denominator * 1000;
+    }
+
+    if (type == 5) {
+      double denominator;
+      getStat("client_req", denominator);
+      if (denominator == 0)
+        value = 0;
+      else
+        value = value / denominator * 100;
+    }
+  }
+
+  bool toggleAbsolute() {
+    if (_absolute == true)
+      _absolute = false;
+    else
+      _absolute = true;
+
+    return _absolute;
+  }
+
+  void parseResponse(const string &response) {
+    // move past global
+    size_t pos = response.find(constant::global);
+    pos += sizeof(constant::global) - 1;
+
+    // find parts of the line
+    while (1) {
+      size_t start = response.find(constant::start, pos);
+      size_t seperator = response.find(constant::seperator, pos);
+      size_t end = response.find(constant::end, pos);
+  
+      if (start == string::npos || seperator == string::npos || end == string::npos)
+        return;
+
+      //cout << constant::start << " " << start << endl;
+      //cout << constant::seperator << " " << seperator << endl;
+      //cout << constant::end << " " << end << endl;
+
+      string key = response.substr(start + 1, seperator - start - 1);
+      string value = response.substr(seperator + sizeof(constant::seperator) - 1, end - seperator - sizeof(constant::seperator) + 1);
+
+      (*_stats)[key] = value;
+      //cout << "key " << key << " " << "value " << value << endl;
+      pos = end + sizeof(constant::end) - 1;
+      //cout << "pos: " << pos << endl;
+    }
+  }
+
+  ~Stats() {
+    if (_stats != NULL) {
+      delete _stats;
+    }
+    if (_old_stats != NULL) {
+      delete _old_stats;
+    }
+  }
+
+private:
+  map<string, string> *_stats;
+  map<string, string> *_old_stats;
+  map<string, LookupItem> lookup_table;
+  string _host;
+  double _old_time;
+  double _now;
+  double _time_diff;
+  struct timeval _time;
+  bool _absolute;
+};

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/d992c005/tools/tstop/tstop.cc
----------------------------------------------------------------------
diff --git a/tools/tstop/tstop.cc b/tools/tstop/tstop.cc
new file mode 100644
index 0000000..d368530
--- /dev/null
+++ b/tools/tstop/tstop.cc
@@ -0,0 +1,379 @@
+/** @file
+
+    Main file for the tstop application.
+
+    @section license License
+
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+*/
+#include <ncurses.h>
+#include <list>
+#include <string.h>
+#include <string>
+#include <iostream>
+#include <assert.h>
+#include <map>
+#include <stdlib.h>
+#include "stats.h"
+#include <unistd.h>
+#include <getopt.h>
+
+using namespace std;
+char curl_error[CURL_ERROR_SIZE];
+string response;
+
+
+namespace colorPair {
+  const short red = 1;
+  const short yellow = 2;
+  const short green = 3;
+  const short blue = 4;
+  const short black = 5;
+  const short grey = 6;
+  const short cyan = 7;
+  const short border = 8;
+};
+
+
+//----------------------------------------------------------------------------
+int printGraphLabels(int x, int y, int width, list<const char*> lables) {
+  char buffer[256];
+  for (list<const char*>::const_iterator it = lables.begin();
+       it != lables.end(); ++it) {
+
+    char *pos = buffer;
+    pos += snprintf(buffer, 256, "%7s [", *it);
+    memset(pos, ' ', width);
+    pos += width - 1;
+    
+    strncat(pos, "]", buffer - pos);
+    
+    mvprintw(y++, x, buffer);
+  }
+  
+  //  mvprintw(x, y, 
+}
+
+
+//----------------------------------------------------------------------------
+void prettyPrint(const int x, const int y, const double number, const int type) {
+  char buffer[32];
+  char exp = ' ';
+  double my_number = number;
+  short color;
+  if (number > 1000000000000LL) {
+    my_number = number / 1000000000000;
+    exp = 'T';
+    color = colorPair::red;
+  } else if (number > 1000000000) {
+    my_number = number / 1000000000;
+    exp = 'G';
+    color = colorPair::red;
+  } else if (number > 1000000) {
+    my_number = number / 1000000;
+    exp = 'M';
+    color = colorPair::yellow;
+  } else if (number > 1000) {
+    my_number = number / 1000;
+    exp = 'K';
+    color = colorPair::cyan;
+  } else if (my_number <= .09) {
+    color = colorPair::grey;
+  } else {
+    color = colorPair::green;
+  }
+
+  if (type == 4 || type == 5) {
+    if (number > 90) {
+      color = colorPair::red;
+    } else if (number > 80) {
+      color = colorPair::yellow;
+    } else if (number > 50) {
+      color = colorPair::blue;
+    } else if (my_number <= .09) {
+      color = colorPair::grey;
+    } else {
+      color = colorPair::green;
+    }
+    snprintf(buffer, sizeof(buffer), "%6.1f%%%%", (double)my_number);
+  } else
+    snprintf(buffer, sizeof(buffer), "%6.1f%c", (double)my_number, exp);
+  attron(COLOR_PAIR(color));
+  attron(A_BOLD);
+  mvprintw(y, x, buffer);
+  attroff(COLOR_PAIR(color));
+  attroff(A_BOLD);
+}
+
+//----------------------------------------------------------------------------
+void makeTable(const int x, const int y, const list<string> &items, Stats &stats) {
+  int my_y = y;
+
+  for (list<string>::const_iterator it = items.begin(); it != items.end(); ++it) {
+    string prettyName;
+    double value;
+    int type;
+
+    stats.getStat(*it, value, prettyName, type);
+    mvprintw(my_y, x, prettyName.c_str());
+    prettyPrint(x + 10, my_y++, value, type);
+  }
+}
+
+//----------------------------------------------------------------------------
+size_t write_data(void *ptr, size_t size, size_t nmemb, void *stream)
+{
+  response.append((char*)ptr, size * nmemb);
+  //cout << "appending: " << size * nmemb << endl;
+  //int written = fwrite(ptr, size, nmemb, (FILE *)stream);
+  return size * nmemb;
+}
+
+//----------------------------------------------------------------------------
+void help(const string &host, const string &version) {
+
+  timeout(1000);
+
+  while(1) {
+    clear();
+    time_t now = time(NULL);
+    struct tm *nowtm = localtime(&now);
+    char timeBuf[32];
+    strftime(timeBuf, sizeof(timeBuf), "%H:%M:%S", nowtm);
+
+    //clear();
+    attron(A_BOLD); mvprintw(0, 0, "Overview:"); attroff(A_BOLD); 
+    mvprintw(1, 0, "tstop is a top like program for Apache Traffic Server (ATS).  There is a lot of statistical information gathered by ATS.  This program tries to show some of the more important stats and gives a good overview of what the proxy server is doing.  Hopefully this can be used as a tool to diagnosing the proxy server is there are problems.");
+
+    attron(A_BOLD); mvprintw(7, 0, "Definitions:"); attroff(A_BOLD); 
+    mvprintw(8, 0, "Fresh      => Requests that were servered by fresh entries in cache");
+    mvprintw(9, 0, "Revalidate => Requests that contacted the origin to verify if still valid");
+    mvprintw(10, 0, "Cold       => Requests that were not in cache at all");
+    mvprintw(11, 0, "Changed    => Requests that required entries in cache to be updated");
+    mvprintw(12, 0, "Changed    => Requests that can't be cached for some reason");
+    mvprintw(12, 0, "No Cache   => Requests that the client sent Cache-Control: no-cache header");
+
+    attron(COLOR_PAIR(colorPair::border));
+    attron(A_BOLD);
+    mvprintw(23, 0, "%s - %.12s - %.12s      (b)ack                            ", timeBuf, version.c_str(), host.c_str());
+    attroff(COLOR_PAIR(colorPair::border));
+    attroff(A_BOLD);
+    refresh();
+    int x = getch();
+    if (x == 'b')
+      break;
+  }
+}
+
+void usage(char **argv) {
+  fprintf(stderr, "Usage: %s [-s seconds] hostname|hostname:port\n", argv[0]);
+  exit(1);
+}
+
+
+//----------------------------------------------------------------------------
+int main(int argc, char **argv)
+{
+  int sleep_time = 5000;
+  bool absolute = false;
+  int opt;
+  while ((opt = getopt(argc, argv, "s:")) != -1) {
+    switch(opt) {
+    case 's':
+      sleep_time = atoi(optarg) * 1000;
+      break;
+    default:
+      usage(argv);
+    }
+  }
+
+  string host = "";
+  if (optind >= argc) {
+    if (TS_ERR_OKAY != TSInit(NULL, static_cast<TSInitOptionT>(TS_MGMT_OPT_NO_EVENTS | TS_MGMT_OPT_NO_SOCK_TESTS))) {
+      fprintf(stderr, "Error: missing hostname on command line or error connecting to the local manager\n");
+      usage(argv);
+    }
+  } else {
+    host = argv[optind];
+  }
+  Stats stats(host);
+
+  if (host == "") {
+    char hostname[25];
+    hostname[sizeof(hostname) - 1] = '\0';
+    gethostname(hostname, sizeof(hostname) - 1);
+    host = hostname;
+  }
+
+  initscr();
+  curs_set(0);
+  
+
+  start_color();			/* Start color functionality	*/
+  
+  init_pair(colorPair::red, COLOR_RED, COLOR_BLACK);
+  init_pair(colorPair::yellow, COLOR_YELLOW, COLOR_BLACK);
+  init_pair(colorPair::grey, COLOR_BLACK, COLOR_BLACK);
+  init_pair(colorPair::green, COLOR_GREEN, COLOR_BLACK);
+  init_pair(colorPair::blue, COLOR_BLUE, COLOR_BLACK);
+  init_pair(colorPair::cyan, COLOR_CYAN, COLOR_BLACK);
+  init_pair(colorPair::border, COLOR_WHITE, COLOR_BLUE);
+  //  mvchgat(0, 0, -1, A_BLINK, 1, NULL);
+
+  stats.getStats();
+  while(1) {
+    attron(COLOR_PAIR(colorPair::border));
+    attron(A_BOLD);
+    for (int i = 0; i <= 22; ++i) {
+      mvprintw(i, 39, " ");
+    }
+    string version;
+    time_t now = time(NULL);
+    struct tm *nowtm = localtime(&now);
+    char timeBuf[32];
+    strftime(timeBuf, sizeof(timeBuf), "%H:%M:%S", nowtm);
+    stats.getStat("version", version);
+    mvprintw(0, 0, "         CACHE INFORMATION             ");
+    mvprintw(0, 40, "       CLIENT REQUEST & RESPONSE        ");
+    mvprintw(16, 0, "             CLIENT                    ");
+    mvprintw(16, 40, "           ORIGIN SERVER                ");
+    mvprintw(23, 0, "%8.8s - %-10.10s - %-24.24s      (q)uit (h)elp (%c)bsolute  ", timeBuf, version.c_str(), host.c_str(), absolute ? 'A' : 'a');
+    attroff(COLOR_PAIR(colorPair::border));
+    attroff(A_BOLD);
+
+    list<string> cache1;
+    cache1.push_back("disk_used");
+    cache1.push_back("disk_total");
+    cache1.push_back("ram_used");
+    cache1.push_back("ram_total");
+    cache1.push_back("lookups");
+    cache1.push_back("cache_writes");
+    cache1.push_back("cache_updates");
+    cache1.push_back("cache_deletes");
+    cache1.push_back("read_active");
+    cache1.push_back("write_active");
+    cache1.push_back("update_active");
+    cache1.push_back("entries");
+    cache1.push_back("avg_size");
+    cache1.push_back("dns_lookups");
+    cache1.push_back("dns_hits");
+    makeTable(0, 1, cache1, stats);
+
+
+    list<string> cache2;
+    cache2.push_back("ram_ratio");
+    cache2.push_back("fresh");
+    cache2.push_back("reval");
+    cache2.push_back("cold");
+    cache2.push_back("changed");
+    cache2.push_back("not");
+    cache2.push_back("no");
+    cache2.push_back("fresh_time");
+    cache2.push_back("reval_time");
+    cache2.push_back("cold_time");
+    cache2.push_back("changed_time");
+    cache2.push_back("not_time");
+    cache2.push_back("no_time");
+    cache2.push_back("dns_ratio");
+    cache2.push_back("dns_time");
+    makeTable(21, 1, cache2, stats);
+
+    list<string> response1;
+    response1.push_back("get");
+    response1.push_back("head");
+    response1.push_back("post");
+    response1.push_back("2xx");
+    response1.push_back("3xx");
+    response1.push_back("4xx");
+    response1.push_back("5xx");
+    response1.push_back("conn_fail");
+    response1.push_back("other_err");
+    response1.push_back("abort");
+    makeTable(41, 1, response1, stats);
+
+
+    list<string> response2;
+    response2.push_back("200");
+    response2.push_back("206");
+    response2.push_back("301");
+    response2.push_back("302");
+    response2.push_back("304");
+    response2.push_back("404");
+    response2.push_back("502");
+    response2.push_back("s_100");
+    response2.push_back("s_1k");
+    response2.push_back("s_3k");
+    response2.push_back("s_5k");
+    response2.push_back("s_10k");
+    response2.push_back("s_1m");
+    response2.push_back("s_>1m");
+    makeTable(62, 1, response2, stats);
+
+    list<string> client1;
+    client1.push_back("client_req");
+    client1.push_back("client_req_conn");
+    client1.push_back("client_conn");
+    client1.push_back("client_curr_conn");
+    client1.push_back("client_actv_conn");
+    makeTable(0, 17, client1, stats);
+
+
+    list<string> client2;
+    client2.push_back("client_head");
+    client2.push_back("client_body");
+    client2.push_back("client_avg_size");
+    client2.push_back("client_net");
+    client2.push_back("client_req_time");
+    makeTable(21, 17, client2, stats);
+
+    list<string> server1;
+    server1.push_back("server_req");
+    server1.push_back("server_req_conn");
+    server1.push_back("server_conn");
+    server1.push_back("server_curr_conn");
+    makeTable(41, 17, server1, stats);
+
+
+    list<string> server2;
+    server2.push_back("server_head");
+    server2.push_back("server_body");
+    server2.push_back("server_avg_size");
+    server2.push_back("server_net");
+    makeTable(62, 17, server2, stats);
+
+
+    curs_set(0);
+    refresh();
+    timeout(sleep_time);
+  loop:
+    int x = getch();
+    if (x == 'q')
+      break;
+    if (x == 'h') {
+      help(host, version);
+    }
+    if (x == 'a') {
+      absolute = stats.toggleAbsolute();
+    }
+    if (x == -1)
+      stats.getStats();
+    clear();
+  }
+  endwin();
+
+  return 0;
+}