You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by am...@apache.org on 2016/10/14 15:26:14 UTC

[trafficserver] branch master updated: TS-4967: Enable header_freq logging to a specific file.

This is an automated email from the ASF dual-hosted git repository.

amc pushed a commit to branch master
in repository https://git-dual.apache.org/repos/asf/trafficserver.git

The following commit(s) were added to refs/heads/master by this push:
       new  e46d64f   TS-4967: Enable header_freq logging to a specific file.
e46d64f is described below

commit e46d64f552769eec88c473aa579f6a06919e439c
Author: Alan M. Carroll <so...@yahoo-inc.com>
AuthorDate: Thu Oct 13 10:44:12 2016 -0500

    TS-4967: Enable header_freq logging to a specific file.
---
 plugins/experimental/header_freq/README         |  23 ++++
 plugins/experimental/header_freq/header_freq.cc | 133 ++++++++++++++----------
 2 files changed, 103 insertions(+), 53 deletions(-)

diff --git a/plugins/experimental/header_freq/README b/plugins/experimental/header_freq/README
new file mode 100644
index 0000000..1ecdf20
--- /dev/null
+++ b/plugins/experimental/header_freq/README
@@ -0,0 +1,23 @@
+Apache Traffic Server Header Field Name Counter
+
+This is a plugin for ATS (Apache Traffic Server) that counts the
+number of times request header field names are used. For each request
+the name of each field is added to a running total for that name. Over
+time this provides a frequency map of header field names.
+
+
+Using the plugin
+----------------
+
+This is a global plugin and does not take any configuration. Simply add it to plugin.config.
+
+The frequency data is accessed via the plugin messaging facility. By
+default the data is sent to traffic.out but it can be appended to an
+arbitrary file. The first form logs to traffic.out, the second appends
+to /tmp/log.tx. Note that this file must be writeable to the
+traffic_server process user.
+
+    traffic_ctl plugin msg header_freq log
+
+    traffic_ctl plugin msg header_freq log:/tmp/log.txt
+
diff --git a/plugins/experimental/header_freq/header_freq.cc b/plugins/experimental/header_freq/header_freq.cc
index 53186c2..bad3d3f 100644
--- a/plugins/experimental/header_freq/header_freq.cc
+++ b/plugins/experimental/header_freq/header_freq.cc
@@ -24,40 +24,37 @@
 
 #include <iostream>
 #include <map>
-#include <sstream>
+#include <fstream>
 #include <stdlib.h>
 #include <string.h>
 #include <string>
 #include <ts/ts.h>
 
