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 2016/01/22 04:23:56 UTC

[08/10] trafficserver git commit: TS-4099: add automatic metrics namespace management

TS-4099: add automatic metrics namespace management

Rather than hardcoding the set of metrics namespace prefixes, poll
it at runtime. We keep polling until the namespace converges and
periodically thereafter to account for metrics created by plugins.


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

Branch: refs/heads/master
Commit: b547b651b662af16f6866d524b7661176e2b2e92
Parents: 4e44756
Author: James Peach <jp...@apache.org>
Authored: Wed Dec 30 16:36:24 2015 -0800
Committer: James Peach <jp...@apache.org>
Committed: Thu Jan 21 19:21:30 2016 -0800

----------------------------------------------------------------------
 cmd/traffic_manager/metrics.cc | 77 +++++++++++++++----------------------
 lib/bindings/bindings.cc       | 73 +++++++++++++++++++++++++++--------
 lib/bindings/bindings.h        |  8 ++--
 lib/bindings/metrics.cc        | 42 ++++++++++++++++++++
 lib/bindings/metrics.h         |  7 ++++
 5 files changed, 142 insertions(+), 65 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/trafficserver/blob/b547b651/cmd/traffic_manager/metrics.cc
----------------------------------------------------------------------
diff --git a/cmd/traffic_manager/metrics.cc b/cmd/traffic_manager/metrics.cc
index 7bc5bec..9608a60 100644
--- a/cmd/traffic_manager/metrics.cc
+++ b/cmd/traffic_manager/metrics.cc
@@ -127,7 +127,7 @@ private:
 };
 
 struct EvaluatorList {
-  EvaluatorList() : passes(0) {}
+  EvaluatorList() : update(true), passes(0) {}
   ~EvaluatorList()
   {
     forv_Vec(Evaluator, e, this->evaluators) { delete e; }
@@ -147,15 +147,27 @@ struct EvaluatorList {
 
     forv_Vec(Evaluator, e, this->evaluators) { e->eval(L); }
 
-
     elapsed = ink_hrtime_diff(ink_get_hrtime_internal(), start);
     Debug("lua", "evaluated %u metrics in %fmsec", evaluators.length(), ink_hrtime_to_usec(elapsed) / 1000.0);
   }
 
+  bool update;
   int64_t passes;
   Vec<Evaluator *> evaluators;
 };
 
+static int
+update_metrics_namespace(lua_State *L)
+{
+  lua_Integer count;
+
+  lua_metrics_install(L);
+  count = lua_tointeger(L, 1);
+  lua_pop(L, 1);
+
+  return count;
+}
+
 static int64_t
 timestamp_now_msec()
 {
@@ -305,46 +317,6 @@ metrics_cluster_sum(lua_State *L)
   return 1;
 }
 
-static void
-register_metrics_namespace(BindingInstance &binding)
-{
-  // XXX Currently known metrics namespace prefixes. Figure out a way to
-  // add new metrics nodes as new prefixes are added.
-  const char *prefixes[] = {
-    "proxy.cluster", "proxy.cluster.cache", "proxy.cluster.cache.contents", "proxy.cluster.dns", "proxy.cluster.hostdb",
-    "proxy.cluster.http", "proxy.cluster.log", "proxy.node", "proxy.node.cache", "proxy.node.cache.contents", "proxy.node.cluster",
-    "proxy.node.config", "proxy.node.config.restart_required", "proxy.node.dns", "proxy.node.hostdb", "proxy.node.http",
-    "proxy.node.http.transaction_counts_avg_10s", "proxy.node.http.transaction_counts_avg_10s.errors",
-    "proxy.node.http.transaction_counts_avg_10s.other", "proxy.node.http.transaction_frac_avg_10s",
-    "proxy.node.http.transaction_frac_avg_10s.errors", "proxy.node.http.transaction_frac_avg_10s.other",
-    "proxy.node.http.transaction_msec_avg_10s", "proxy.node.http.transaction_msec_avg_10s.errors",
-    "proxy.node.http.transaction_msec_avg_10s.other", "proxy.node.log", "proxy.node.restarts.manager", "proxy.node.restarts.proxy",
-    "proxy.node.version.manager", "proxy.process.cache", "proxy.process.cache.direntries", "proxy.process.cache.evacuate",
-    "proxy.process.cache.frags_per_doc", "proxy.process.cache.frags_per_doc.3+", "proxy.process.cache.lookup",
-    "proxy.process.cache.ram_cache", "proxy.process.cache.read", "proxy.process.cache.read_busy", "proxy.process.cache.remove",
-    "proxy.process.cache.scan", "proxy.process.cache.sync", "proxy.process.cache.update", "proxy.process.cache.write",
-    "proxy.process.cache.write.backlog", "proxy.process.cluster", "proxy.process.congestion", "proxy.process.dns",
-    "proxy.process.hostdb", "proxy.process.http", "proxy.process.http.milestone", "proxy.process.http.transaction_counts",
-    "proxy.process.http.transaction_counts.errors", "proxy.process.http.transaction_counts.hit_fresh",
-    "proxy.process.http.transaction_counts.other", "proxy.process.http.transaction_totaltime",
-    "proxy.process.http.transaction_totaltime.errors", "proxy.process.http.transaction_totaltime.hit_fresh",
-    "proxy.process.http.transaction_totaltime.other", "proxy.process.http.websocket", "proxy.process.http2", "proxy.process.https",
-    "proxy.process.log", "proxy.process.net", "proxy.process.socks", "proxy.process.ssl", "proxy.process.ssl.cipher.user_agent",
-    "proxy.process.version.server",
-  };
-
-  // Register the metrics userdata type.
-  lua_metrics_register(binding.lua);
-
-  // Bind metric nodes to all the metrics namespace prefixes.
-  for (unsigned i = 0; i < countof(prefixes); ++i) {
-    if (lua_metrics_new(prefixes[i], binding.lua) == 1) {
-      binding.bind_value(prefixes[i], -1);
-      lua_pop(binding.lua, 1);
-    }
-  }
-}
-
 bool
 metrics_binding_initialize(BindingInstance &binding)
 {
@@ -355,8 +327,9 @@ metrics_binding_initialize(BindingInstance &binding)
     mgmt_fatal(stderr, 0, "failed to initialize Lua runtime\n");
   }
 
-  // Register the metrics bindings.
-  register_metrics_namespace(binding);
+  // Register the metrics userdata type.
+  lua_metrics_register(binding.lua);
+  update_metrics_namespace(binding.lua);
 
   // Register our own API.
   binding.bind_function("integer", metrics_create_integer);
@@ -371,7 +344,11 @@ metrics_binding_initialize(BindingInstance &binding)
   binding.attach_ptr("evaluators", new EvaluatorList());
 
   // Finally, execute the config file.
-  return binding.require(config.get());
+  if (binding.require(config.get())) {
+    return true;
+  }
+
+  return false;
 }
 
 void
