Add network_event_log_summary.js to support network UI logs

Bug: 1054951
Change-Id: I2ff40c59ee06488e24ebcbda1bd042a5b366c917
diff --git a/Gruntfile.js b/Gruntfile.js
index 2b0e7c3..6d349c0 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -27,6 +27,7 @@
           './log_summary.js',
           './manager.js',
           './netlog_summary.js',
+          './network_event_log_summary.js',
           './process_log.js',
           './service.js',
           './state_graph.js',
@@ -70,6 +71,7 @@
       'manager.js',
       'manifest.json',
       'netlog_summary.js',
+      'network_event_log_summary.js',
       'popup.js',
       'process_log.js',
       'service.js',
diff --git a/log_helper.js b/log_helper.js
index 47e5ce4..f33d415 100644
--- a/log_helper.js
+++ b/log_helper.js
@@ -16,10 +16,10 @@
 logHelper.NET_LOG_START = /netlog=<multiline>/;
 
 /**
- * RegExp for netlog end.
+ * RegExp for network_event_log (UI) start.
  * @type {RegExp}
  */
-logHelper.NET_LOG_END = /---------- END ----------/;
+logHelper.NETWORK_EVENT_LOG_START = /network_event_log=<multiline>/;
 
 /**
  * RegExp for syslog start.
@@ -211,6 +211,17 @@
       return i + logHolder.netlog.length;
     }
   },
+  'network_event_log_multiline': {
+    re: logHelper.NETWORK_EVENT_LOG_START,
+    handler: function(logHolder, logLines, i) {
+      // we have a network_event_log section of a system_log
+      logHolder.fileType = 'system_log';
+      logHolder.networkEventLog = logHelper.getSubLog(logLines, i);
+      console.log('found the network_event_log section!: ' +
+                  logHolder.networkEventLog.length);
+      return i + logHolder.networkEventLog.length;
+    }
+  },
   'syslog_multiline': {
     re: logHelper.SYS_LOG_START,
     handler: function(logHolder, logLines, i) {
diff --git a/network_event_log_summary.js b/network_event_log_summary.js
new file mode 100644
index 0000000..0bcebd2
--- /dev/null
+++ b/network_event_log_summary.js
@@ -0,0 +1,86 @@
+// Copyright 2020 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+'use strict';
+
+/**
+ * @fileoverview Class for processing network_event_log messages.
+ */
+
+let networkEventLogSummary = {};
+
+/**
+ * Objects holding regexs and handlers for log subsections
+ * @type {Object}
+ */
+networkEventLogSummary.taggedLines = {
+  'error': {
+    re: /(ERROR )(.*$)/,
+    handler: function(result) {
+      return 'error';
+    }
+  },
+  'user': {
+    re: /(USER )(.*$)/,
+    handler: function(result) {
+      return 'user';
+    }
+  },
+};
+
+/**
+ * @param {Array<string>} logLines
+ * @param {LogSummary} logSummary
+ * @return {Array<Object>} Returns an Array of Objects with text and anchor
+ *     labels if the log was processed, null if |logLines| is invalid.
+ */
+networkEventLogSummary.processLogLines = function(logLines, logSummary) {
+  const logType = 'eventLog';
+  let logStart = -1;
+  let logText = [];
+
+  for (var i = 0; i < logLines.length; i++) {
+    // do we have a start time?
+    const time = logLines[i].match(logHelper.TIME_FORMAT);
+    if (time == null) {
+      console.log('logline: ', logLines[i]);
+      console.log('not a valid time...  continue');
+      continue;
+    }
+    logHelper.getOffsetMS(time);
+    const timeCheck = Date.parse(time[0]);
+    if (logStart == -1 && time !== null) {
+      logStart = time[0];
+      logSummary.logStartTime = timeCheck;
+      logSummary.prevLogLineTime = logSummary.logStartTime;
+    }
+    if (timeCheck < logSummary.logEndTime) {
+      console.log('warning: log time has rolled back, check timezone');
+    } else {
+      logSummary.logEndTime = timeCheck;
+      logSummary.prevLogLineTime = timeCheck;
+    }
+    console.log('log_line: ' + logLines[i]);
+    var tempLogText = {text: logLines[i],
+                       tag: null,
+                       type: 'basic',
+                       file: logType,
+                       ts: timeCheck};
+    for (var taggedLine in networkEventLogSummary.taggedLines) {
+      var result =
+          logLines[i].match(networkEventLogSummary.taggedLines[taggedLine].re);
+      if (result !== null) {
+        tempLogText.type =
+            networkEventLogSummary.taggedLines[taggedLine].handler(result);
+        tempLogText.tag = time[0];
+        break;
+      }
+    }
+
+    logText.push(tempLogText);
+  }
+
+  console.log('this is the end of our log...');
+
+  return logText;
+};
diff --git a/process_log.js b/process_log.js
index 62621b0..1c680e2 100644
--- a/process_log.js
+++ b/process_log.js
@@ -116,6 +116,11 @@
         logHolder.netlog = netlogSummary.processLogLines(logHolder.netlog,
                                                          logSummary);
       }
