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

zwoop 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  65bb454   TS-5069: enhanced logstats to report stats per user
65bb454 is described below

commit 65bb454fcdb057db28b6c622abce0b0aee22ee96
Author: Gancho Tenev <[email protected]>
AuthorDate: Tue Nov 29 21:55:21 2016 -0800

    TS-5069: enhanced logstats to report stats per user
---
 proxy/logstats.cc | 137 +++++++++++++++++++++++++++++++++---------------------
 1 file changed, 85 insertions(+), 52 deletions(-)

diff --git a/proxy/logstats.cc b/proxy/logstats.cc
index 179b1fa..60cb483 100644
--- a/proxy/logstats.cc
+++ b/proxy/logstats.cc
@@ -594,15 +594,16 @@ struct CommandLineArgs {
   int64_t min_hits;
   int max_age;
   int line_len;
-  int incremental; // Do an incremental run
-  int tail;        // Tail the log file
-  int summary;     // Summary only
-  int json;        // JSON output
-  int cgi;         // CGI output (typically with json)
-  int urls;        // Produce JSON output of URL stats, arg is LRU size
-  int show_urls;   // Max URLs to show
-  int as_object;   // Show the URL stats as a single JSON object (not array)
-  int concise;     // Eliminate metrics that can be inferred by other values
+  int incremental;     // Do an incremental run
+  int tail;            // Tail the log file
+  int summary;         // Summary only
+  int json;            // JSON output
+  int cgi;             // CGI output (typically with json)
+  int urls;            // Produce JSON output of URL stats, arg is LRU size
+  int show_urls;       // Max URLs to show
+  int as_object;       // Show the URL stats as a single JSON object (not 
array)
+  int concise;         // Eliminate metrics that can be inferred by other 
values
+  int report_per_user; // A flag to aggregate and report stats per user 
instead of per host if 'true' (default 'false')
 
   CommandLineArgs()
     : max_origins(0),