+namespace
+{
 // plugin registration info
-static char plugin_name[]   = "header_freq";
-static char vendor_name[]   = "Apache Software Foundation";
-static char support_email[] = "dev@trafficserver.apache.org";
+char PLUGIN_NAME[]   = "header_freq";
+char VENDOR_NAME[]   = "Apache Software Foundation";
+char SUPPORT_EMAIL[] = "dev@trafficserver.apache.org";
 
 // debug messages during one-time initialization
-static const char DEBUG_TAG_INIT[] = "header_freq.init";
+const char DEBUG_TAG_INIT[] = "header_freq.init";
 
 // debug messages in continuation callbacks
-static const char DEBUG_TAG_HOOK[] = "header_freq.hook";
+const char DEBUG_TAG_HOOK[] = "header_freq.hook";
 
 // maps from header name to # of times encountered
-static std::map<std::string, unsigned int> client_freq;
-static std::map<std::string, unsigned int> origin_freq;
+std::map<std::string, unsigned int> client_freq;
+std::map<std::string, unsigned int> origin_freq;
 
 // for traffic_ctl, name is a convenient identifier
-static const char *ctl_tag = plugin_name;
-static const char *ctl_log = "log"; // log all data
+const char *ctl_tag              = PLUGIN_NAME;
+const char CONTROL_MSG_LOG[]     = "log"; // log all data
+const size_t CONTROL_MSG_LOG_LEN = sizeof(CONTROL_MSG_LOG) - 1;
 
-/**
- * Logs the data collected, first the client, and then
- * the origin headers.
- */
-static void
-log_frequencies()
+void
+Log_Data(std::ostream &ss)
 {
-  std::stringstream ss("");
-
   ss << std::endl << std::string(100, '+') << std::endl;
 
   ss << "CLIENT HEADERS" << std::endl;
@@ -73,7 +70,42 @@ log_frequencies()
   }
 
   ss << std::string(100, '+') << std::endl;
-  std::cout << ss.str() << std::endl;
+}
+
+/**
+ * Logs the data collected, first the client, and then
+ * the origin headers.
+ */
+int
+CB_Command_Log(TSCont contp, TSEvent event, void *edata)
+{
+  std::string *command = static_cast<std::string *>(TSContDataGet(contp));
+  std::string::size_type colon_idx;
+
+  if (std::string::npos != (colon_idx = command->find(':'))) {
+    std::string path = command->substr(colon_idx + 1);
+    // The length of the data can include a trailing null, clip it.
+    if (path.length() > 0 && path.back() == '\0')
+      path.pop_back();
+    if (path.length() > 0) {
+      std::ofstream out;
+      out.open(path, std::ios::out | std::ios::app);
+      if (out.is_open()) {
+        Log_Data(out);
+      } else {
+        TSError("[%s] Failed to open file '%s' for logging", PLUGIN_NAME, path.c_str());
+      }
+    } else {
+      TSError("[%s] Invalid (zero length) file name for logging", PLUGIN_NAME);
+    }
+  } else {
+    Log_Data(std::cout);
+  }
+
+  // cleanup.
+  delete command;
+  TSContDestroy(contp);
+  return TS_SUCCESS;
 }
 
 /**
@@ -89,22 +121,18 @@ count_all_headers(TSMBuffer &bufp, TSMLoc &hdr_loc, std::map<std::string, unsign
   TSDebug(DEBUG_TAG_HOOK, "%d headers found", n_headers);
 
   // iterate through all headers
-  for (int i = 0; i < n_headers; ++i) {
-    if (hdr == NULL)
-      break;
-    next_hdr = TSMimeHdrFieldNext(bufp, hdr_loc, hdr);
+  for (int i = 0; i < n_headers && nullptr != hdr; ++i) {
     int hdr_len;
     const char *hdr_name = TSMimeHdrFieldNameGet(bufp, hdr_loc, hdr, &hdr_len);
-
-    std::string str = std::string(hdr_name, hdr_len);
+    std::string str      = std::string(hdr_name, hdr_len);
 
     // make case-insensitive by converting to lowercase
-    for (auto &c : str) {
+    for (auto &c : str)
       c = tolower(c);
-    }
 
     ++map[str];
 
+    next_hdr = TSMimeHdrFieldNext(bufp, hdr_loc, hdr);
     TSHandleMLocRelease(bufp, hdr_loc, hdr);
     hdr = next_hdr;
   }
@@ -116,7 +144,7 @@ count_all_headers(TSMBuffer &bufp, TSMLoc &hdr_loc, std::map<std::string, unsign
  * Continuation callback. Invoked to count headers on READ_REQUEST_HDR and
  * SEND_RESPONSE_HDR hooks and to log through traffic_ctl's LIFECYCLE_MSG.
  */