@@ -392,7 +369,17 @@ metrics_binding_evaluate(BindingInstance &binding)
   evaluators = (EvaluatorList *)binding.retrieve_ptr("evaluators");
   ink_release_assert(evaluators != NULL);
 
+  // Keep updating the namespace until it settles (ie. we make 0 updates).
+  if (evaluators->update) {
+    evaluators->update = update_metrics_namespace(binding.lua) ? true : false;
+  }
+
   binding.bind_constant("metrics.now.msec", timestamp_now_msec());
   binding.bind_constant("metrics.update.pass", ++evaluators->passes);
   evaluators->evaluate(binding.lua);
+
+  // Periodically refresh the namespace to catch newly added metrics.
+  if (evaluators->passes % 10 == 0) {
+    evaluators->update = true;
+  }
 }

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/b547b651/lib/bindings/bindings.cc
----------------------------------------------------------------------
diff --git a/lib/bindings/bindings.cc b/lib/bindings/bindings.cc
index 9cd01b8..d189e52 100644
--- a/lib/bindings/bindings.cc
+++ b/lib/bindings/bindings.cc
@@ -56,36 +56,49 @@ BindingInstance::retrieve_ptr(const char *name)
   return (ptr == this->attachments.end()) ? NULL : ptr->second;
 }
 