@@ -617,7 +618,8 @@ struct CommandLineArgs {
       urls(0),
       show_urls(0),
       as_object(0),
-      concise(0)
+      concise(0),
+      report_per_user(0)
   {
     log_file[0]    = '\0';
     origin_file[0] = '\0';
@@ -649,6 +651,7 @@ static ArgumentDescription argument_descriptions[] = {
   {"max_age", 'a', "Max age for log entries to be considered", "I", 
&cl.max_age, NULL, NULL},
   {"line_len", 'l', "Output line length", "I", &cl.line_len, NULL, NULL},
   {"debug_tags", 'T', "Colon-Separated Debug Tags", "S1023", &error_tags, 
NULL, NULL},
+  {"report_per_user", 'r', "Report stats per user instead of host", "T", 
&cl.report_per_user, NULL, NULL},
   HELP_ARGUMENT_DESCRIPTION(),
   VERSION_ARGUMENT_DESCRIPTION()};
 
@@ -1164,16 +1167,64 @@ update_schemes(OriginStats *stat, int scheme, int size)
 }
 
 ///////////////////////////////////////////////////////////////////////////////
+// Finds or creates a stats structures if missing
+OriginStats *
+find_or_create_stats(const char *key)
+{
+  OriginStats *o_stats = NULL;
+  OriginStorage::iterator o_iter;
+  char *o_server = NULL;
+
+  // TODO: If we save state (struct) for a run, we probably need to always
+  // update the origin data, no matter what the origin_set is.
+  if (origin_set->empty() || (origin_set->find(key) != origin_set->end())) {
+    o_iter = origins.find(key);
+    if (origins.end() == o_iter) {
+      o_stats = (OriginStats *)ats_malloc(sizeof(OriginStats));
+      memset(o_stats, 0, sizeof(OriginStats));
+      init_elapsed(o_stats);
+      o_server = ats_strdup(key);
+      if (o_stats && o_server) {
+        o_stats->server   = o_server;
+        origins[o_server] = o_stats;
+      }
+    } else {
+      o_stats = o_iter->second;
+    }
+  }
+  return o_stats;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Update the stats
+void
+update_stats(OriginStats *o_stats, const HTTPMethod method, URLScheme scheme, 
int http_code, int size, int result, int hier,
+             int elapsed)
+{
+  update_results_elapsed(&totals, result, elapsed, size);
+  update_codes(&totals, http_code, size);
+  update_methods(&totals, method, size);
+  update_schemes(&totals, scheme, size);
+  update_counter(totals.total, size);
+  if (NULL != o_stats) {
+    update_results_elapsed(o_stats, result, elapsed, size);
+    update_codes(o_stats, http_code, size);
+    update_methods(o_stats, method, size);
+    update_schemes(o_stats, scheme, size);
+    update_counter(o_stats->total, size);
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
 // Parse a log buffer
 int
-parse_log_buff(LogBufferHeader *buf_header, bool summary = false)
+parse_log_buff(LogBufferHeader *buf_header, bool summary = false, bool 
aggregate_per_userid = false)
 {
   static LogFieldList *fieldlist = NULL;
 
   LogEntryHeader *entry;
   LogBufferIterator buf_iter(buf_header);
   LogField *field;
-  OriginStorage::iterator o_iter;
   ParseStates state;
 
   char *read_from;
@@ -1185,7 +1236,6 @@ parse_log_buff(LogBufferHeader *buf_header, bool summary 
= false)
   // Parsed results
   int http_code = 0, size = 0, result = 0, hier = 0, elapsed = 0;
   OriginStats *o_stats;
-  char *o_server;
   HTTPMethod method;
   URLScheme scheme;
 
@@ -1205,11 +1255,10 @@ parse_log_buff(LogBufferHeader *buf_header, bool 
summary = false)
       break;
     }
 
-    state    = P_STATE_ELAPSED;
-    o_stats  = NULL;
-    o_server = NULL;
-    method   = METHOD_OTHER;
-    scheme   = SCHEME_OTHER;
+    state   = P_STATE_ELAPSED;
+    o_stats = NULL;
+    method  = METHOD_OTHER;
+    scheme  = SCHEME_OTHER;
 
     while ((field = fieldlist->next(field))) {
       switch (state) {
@@ -1342,26 +1391,11 @@ parse_log_buff(LogBufferHeader *buf_header, bool 
summary = false)
             tok++;
           }
           ptr = strchr(tok, '/');
-          if (ptr && !summary) { // Find the origin
+          if (ptr) {
             *ptr = '\0';
-
-            // TODO: If we save state (struct) for a run, we probably need to 
always
-            // update the origin data, no matter what the origin_set is.
-            if (origin_set->empty() || (origin_set->find(tok) != 
origin_set->end())) {
-              o_iter = origins.find(tok);
-              if (origins.end() == o_iter) {
-                o_stats = (OriginStats *)ats_malloc(sizeof(OriginStats));
-                memset(o_stats, 0, sizeof(OriginStats));
-                init_elapsed(o_stats);
-                o_server = ats_strdup(tok);
-                if (o_stats && o_server) {
-                  o_stats->server   = o_server;
-                  origins[o_server] = o_stats;
-                }
-              } else {
-                o_stats = o_iter->second;
-              }
-            }
+          }
+          if (!aggregate_per_userid && !summary) {
+            o_stats = find_or_create_stats(tok);
           }
         } else {
           // No method given
@@ -1371,24 +1405,21 @@ parse_log_buff(LogBufferHeader *buf_header, bool 
summary = false)
           tok_len = strlen(read_from);
         }
         read_from += LogAccess::round_strlen(tok_len + 1);
-
-        // Update the stats so far, since now we have the Origin (maybe)
-        update_results_elapsed(&totals, result, elapsed, size);
-        update_codes(&totals, http_code, size);
-        update_methods(&totals, method, size);
-        update_schemes(&totals, scheme, size);
-        update_counter(totals.total, size);
-        if (o_stats != NULL) {
-          update_results_elapsed(o_stats, result, elapsed, size);
-          update_codes(o_stats, http_code, size);
-          update_methods(o_stats, method, size);
-          update_schemes(o_stats, scheme, size);
-          update_counter(o_stats->total, size);
+        if (!aggregate_per_userid) {
+          update_stats(o_stats, method, scheme, http_code, size, result, hier, 
elapsed);
         }
         break;
 
       case P_STATE_RFC931:
         state = P_STATE_HIERARCHY;
+
+        if (aggregate_per_userid) {
+          if (!summary) {
+            o_stats = find_or_create_stats(read_from);
+          }
+          update_stats(o_stats, method, scheme, http_code, size, result, hier, 
elapsed);
+        }
+
         if ('-' == *read_from) {
           read_from += LogAccess::round_strlen(1 + 1);
         } else {
@@ -1792,7 +1823,7 @@ process_file(int in_fd, off_t offset, unsigned max_age)
 
     // Possibly skip too old entries (the entire buffer is skipped)
     if (header->high_timestamp >= max_age) {
-      if (parse_log_buff(header, cl.summary != 0) != 0) {
+      if (parse_log_buff(header, cl.summary != 0, cl.report_per_user != 0) != 
0) {
         Debug("logstats", "Failed to parse log buffer.");
         return 1;
       }
@@ -1810,7 +1841,9 @@ process_file(int in_fd, off_t offset, unsigned max_age)
 inline int
 use_origin(const OriginStats *stat)
 {
-  return ((stat->total.count > cl.min_hits) && (NULL != strchr(stat->server, 
'.')) && (NULL == strchr(stat->server, '%')));
+  return cl.report_per_user != 0 ?
+           (stat->total.count > cl.min_hits) :
+           ((stat->total.count > cl.min_hits) && (NULL != strchr(stat->server, 
'.')) && (NULL == strchr(stat->server, '%')));
 }
 
 ///////////////////////////////////////////////////////////////////////////////

-- 
To stop receiving notification emails like this one, please contact
['"[email protected]" <[email protected]>'].

Reply via email to