-static int
+int
 handle_hook(TSCont contp, TSEvent event, void *edata)
 {
   TSHttpTxn txnp;
@@ -131,7 +159,7 @@ handle_hook(TSCont contp, TSEvent event, void *edata)
     txnp = reinterpret_cast<TSHttpTxn>(edata);
     // get the client request so we can loop through the headers
     if (TSHttpTxnClientReqGet(txnp, &bufp, &hdr_loc) != TS_SUCCESS) {
-      TSError("(%s) could not get request headers", plugin_name);
+      TSError("[%s] could not get request headers", PLUGIN_NAME);
       TSHttpTxnReenable(txnp, TS_EVENT_HTTP_ERROR);
       ret_val = -1;
       break;
@@ -145,7 +173,7 @@ handle_hook(TSCont contp, TSEvent event, void *edata)
     // get the response so we can loop through the headers
     txnp = reinterpret_cast<TSHttpTxn>(edata);
     if (TSHttpTxnClientRespGet(txnp, &bufp, &hdr_loc) != TS_SUCCESS) {
-      TSError("(%s) could not get response headers", plugin_name);
+      TSError("[%s] could not get response headers", PLUGIN_NAME);
       TSHttpTxnReenable(txnp, TS_EVENT_HTTP_ERROR);
       ret_val = -2;
       break;
@@ -153,20 +181,23 @@ handle_hook(TSCont contp, TSEvent event, void *edata)
     count_all_headers(bufp, hdr_loc, origin_freq);
     TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
   } break;
-  case TS_EVENT_LIFECYCLE_MSG: {
-    TSDebug(DEBUG_TAG_HOOK, "event TS_EVENT_LIFECYCLE_MSG");
-    TSPluginMsg *msgp = reinterpret_cast<TSPluginMsg *>(edata);
-
-    if (strcmp(ctl_tag, msgp->tag)) {
-      TSDebug(DEBUG_TAG_HOOK, "tag %s does not concern us", msgp->tag);
-      break;
-    }
-
-    // identify the command
-    if (strncmp(ctl_log, reinterpret_cast<const char *>(msgp->data), strlen(ctl_log)) == 0) {
-      log_frequencies();
+  case TS_EVENT_LIFECYCLE_MSG: // Handle external command
+  {
+    TSPluginMsg *msgp = static_cast<TSPluginMsg *>(edata);
+
+    if (0 == strcasecmp(ctl_tag, msgp->tag)) {
+      // identify the command
+      if (msgp->data_size >= CONTROL_MSG_LOG_LEN &&
+          0 == strncasecmp(CONTROL_MSG_LOG, static_cast<char const *>(msgp->data), CONTROL_MSG_LOG_LEN)) {
+        TSDebug(DEBUG_TAG_HOOK, "Scheduled execution of '%s' command", CONTROL_MSG_LOG);
+        TSCont c = TSContCreate(CB_Command_Log, TSMutexCreate());
+        TSContDataSet(c, new std::string(static_cast<char const *>(msgp->data), msgp->data_size));
+        TSContSchedule(c, 0, TS_THREAD_POOL_TASK);
+      } else {
+        TSError("[%s] Unknown command '%.*s'", PLUGIN_NAME, static_cast<int>(msgp->data_size),
+                static_cast<char const *>(msgp->data));
+      }
     }
-
   } break;
   // do nothing in any of the other states
   default:
@@ -176,28 +207,24 @@ handle_hook(TSCont contp, TSEvent event, void *edata)
   return ret_val;
 }
 
-/**
- * Entry point for the plugin.
- */
+} // namespace
+
+/// Registration entry point for plugin.
 void
 TSPluginInit(int argc, const char *argv[])
 {
   TSDebug(DEBUG_TAG_INIT, "initializing plugin");
 
-  TSPluginRegistrationInfo info;
-
-  info.plugin_name   = plugin_name;
-  info.vendor_name   = vendor_name;
-  info.support_email = support_email;
+  TSPluginRegistrationInfo info = {PLUGIN_NAME, VENDOR_NAME, SUPPORT_EMAIL};
 
   if (TSPluginRegister(&info) != TS_SUCCESS) {
-    TSError("[%s](%s) Plugin registration failed. \n", plugin_name, __FUNCTION__);
+    TSError("[%s](%s) Plugin registration failed. \n", PLUGIN_NAME, __FUNCTION__);
   }
 
   TSCont contp = TSContCreate(handle_hook, TSMutexCreate());
   if (contp == NULL) {
     // Continuation initialization failed. Unrecoverable, report and exit.
-    TSError("(%s)[%s] could not create continuation", plugin_name, __FUNCTION__);
+    TSError("[%s](%s) could not create continuation", PLUGIN_NAME, __FUNCTION__);
     abort();
   } else {
     // Continuation initialization succeeded

-- 
To stop receiving notification emails like this one, please contact
['"commits@trafficserver.apache.org" <co...@trafficserver.apache.org>'].