-void
+bool
 BindingInstance::bind_constant(const char *name, lua_Integer value)
 {
+  bool bound;
+
   lua_pushinteger(this->lua, value);
-  this->bind_value(name, -1);
+  bound = this->bind_value(name, -1);
   lua_pop(this->lua, 1);
+
+  return bound;
 }
 
-void
+bool
 BindingInstance::bind_constant(const char *name, const char *value)
 {
+  bool bound;
+
   lua_pushlstring(this->lua, value, strlen(value));
-  this->bind_value(name, -1);
+  bound = this->bind_value(name, -1);
   lua_pop(this->lua, 1);
+
+  return bound;
 }
 
-void
+bool
 BindingInstance::bind_function(const char *name, int (*value)(lua_State *))
 {
+  bool bound;
+
   lua_pushcfunction(this->lua, value);
-  this->bind_value(name, -1);
+  bound = this->bind_value(name, -1);
   lua_pop(this->lua, 1);
+
+  return bound;
 }
 
 // Bind an arbitrary Lua value from the give stack position.
-void
+bool
 BindingInstance::bind_value(const char *name, int value)
 {
-  const char * start = name;
-  const char * end = name;
+  const char *start = name;
+  const char *end = name;
+  bool bound = false;
 
   int depth = 0;
 
@@ -161,18 +174,48 @@ BindingInstance::bind_value(const char *name, int value)
   // If we pushed a series of tables onto the stack, bind the name to a table
   // entry. otherwise bind it as a global name.
   if (depth) {
+    bool isnil;
+
+    // At this point the top of stack should be something indexable.
+    ink_assert(is_indexable(this->lua, -1));
+
+    Debug("lua", "stack depth is %d (expected %d)\n", lua_gettop(this->lua), depth);
+    // Push the index name.
     lua_pushstring(this->lua, start);
-    lua_pushvalue(this->lua, value);
 
-    ink_assert(is_indexable(this->lua, -3));
+    Debug("lua", "stack depth is %d (expected %d)\n", lua_gettop(this->lua), depth);
+    // Fetch the index (without metamethods);
+    lua_gettable(this->lua, -2);
+
+    // Only push the value if it is currently nil.
+    isnil = lua_isnil(this->lua, -1);
+    lua_pop(this->lua, 1);
+    Debug("lua", "isnil? %s", isnil ? "yes" : "no");
+
+    if (isnil) {
+      lua_pushstring(this->lua, start);
+      lua_pushvalue(this->lua, value);
+      lua_settable(this->lua, -3);
+      bound = true;
+    }
 
-    lua_settable(this->lua, -3);
     Debug("lua", "stack depth is %d (expected %d)\n", lua_gettop(this->lua), depth);
     lua_pop(this->lua, depth);
   } else {
-    lua_pushvalue(this->lua, value);
-    lua_setglobal(this->lua, start);
+    bool isnil;
+
+    lua_getglobal(this->lua, start);
+    isnil = lua_isnil(this->lua, -1);
+    lua_pop(this->lua, 1);
+
+    if (isnil) {
+      lua_pushvalue(this->lua, value);
+      lua_setglobal(this->lua, start);
+      bound = true;
+    }
   }
+
+  return bound;
 }
 
 bool
@@ -271,5 +314,3 @@ BindingInstance::register_metatable(lua_State *lua, const char *name, const luaL
 
   ink_assert(lua_gettop(lua) == 0);
 }