+      if (logHolder.networkEventLog) {
+        console.log('processing network_event_log');
+        logHolder.networkEventLog = networkEventLogSummary.processLogLines(
+            logHolder.networkEventLog, logSummary);
+      }
       if (logHolder.syslog) {
         console.log('processing syslog');
         logHolder.syslog = syslogSummary.processLogLines(logHolder.syslog,
@@ -130,7 +135,7 @@
         displayAndroidLogSummary(logSummary);
       }
 
-      if (logHolder.syslog || logHolder.netlog ||
+      if (logHolder.syslog || logHolder.netlog || logHolder.networkEventLog ||
           logHolder.brillolog || logHolder.androidlog) {
         displayLog(logHolder);
       } else {
@@ -574,56 +579,52 @@
 }
 
 /**
+ * @param {Array<Array<Object>>} logs
+ * @param {Array<Object>} log
+ * @private
+ */
+function addLog(logs, log) {
+  if (!log || log.length <= 0)
+    return;
+  logs.push(log);
+}
+
+/**
  * Method to display the log lines after the summary by appending a preformatted
- * (<pre>) element to the document.
+ * (<pre>) element to the document. Note: This clears the logs in logHolder.
  *
- * @param {Object[]} logHolder Object holding log subsections.
+ * @param {Object} logHolder Object holding log subsections.
  * @private
  */
 function displayLog(logHolder) {
   var mergedLog = [];
   // merge all log types together...
-  var netLength = 0;
-  if (logHolder.netlog)
-    netLength = logHolder.netlog.length;
-  if (logHolder.brillolog) {
-    if (logHolder.netlog) {
-      console.error('processor holds netlog and brillo log - error!');
-      return;
-    }
-    netLength = logHolder.brillolog.length;
-    logHolder.netlog = logHolder.brillolog;
-  }
-  var sysLength = 0;
-  if (logHolder.syslog)
-    sysLength = logHolder.syslog.length;
+  var logs = [];
+  addLog(logs, logHolder.netlog);
+  addLog(logs, logHolder.brillolog);
+  addLog(logs, logHolder.networkEventLog);
+  addLog(logs, logHolder.syslog);
+  addLog(logs, logHolder.androidlog);
 
-  if (logHolder.androidlog) {
-    console.log('attempting to display an android log');
-    netLength = logHolder.androidlog.length;
-    logHolder.netlog = logHolder.androidlog;
-  }
-
-  while (netLength > 0 || sysLength > 0) {
-    if (netLength == 0) {
-      mergedLog.appendLog(logHolder.syslog);
-      sysLength = 0;
-    } else if (sysLength == 0) {
-      mergedLog.appendLog(logHolder.netlog);
-      netLength = 0;
-    } else {
-      if (logHolder.netlog[0].ts < logHolder.syslog[0].ts) {
-        mergedLog.push(logHolder.netlog.shift());
-        netLength -= 1;
-      } else if (logHolder.netlog[0].ts > logHolder.syslog[0].ts) {
-        mergedLog.push(logHolder.syslog.shift());
-        sysLength -= 1;
-      } else {
-        //the log times are equal - grab them both for proper interleaving
-        mergedLog.push(logHolder.syslog.shift());
-        sysLength -= 1;
-        mergedLog.push(logHolder.netlog.shift());
-        netLength -= 1;
+  while (logs.length > 0) {
+    var logIdx;
+    var minTs;
+    logs.forEach((log, i) => {
+      var logTs = log[0].ts;
+      if (i == 0 || logTs < minTs) {
+        logIdx = i;
+        minTs = logTs;
+      }
+    });
+    var log = logs[logIdx];
+    mergedLog.push(log.shift());
+    if (log.length == 0) {
+      logs.splice(logIdx, 1);
+      if (logs.length == 1) {
+        logs[0].forEach(entry => {
+          mergedLog.push(entry);
+        });
+        break;
       }
     }
   }
@@ -689,16 +690,3 @@
   }
   logTextHeader.appendChild(logText);
 }
-
-/**
- * Helper method to move and append one log to another.
- *
- * @param {Object[]} toCopy LogLine entries to move.
- */
-Array.prototype.appendLog = function(toCopy) {
-  toCopy.forEach(function(x) {
-    this.push(x);
-  },
-  this);
-  toCopy.length = 0;
-};
diff --git a/service_states.html b/service_states.html
index 94e3412..c8e1e24 100644
--- a/service_states.html
+++ b/service_states.html
@@ -12,6 +12,7 @@
     <script src="log_summary.js"></script>
     <script src="manager.js"></script>
     <script src="netlog_summary.js"></script>
+    <script src="network_event_log_summary.js"></script>
     <script src="service.js"></script>
     <script src="process_log.js"></script>
     <script src="syslog_summary.js"></script>
diff --git a/service_summary.css b/service_summary.css
index 874a7ba..efd7d31 100644
--- a/service_summary.css
+++ b/service_summary.css
@@ -10,6 +10,7 @@
 .serviceState { background-color: #FFC966; }
 .crash { background-color: #B36969; }
 .netlog { background-color: #b0c4de; }
+.eventLog { background-color: #8080ff; }
 .syslog { background-color: #663399; }
 .brillo { background-color: #b0deca; }
 .android { background-color: #90FF90; }
@@ -17,6 +18,10 @@
 .supplicant { background-color: #ccb3e5; }
 .wsmState { background-color: #FFC966; }
 
+/* Network UI logs */
+.error { background-color: #FF5050; }
+.user { background-color: #a0c0ff; }
+
 .legend {
   font-family: 'Arial';
   font-size: 13px;