-
-/* vim: set sw=4 ts=4 tw=79 et: */

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/b547b651/lib/bindings/bindings.h
----------------------------------------------------------------------
diff --git a/lib/bindings/bindings.h b/lib/bindings/bindings.h
index 525cb60..55f78a0 100644
--- a/lib/bindings/bindings.h
+++ b/lib/bindings/bindings.h
@@ -41,10 +41,10 @@ struct BindingInstance {
   // Bind values to the specified global name. If the name contains '.'
   // separators, intermediate tables are constucted and the value is bound
   // to the final path component.
-  void bind_constant(const char *name, lua_Integer value);
-  void bind_constant(const char *name, const char *value);
-  void bind_function(const char *name, int (*value)(lua_State *));
-  void bind_value(const char *name, int value);
+  bool bind_constant(const char *name, lua_Integer value);
+  bool bind_constant(const char *name, const char *value);
+  bool bind_function(const char *name, int (*value)(lua_State *));
+  bool bind_value(const char *name, int value);
 
   // Attach a named pointer that we can later fish out from a Lua state.
   void attach_ptr(const char *, void *);

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/b547b651/lib/bindings/metrics.cc
----------------------------------------------------------------------
diff --git a/lib/bindings/metrics.cc b/lib/bindings/metrics.cc
index 66dbacf..ae148ee 100644
--- a/lib/bindings/metrics.cc
+++ b/lib/bindings/metrics.cc
@@ -26,6 +26,7 @@
 #include "P_RecCore.h"
 #include "ts/ink_memory.h"
 #include <map>
+#include <set>
 
 #define BINDING "lua.metrics"
 
@@ -199,3 +200,44 @@ lua_metrics_register(lua_State *L)
 
   BindingInstance::register_metatable(L, BINDING, metatable);
 }
+
+static void
+install_metrics_object(RecT rec_type, void *edata, int registered, const char *name, int data_type, RecData *datum)
+{
+  std::set<std::string> *prefixes = (std::set<std::string> *)edata;
+
+  if (likely(registered)) {
+    const char *end = strrchr(name, '.');
+    ptrdiff_t len = end - name;
+    prefixes->insert(std::string(name, len));
+  }
+}
+
+int
+lua_metrics_install(lua_State *L)
+{
+  int count = 0;
+  int metrics_type = RECT_NODE | RECT_PROCESS | RECT_CLUSTER | RECT_PLUGIN;
+  BindingInstance *binding = BindingInstance::self(L);
+  std::set<std::string> prefixes;
+
+  // Gather all the metrics namespace prefixes into a sorted set. We want to install
+  // metrics objects as the last branch of the namespace so that leaf metrics lookup
+  // end up indexing metrics objects.
+  RecDumpRecords((RecT)metrics_type, install_metrics_object, &prefixes);
+
+  for (std::set<std::string>::const_iterator p = prefixes.cbegin(); p != prefixes.cend(); ++p) {
+    if (lua_metrics_new(p->c_str(), binding->lua) == 1) {
+      if (binding->bind_value(p->c_str(), -1)) {
+        Debug("lua", "installed metrics object at prefix %s", p->c_str());
+        ++count;
+      }
+
+      lua_pop(binding->lua, 1);
+    }
+  }
+
+  // Return the number of metrics we installed;
+  lua_pushinteger(L, count);
+  return 1;
+}

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/b547b651/lib/bindings/metrics.h
----------------------------------------------------------------------
diff --git a/lib/bindings/metrics.h b/lib/bindings/metrics.h
index e0d39ac..9e42c16 100644
--- a/lib/bindings/metrics.h
+++ b/lib/bindings/metrics.h
@@ -30,4 +30,11 @@ int lua_metrics_new(const char *prefix, lua_State *L);
 // Register metrics binding type metatable.
 void lua_metrics_register(lua_State *L);
 
+// Install new metrics objects into the global namespace. This function
+// iterates over all the registered metrics and installs a metrics
+// object at the global name given by the metric's prefix. For example,
+// if the metric is named "proxy.my.great.counter", it would install
+// a metrics object at the global name "proxy.my.great".
+int lua_metrics_install(lua_State *L);
+
 #endif /* METRICS_H_FED1F5EA_9EDE_48E6_B05A_5DCAFD8DC319 */