apps: refactor regular expressions

Refactor code to utilize regular expressions to replace string
manipulation.  This will improve performance by reducing the amount of
log line parsing.

BUG=chromium:466247
TEST=ran "grunt test" and manually checked multiple shill logs

Change-Id: I977d03843e1dfaef1434a11a1953587dd1f21b6d
diff --git a/Gruntfile.js b/Gruntfile.js
index 13bb24f..7a99778 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -25,6 +25,7 @@
           './process_log.js',
           './log_helper.js',
           './manager.js',
+          './netlog_summary.js',
           './service.js',
           './syslog_summary.js'
         ],
diff --git a/log_helper.js b/log_helper.js
index b0b63e3..d29a468 100644
--- a/log_helper.js
+++ b/log_helper.js
@@ -35,182 +35,13 @@
 
 
 /**
-* RegExp for log timestamp.
-* @type {RegExp}
-*/
+ * RegExp for log timestamp.
+ * @type {RegExp}
+ */
 logHelper.TIME_FORMAT =
     /\d{4}-\d+-\d+T\d{2}:\d{2}:\d{2}.\d{6}(-|\+)\d{2}:\d{2}/;
 
 /**
-* RegExp for new manager.
-* @type {RegExp}
-*/
-logHelper.NEW_MANAGER = /Manager started./;
-
-/**
- * RegExp for service state change.
- * @type {RegExp}
- **/
-logHelper.SERVICE_STATE = /Service \d+ updated; state:/;
-
-/**
- * RegExp for service state change.
- * @type {RegExp}
- **/
-logHelper.SERVICE_STATE_HINT = /Service \d+: state \D* -> /;
-
-/**
- * RegExp for service destroyed message.
- * @type {RegExp}
- */
-logHelper.SERVICE_DESTROYED = /destroyed/;
-
-/**
- * RegExp for service connect message.
- * @type {RegExp}
- */
-logHelper.SERVICE_CONNECT = /Connect to/;
-
-/**
- * RegExp for link monitor update.
- * @type {RegExp}
- */
-logHelper.LINK_MONITOR = /link_monitor/;
-
-/**
- * RegExp for traffic monitor update.
- * @type {RegExp}
- */
-logHelper.TRAFFIC_MONITOR = /traffic_monitor/;
-
-/**
- * RegExp for suppressed autoconnect message.
- * @type {RegExp}
- */
-logHelper.SUPRESSED = /Suppressed /;
-
-/**
- * RegExp for imminent suspend message.
- * @type {RegExp}
- */
-logHelper.SUSPEND_IMMINENT = / SuspendImminent/;
-
-/**
- * RegExp for suspend done message.
- * @type {RegExp}
- */
-logHelper.SUSPEND_DONE = / SuspendDone/;
-
-/**
-* RegExp for imminent dark suspend message.
-* @type {RegExp}
-*/
-logHelper.DARK_SUSPEND_IMMINENT = / DarkSuspendImminent/;
-
-/**
-* RegExp for dark suspend done message.
-* @type {RegExp}
-*/
-logHelper.DARK_SUSPEND_DONE = / ReportSuspendReadinessInternal.*dark=true/;
-
-
-/**
- * RegExp for state change completed message.
- * @type {RegExp}
- */
-logHelper.COMPLETED = / completed -> completed/;
-
-/**
- * RegExp for scan request message.
- * @type {RegExp}
- */
-logHelper.SCAN = /.*Scan \[.* from .*/;
-
-/**
- * RegExp for ScanDone message
- * @type {RegExp}
- */
-logHelper.SCANDONE = / ScanDone/;
-
-/**
- * RegExp for update from IP config message.
- * @type {RegExp}
- */
-logHelper.UPDATE_FROM_IP_CONFIG = /UpdateFromIPConfig/;
-
-/**
- * RegExp for device updated message.
- * @type {RegExp}
- */
-logHelper.DEVICE_UPDATED = /.*Device.*updated:.*/;
-
-/**
- * RegExp for profile change message.
- * @type {RegExp}
- */
-logHelper.PROFILE_INTERNAL = /.*ProfileInternal.*/;
-
-/**
- * RegExp for device updated message.
- * @type {RegExp}
- */
-logHelper.AP_SCAN = /AP scan/;
-
-/**
- * RegExp for auth_timed_out message.
- * @type {RegExp}
- */
-logHelper.AUTH_TIMED_OUT = /AUTH_TIMED_OUT/;
-
-/**
- * RegExp for added bssid message.
- * @type {RegExp}
- */
-logHelper.ADDED_BSSID = /Added BSSID/;
-
-/**
- * RegExp for disconnection event message.
- * @type {RegExp}
- */
-logHelper.EVENT_DISCONNECTED = /CTRL-EVENT-DISCONNECTED/;
-
-/**
- * RegExp for WPA received packet message.
- * @type {RegExp}
- */
-logHelper.WPA_RX = /WPA: RX/;
-
-/**
- * RegExp for WPA send packet message.
- * @type {RegExp}
- */
-logHelper.WPA_TX = /WPA: Sending/;
-
-/**
- * RegExp for WPA group rekeying message.
- * @type {RegExp}
- */
-logHelper.WPA_GROUP_REKEY = /WPA: Group rekeying/;
-
-/**
- * RegExp for skip roam message.
- * @type {RegExp}
- */
-logHelper.SKIP_ROAM = /Skip roam/;
-
-/**
- * RegExp for connectivity test message.
- * @type {RegExp}
- */
-logHelper.CONNECTIVITY_TEST = /ConnectivityTest/;
-
-/**
- * RegExp for DEAUTH events.
- * @type {RegExp}
- */
-logHelper.DEAUTH_EVENT_TEST = /Event DEAUTH/;
-
-/**
  * Method to format an elapsed time in ms to HH:MM:SS.
  *
  * @param {Number} elapsedMS elapsed ms to format.
@@ -242,24 +73,6 @@
 };
 
 /**
- * Helper method checking if a given service state is active.
- *
- * @param {String} state Service state to check.
- * @return {boolean} returns true if the state is considered active
- */
-logHelper.isActive = function(state) {
-  if (state == 'Associating' ||
-      state == 'Configuring' ||
-      state == 'Connected' ||
-      state == 'Online' ||
-      state == 'Portal' ||
-      state == 'Failure') {
-    return true;
-  }
-  return false;
-};
-
-/**
  * Array of Objects holding regexs and handlers for system_log subsections
  * @type {Object[]}
  * @return  {int} returns new index into supplied String[]
@@ -288,22 +101,6 @@
 };
 
 /**
- * This method processes each log line in the supplied String array to determine
- * if the log is a netlog.
- *
- * @param {String[]} logLines String array for lines in a log.
- * @return {boolean} Returns true is the log is a netlog, false otherwise.
- */
-logHelper.netlogTypeCheck = function(logLines) {
-  for (var i = 0; i < logLines.length; i++) {
-    if (logHelper.SERVICE_STATE.test(logLines[i])) {
-      return true;
-    }
-  }
-  return false;
-};
-
-/**
  * Helper method checking what type of log is being processed.
  *
  * @param {String[]} logLines String array for lines in a log.
@@ -327,7 +124,7 @@
   }
 
   if (logHolder.fileType == 'unknown') {
-    if (logHelper.netlogTypeCheck(logLines)) {
+    if (netlogSummary.netlogTypeCheck(logLines)) {
       // supplied file is netlog
       logHolder.fileType = 'netlog';
       logHolder.netlog = logLines;
diff --git a/log_summary.js b/log_summary.js
index 5e0ce55..47bcac7 100644
--- a/log_summary.js
+++ b/log_summary.js
@@ -16,302 +16,6 @@
 }
 
 /**
- * This method processes each log line in the supplied String array.  Each log
- * line is checked to see if matches one of the regular expressions from the
- * logHelper.  Each flagged log line is then processed and adds state to the
- * associated manager or service.  If the method does not find an appropriate
- * start for the net.log portion of the log, it will make a second pass and
- * attempt to parse the entire file as a net.log file.
- *
- * @param {String[]} logLines String array for lines in a log.
- * @return {Object[]} Returns an Object[] of text and anchor labels if the log
- * was processed, null if the log is not a recognized format.
- */
-LogSummary.prototype.processLogLines = function(logLines) {
-  var logStart = -1;
-  var netlog = false;
-  var currentManager = null;
-  var time;
-  var secondPass = false;
-  var logText = [];
-  var timeCheck;
-  while (secondPass == netlog) {
-    for (var i = 0; i < logLines.length; i++) {
-      time = null;
-      if (!netlog && logHelper.NET_LOG_START.test(logLines[i])) {
-        console.log('this is the start of our log!');
-        netlog = true;
-      } else if (netlog && logHelper.MULTILINE_LOG_END.test(logLines[i])) {
-        if (this.managers.length == 0) {
-          console.log('Valid netlog not found.');
-          return null;
-        }
-        console.log('this is the end of our log...');
-        netlog = false;
-        this.managers[this.managers.length - 1].endTime = this.logEndTime;
-        return logText;
-      }
-      if (netlog) {
-        // do we have a start time?
-        time = logLines[i].match(logHelper.TIME_FORMAT);
-        if (time == null) {
-          continue;
-        }
-        timeCheck = Date.parse(time[0]);
-        if (logStart == -1 && time != null) {
-          logStart = time[0];
-          this.logStartTime = timeCheck;
-          this.prevLogLineTime = this.logStartTime;
-          if (this.managers.length == 0) {
-            //need to add default manager
-            currentManager = new Manager(1, this.logStartTime);
-            this.managers.push(currentManager);
-          }
-        }
-        if (timeCheck < this.logEndTime) {
-          console.log('warning: log time has rolled back, check timezone');
-        } else {
-          this.logEndTime = timeCheck;
-          this.prevLogLineTime = timeCheck;
-        }
-        console.log('log_line: ' + logLines[i]);
-        var tempLogText = {text: logLines[i],
-                           tag: time[0],
-                           type: 'basic',
-                           file: 'netlog',
-                           ts: timeCheck};
-        if (logHelper.NEW_MANAGER.test(logLines[i]) && time[0] != logStart) {
-          if (time != null) {
-            var new_manager = new Manager(currentManager.id + 1,
-                                          Date.parse(time[0]));
-            this.managers[this.managers.length - 1].endTime =
-                this.prevLogLineTime;
-            this.managers.push(new_manager);
-            currentManager = new_manager;
-            console.log('added a new manager!', this.managers);
-          } else {
-            console.log('time == null');
-          }
-        } else if (logHelper.SERVICE_STATE.test(logLines[i])) {
-          var id = logLines[i].slice(logLines[i].indexOf('Service ') + 8,
-              logLines[i].indexOf(' updated; '));
-          var state = logLines[i].slice(logLines[i].indexOf('state: ') + 7,
-              logLines[i].indexOf(' failure'));
-          var failure =
-              logLines[i].slice(logLines[i].indexOf(' failure') + 9).trim();
-          if (failure == 'Unknown') {
-            failure = null;
-          }
-          console.log('*****Service state update!');
-          console.log('service [' + id + '][' + state + ']');
-          console.log('managers.length: ' + this.managers.length);
-          console.log('managers: ', this.managers);
-          console.log('failure: ' + failure);
-          var currentService = currentManager.getService(id);
-          var update = {state: state, time: time[0]};
-          if (failure) {
-            update.failure = failure;
-          }
-          currentService.addUpdate(update);
-          console.log(currentService);
-          if (currentService.isActive) {
-            tempLogText.type = 'serviceStateActive';
-          } else {
-            tempLogText.type = 'serviceState';
-          }
-        } else if (logHelper.SERVICE_STATE_HINT.test(logLines[i])) {
-          var id = logLines[i].slice(logLines[i].indexOf('Service ') + 8,
-              logLines[i].indexOf(': state '));
-          var serviceCheck = currentManager.getService(id);
-          if (!serviceCheck.getCurrentUpdate()) {
-            var state = logLines[i].slice(logLines[i].indexOf('state ') + 6,
-                logLines[i].indexOf(' -> '));
-            var update = {state: state, time: null};
-            serviceCheck.addUpdate(update);
-          }
-        } else if (logHelper.SERVICE_DESTROYED.test(logLines[i])) {
-          var id = logLines[i].slice(logLines[i].indexOf('Service ') + 8,
-              logLines[i].indexOf(' destroyed.'));
-          var current_service = currentManager.getService(id);
-          var current_update = current_service.getCurrentUpdate();
-          if (current_update != null) {
-            addNote(current_update, time[0], 'destroyed');
-          } else {
-            addNote(current_service, time[0], 'destroyed');
-          }
-          tempLogText.type = 'faint';
-        } else if (logHelper.SERVICE_CONNECT.test(logLines[i])) {
-          addNote(currentManager,
-                  time[0],
-                  logLines[i].slice(logLines[i].indexOf('Connect to')));
-        } else if (logHelper.LINK_MONITOR.test(logLines[i])) {
-          addNote(currentManager,
-                  time[0],
-                  'Link Monitor: ' +
-                  logLines[i].slice(logLines[i].indexOf('Link')));
-        } else if (logHelper.TRAFFIC_MONITOR.test(logLines[i])) {
-          addNote(currentManager,
-                  time[0],
-                  'Traffic Monitor: ' +
-                  logLines[i].slice(logLines[i].indexOf(')] ') + 3));
-        /** temporarily commented out to reduce clutter in current display
-        *} else if (logHelper.SUPRESSED.test(logLines[i])) {
-        * addNote(currentManager,
-        *          time[0],
-        *          logLines[i].slice(logLines[i].indexOf(' Suppressed ')));
-        */
-        } else if (logHelper.SUSPEND_IMMINENT.test(logLines[i])) {
-          var message =
-              logLines[i].slice(logLines[i].indexOf('SuspendImminent'));
-          addNote(currentManager, time[0], message);
-          tempLogText.type = 'suspend';
-          var active_service = currentManager.getActiveService();
-          if (active_service) {
-            var current_update = active_service.getCurrentUpdate();
-            addNote(current_update, time[0], message);
-          }
-          currentManager
-              .addEventDetail('suspend',
-                              false,
-                              Date.parse(time[0]) - currentManager.startTime);
-        } else if (logHelper.SUSPEND_DONE.test(logLines[i])) {
-          var message =
-              logLines[i].slice(logLines[i].indexOf('SuspendDone'));
-          addNote(currentManager, time[0], message);
-          tempLogText.type = 'suspend';
-          var active_service = currentManager.getActiveService();
-          if (active_service) {
-            var current_update = active_service.getCurrentUpdate();
-            addNote(current_update, time[0], message);
-          }
-          currentManager
-              .addEventDetail('suspend',
-                              true,
-                              Date.parse(time[0]) - currentManager.startTime);
-        } else if (logHelper.DARK_SUSPEND_IMMINENT.test(logLines[i])) {
-          var message =
-              logLines[i].slice(logLines[i].indexOf('DarkSuspendImminent'));
-          addNote(currentManager, time[0], message);
-          tempLogText.type = 'suspend';
-          var active_service = currentManager.getActiveService();
-          if (active_service) {
-            var current_update = active_service.getCurrentUpdate();
-            addNote(current_update, time[0], message);
-          }
-          currentManager
-              .addEventDetail('darksuspend',
-                              false,
-                              Date.parse(time[0]) - currentManager.startTime);
-        } else if (logHelper.DARK_SUSPEND_DONE.test(logLines[i])) {
-          var message =
-              logLines[i].slice(logLines[i].indexOf(' ReportSuspend'));
-          addNote(currentManager, time[0], message);
-          tempLogText.type = 'suspend';
-          var active_service = currentManager.getActiveService();
-          if (active_service) {
-            var current_update = active_service.getCurrentUpdate();
-            addNote(current_update, time[0], message);
-          }
-          currentManager
-              .addEventDetail('darksuspend',
-                  true,
-                  Date.parse(time[0]) - currentManager.startTime);
-        } else if (logHelper.COMPLETED.test(logLines[i])) {
-          addNote(currentManager,
-                  time[0],
-                  logLines[i].slice(logLines[i].indexOf('WiFi')));
-        } else if (logHelper.UPDATE_FROM_IP_CONFIG.test(logLines[i])) {
-          addNote(currentManager,
-                  time[0],
-                  logLines[i].slice(logLines[i].indexOf('UpdateFromIPConfig')));
-        } else if (logHelper.DEVICE_UPDATED.test(logLines[i])) {
-          addNote(currentManager,
-                  time[0],
-                  logLines[i].slice(logLines[i].indexOf('Device')));
-        } else if (logHelper.PROFILE_INTERNAL.test(logLines[i])) {
-          addNote(currentManager,
-                  time[0],
-                  logLines[i].slice(logLines[i].indexOf('\)\] ') + 3));
-        } else if (logHelper.SCAN.test(logLines[i])) {
-          addNote(currentManager,
-                  time[0],
-                  logLines[i].slice(logLines[i].indexOf('Scan')));
-          currentManager.scans++;
-          currentManager
-              .addEventDetail('scan',
-                              false,
-                              Date.parse(time[0]) - currentManager.startTime);
-        } else if (logHelper.SCANDONE.test(logLines[i])) {
-          currentManager
-              .addEventDetail('scan',
-                              true,
-                              Date.parse(time[0]) - currentManager.startTime);
-        } else if (logHelper.AP_SCAN.test(logLines[i])) {
-          addNote(currentManager,
-                  time[0],
-                  logLines[i].slice(logLines[i].indexOf('\]: ') + 3));
-          currentManager.scans++;
-        } else if (logHelper.AUTH_TIMED_OUT.test(logLines[i])) {
-          addNote(currentManager,
-                  time[0],
-                  logLines[i].slice(logLines[i].indexOf('Event ')));
-        } else if (logHelper.ADDED_BSSID.test(logLines[i])) {
-          addNote(currentManager,
-                  time[0],
-                  logLines[i].slice(logLines[i].indexOf('Added ')));
-        } else if (logHelper.EVENT_DISCONNECTED.test(logLines[i])) {
-          addNote(currentManager,
-                  time[0],
-                  logLines[i].slice(logLines[i].indexOf('\]: ') + 3));
-        } else if (logHelper.WPA_RX.test(logLines[i])) {
-          addNote(currentManager,
-                  time[0],
-                  logLines[i].slice(logLines[i].indexOf('\]: ') + 3));
-        } else if (logHelper.WPA_TX.test(logLines[i])) {
-          addNote(currentManager,
-                  time[0],
-                  logLines[i].slice(logLines[i].indexOf('\]: ') + 3));
-        } else if (logHelper.WPA_GROUP_REKEY.test(logLines[i])) {
-          addNote(currentManager,
-                  time[0],
-                  logLines[i].slice(logLines[i].indexOf('\]: ') + 3));
-        } else if (logHelper.SKIP_ROAM.test(logLines[i])) {
-          addNote(currentManager,
-                  time[0],
-                  logLines[i].slice(logLines[i].indexOf('\]: ') + 3));
-        } else if (logHelper.CONNECTIVITY_TEST.test(logLines[i])) {
-          addNote(currentManager,
-                  time[0],
-                  logLines[i].slice(logLines[i].indexOf('\)\] ') + 3));
-        } else if (logHelper.DEAUTH_EVENT_TEST.test(logLines[i])) {
-          addNote(currentManager,
-                  time[0],
-                  logLines[i].slice(logLines[i].indexOf('\]: ') + 3));
-        } else {
-          tempLogText.tag = null;
-        }
-        logText.push(tempLogText);
-      }
-    }
-    if (logStart == -1) {
-      if (secondPass) {
-        // already tried a second pass.
-        return null;
-      }
-      secondPass = true;
-      netlog = true;
-    } else {
-      // we did find the start of a log, might have been on second pass
-      if (secondPass) {
-         console.log('this is the end of our log...');
-         this.managers[this.managers.length - 1].endTime = this.logEndTime;
-         return logText;
-      }
-    }
-  }
-};
-
-/**
  * Helper method to add flagged messages to an object.
  *
  * @param {Object} noteHolder Object to get the new note.
diff --git a/netlog_summary.js b/netlog_summary.js
new file mode 100644
index 0000000..534f286
--- /dev/null
+++ b/netlog_summary.js
@@ -0,0 +1,486 @@
+// Copyright 2015 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 to hold methods for processing netlog messages.
+ */
+
+var netlogSummary = {};
+
+/**
+ * Object used for passing state between main processing loop and
+ * regeular expression handler functions.
+ * @constructor
+ * @type {Object}
+ * @param {LogSummary} logSummary object holding log state after processing
+ * @param {Manager} currentManager object of the current manager in log
+ * @param {String} time timestamp of current log line
+ * @param {String[]} results results from regex test
+ */
+function ProcessingState(logSummary, currentManager, time, results) {
+  this.logSummary = logSummary;
+  this.currentManager = currentManager;
+  this.time = time;
+  this.results = results;
+}
+
+/**
+ * Array of Objects holding regexs and handlers for netlog subsections
+ * @type {Object[]}
+ * @return {string} handler functions return log line tag label
+ */
+netlogSummary.taggedLines = {
+  'new_manager': {
+    re: /Manager started./,
+    handler: function(processingState, result) {
+      var logSummary = processingState.logSummary;
+      var currentManager = processingState.currentManager;
+      if (processingState.time != null) {
+        var new_manager;
+        if (!currentManager) {
+          new_manager = new Manager(1, Date.parse(processingState.time[0]));
+        } else {
+          new_manager = new Manager(processingState.currentManager.id + 1,
+              Date.parse(processingState.time[0]));
+          logSummary.managers[logSummary.managers.length - 1].endTime =
+              logSummary.prevLogLineTime;
+        }
+        logSummary.managers.push(new_manager);
+        processingState.currentManager = new_manager;
+        console.log('added a new manager!', logSummary.managers);
+      } else {
+        console.log('time == null');
+      }
+      return 'basic';
+    }
+  },
+  'service_state': {
+    re: /Service (\d+) updated; state:* (\w+) failure:* (\D+)/,
+    handler: function(processingState, result) {
+      var logSummary = processingState.logSummary;
+      var id = result[1];
+      var state = result[2];
+      var failure = result[3];
+      if (failure == 'Unknown') {
+        failure = null;
+      }
+      console.log('*****Service state update!');
+      console.log('service [' + id + '][' + state + ']');
+      console.log('managers.length: ' + logSummary.managers.length);
+      console.log('managers: ', logSummary.managers);
+      console.log('failure: ' + failure);
+      var currentService = processingState.currentManager.getService(id);
+      var update = {state: state, time: processingState.time[0]};
+      if (failure) {
+        update.failure = failure;
+      }
+      currentService.addUpdate(update);
+      console.log(currentService);
+      if (currentService.isActive) {
+        return 'serviceStateActive';
+      }
+      return 'serviceState';
+    }
+  },
+  'service_state_hint': {
+    re: /Service (\d+): state (\w+) -> (\w+)/,
+    handler: function(processingState, result) {
+      var id = result[1];
+      var state = result[2];
+      console.log('service state hint!!!');
+      var serviceCheck = processingState.currentManager.getService(id);
+      if (!serviceCheck.getCurrentUpdate()) {
+        var update = {state: state, time: null};
+        serviceCheck.addUpdate(update);
+      }
+      return 'basic';
+    }
+  },
+  'service_destroyed': {
+    re: /Service (\d+) destroyed/,
+    handler: function(processingState, result) {
+      var id = result[1];
+      var current_service = processingState.currentManager.getService(id);
+      var current_update = current_service.getCurrentUpdate();
+      if (current_update != null) {
+        addNote(current_update, processingState.time[0], 'destroyed');
+      } else {
+        addNote(current_service, processingState.time[0], 'destroyed');
+      }
+      return 'faint';
+    }
+  },
+  'service_connect': {
+    re: /Connect to service (\d+): \D+/,
+    handler: function(processingState, result) {
+      addNote(processingState.currentManager,
+              processingState.time[0],
+              result[0]);
+      return 'basic';
+    }
+  },
+  'link_monitor': {
+    re: /link_monitor\S+ (.*$)/,
+    handler: function(processingState, result) {
+      addNote(processingState.currentManager,
+              processingState.time[0],
+              'Link Monitor: ' + result[0]);
+      return 'basic';
+    }
+  },
+  'traffic_monitor': {
+    re: /traffic_monitor\S+ (.*$)/,
+    handler: function(processingState, result) {
+      addNote(processingState.currentManager,
+              processingState.time[0],
+              'Traffic Monitor: ' + result[1]);
+      return 'basic';
+    }
+  },
+  'suspend_imminent': {
+    re: /shill.* SuspendImminent(.*$)/,
+    handler: function(processingState, result) {
+      var time = processingState.time;
+      var currentManager = processingState.currentManager;
+      addNote(currentManager, time[0], 'SuspendImminent');
+      var active_service = currentManager.getActiveService();
+      if (active_service) {
+        var current_update = active_service.getCurrentUpdate();
+        addNote(current_update, time[0], 'SuspendImminent');
+      }
+      currentManager
+          .addEventDetail('suspend',
+                          false,
+                          Date.parse(time[0]) - currentManager.startTime);
+      return 'suspend';
+    }
+  },
+  'suspend_done': {
+    re: /shill.* SuspendDone(.*$)/,
+    handler: function(processingState, result) {
+      var time = processingState.time;
+      var currentManager = processingState.currentManager;
+      addNote(currentManager, time[0], 'SuspendDone');
+      var active_service = currentManager.getActiveService();
+      if (active_service) {
+        var current_update = active_service.getCurrentUpdate();
+        addNote(current_update, time[0], 'SuspendDone');
+      }
+      currentManager
+          .addEventDetail('suspend',
+                          true,
+                          Date.parse(time[0]) - currentManager.startTime);
+      return 'suspend';
+    }
+  },
+  'dark_suspend_imminent': {
+    re: / DarkSuspendImminent(.*$)/,
+    handler: function(processingState, result) {
+      var time = processingState.time;
+      var currentManager = processingState.currentManager;
+      addNote(currentManager, time[0], result[0]);
+      var active_service = currentManager.getActiveService();
+      if (active_service) {
+        var current_update = active_service.getCurrentUpdate();
+        addNote(current_update, time[0], result[0]);
+      }
+      currentManager
+          .addEventDetail('darksuspend',
+                          false,
+                          Date.parse(time[0]) - currentManager.startTime);
+      return 'suspend';
+    }
+  },
+  'dark_suspend_done': {
+    re: /shill.* ReportSuspendReadinessInternal.*dark=true\)/,
+    handler: function(processingState, result) {
+      var time = processingState.time;
+      var currentManager = processingState.currentManager;
+      addNote(currentManager, time[0], 'DarkSuspendDone');
+      var active_service = currentManager.getActiveService();
+      if (active_service) {
+        var current_update = active_service.getCurrentUpdate();
+        addNote(current_update, time[0], 'DarkSuspendDone');
+      }
+      currentManager
+          .addEventDetail('darksuspend',
+                          true,
+                          Date.parse(time[0]) - currentManager.startTime);
+      return 'suspend';
+    }
+  },
+  'completed': {
+    re: / WiFi \w+ StateChanged completed -> completed/,
+    handler: function(processingState, result) {
+      addNote(processingState.currentManager,
+              processingState.time[0],
+              result[0]);
+      return 'basic';
+    }
+  },
+  'update_from_ip_config': {
+    re: /UpdateFromIPConfig.*/,
+    handler: function(processingState, result) {
+      addNote(processingState.currentManager,
+              processingState.time[0],
+              result[0]);
+      return 'basic';
+    }
+  },
+  'device_updated': {
+    re: /Device.*updated:.*/,
+    handler: function(processingState, result) {
+      addNote(processingState.currentManager,
+              processingState.time[0],
+              result[0]);
+      return 'basic';
+    }
+  },
+  'profile_internal': {
+    re: /\)\] (.*ProfileInternal.*)/,
+    handler: function(processingState, result) {
+      addNote(processingState.currentManager,
+              processingState.time[0],
+              result[1]);
+      return 'basic';
+    }
+  },
+  'scan': {
+    re: / Scan \[.* from .*/,
+    handler: function(processingState, result) {
+      var currentManager = processingState.currentManager;
+      var time = processingState.time;
+      addNote(currentManager, time[0], result[0]);
+      currentManager.scans++;
+      currentManager
+          .addEventDetail('scan',
+                          false,
+                          Date.parse(time[0]) - currentManager.startTime);
+      return 'basic';
+    }
+  },
+  'scandone': {
+    re: / ScanDone/,
+    handler: function(processingState, result) {
+      var currentManager = processingState.currentManager;
+      var time = processingState.time;
+      currentManager
+          .addEventDetail('scan',
+                          true,
+                          Date.parse(time[0]) - currentManager.startTime);
+      return 'basic';
+    }
+  },
+  'ap_scan': {
+    re: /\]: (.*AP scan.*)/,
+    handler: function(processingState, result) {
+      var currentManager = processingState.currentManager;
+      var time = processingState.time;
+      addNote(currentManager, time[0], result[1]);
+      currentManager.scans++;
+      return 'basic';
+    }
+  },
+  'auth_timed_out': {
+    re: /Event.*AUTH_TIMED_OUT.*/,
+    handler: function(processingState, result) {
+      addNote(processingState.currentManager,
+              processingState.time[0],
+              result[0]);
+      return 'basic';
+    }
+  },
+  'added_bssid': {
+    re: /Added BSSID.*/,
+    handler: function(processingState, result) {
+      addNote(processingState.currentManager,
+              processingState.time[0],
+              result[0]);
+      return 'basic';
+    }
+  },
+  'event_disconnected': {
+    re: /\]: (.*CTRL-EVENT-DISCONNECTED.*)/,
+    handler: function(processingState, result) {
+      addNote(processingState.currentManager,
+              processingState.time[0],
+              result[1]);
+      return 'basic';
+    }
+  },
+  'wpa_rx': {
+    re: /\]: (.*WPA: RX.*)/,
+    handler: function(processingState, result) {
+      addNote(processingState.currentManager,
+              processingState.time[0],
+              result[1]);
+      return 'basic';
+    }
+  },
+  'wpa_tx': {
+    re: /\]: (.*WPA: Sending.*)/,
+    handler: function(processingState, result) {
+      addNote(processingState.currentManager,
+              processingState.time[0],
+              result[1]);
+      return 'basic';
+    }
+  },
+  'wpa_group_rekey': {
+    re: /\]: (.*WPA: Group rekeying.*)/,
+    handler: function(processingState, result) {
+      addNote(processingState.currentManager,
+              processingState.time[0],
+              result[1]);
+      return 'basic';
+    }
+  },
+  'skip_roam': {
+    re: /\]: (.*Skip roam.*)/,
+    handler: function(processingState, result) {
+      addNote(processingState.currentManager,
+              processingState.time[0],
+              result[1]);
+      return 'basic';
+    }
+  },
+  'connectivity_test': {
+    re: /\)\] (.*ConnectivityTest.*)/,
+    handler: function(processingState, result) {
+      addNote(processingState.currentManager,
+              processingState.time[0],
+              result[1]);
+      return 'basic';
+    }
+  },
+  'deauth_event': {
+    re: /\]: (.*Event DEAUTH.*)/,
+    handler: function(processingState, result) {
+      addNote(processingState.currentManager,
+              processingState.time[0],
+              result[1]);
+      return 'basic';
+    }
+  }
+};
+
+
+
+/**
+ * Helper method checking if a given service state is active.
+ *
+ * @param {String} state Service state to check.
+ * @return {boolean} returns true if the state is considered active
+ */
+netlogSummary.isActive = function(state) {
+  if (state == 'Associating' ||
+      state == 'Configuring' ||
+      state == 'Connected' ||
+      state == 'Online' ||
+      state == 'Portal' ||
+      state == 'Failure') {
+    return true;
+  }
+  return false;
+};
+
+/**
+ * This method processes each log line in the supplied String array.  Each log
+ * line is checked to see if matches one of the regular expressions from the
+ * logHelper.  Each flagged log line is then processed and adds state to the
+ * associated manager or service.  If the method does not find an appropriate
+ * start for the net.log portion of the log, it will make a second pass and
+ * attempt to parse the entire file as a net.log file.
+ *
+ * @param {String[]} logLines String array for lines in a log.
+ * @param {LogSummary} logSummary Object to hold processed log state.
+ * @return {Object[]} Returns an Object[] of text and anchor labels if the log
+ * was processed, null if the log is not a recognized format.
+ */
+netlogSummary.processLogLines = function(logLines, logSummary) {
+  var logStart = -1;
+  var time;
+  var logText = [];
+  var timeCheck;
+  var result = null;
+  var processingState = new ProcessingState(logSummary, null, time, null);
+
+  for (var i = 0; i < logLines.length; i++) {
+    // do we have a start time?
+    time = logLines[i].match(logHelper.TIME_FORMAT);
+    processingState.time = time;
+    if (time == null) {
+      continue;
+    }
+    timeCheck = Date.parse(time[0]);
+    if (logStart == -1 && time != null) {
+      logStart = time[0];
+      logSummary.logStartTime = timeCheck;
+      logSummary.prevLogLineTime = logSummary.logStartTime;
+      if (logSummary.managers.length == 0 &&
+          !logLines[i].match(netlogSummary.taggedLines['new_manager'].re)) {
+        //need to add default manager
+        processingState.currentManager =
+            new Manager(1, logSummary.logStartTime);
+        logSummary.managers.push(processingState.currentManager);
+      }
+    }
+    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: time[0],
+                       type: 'basic',
+                       file: 'netlog',
+                       ts: timeCheck};
+    result = null;
+    for (var taggedLine in netlogSummary.taggedLines) {
+      var result = logLines[i].match(netlogSummary.taggedLines[taggedLine].re);
+      if (result != null) {
+        tempLogText.type =
+            netlogSummary.taggedLines[taggedLine].handler(processingState,
+                                                          result);
+        break;
+      }
+    }
+    if (!result) {
+      tempLogText.tag = null;
+    }
+
+    logText.push(tempLogText);
+  }
+
+  if (logSummary.managers.length == 0) {
+    console.log('Valid netlog not found.');
+    return null;
+  }
+
+  console.log('this is the end of our log...');
+  logSummary.managers[logSummary.managers.length - 1].endTime =
+      logSummary.logEndTime;
+
+  return logText;
+};
+
+/**
+ * This method processes each log line in the supplied String array to determine
+ * if the log is a netlog.
+ *
+ * @param {String[]} logLines String array for lines in a log.
+ * @return {boolean} Returns true is the log is a netlog, false otherwise.
+ */
+netlogSummary.netlogTypeCheck = function(logLines) {
+  for (var i = 0; i < logLines.length; i++) {
+    if (netlogSummary.taggedLines['service_state'].re.test(logLines[i])) {
+      return true;
+    }
+  }
+  return false;
+};
+
diff --git a/process_log.js b/process_log.js
index cebf133..0adb3d0 100644
--- a/process_log.js
+++ b/process_log.js
@@ -56,7 +56,8 @@
       }
 
       if (logHolder.netlog) {
-        logHolder.netlog = logSummary.processLogLines(logHolder.netlog);
+        logHolder.netlog = netlogSummary.processLogLines(logHolder.netlog,
+                                                         logSummary);
       }
 
       if (logHolder.syslog) {
diff --git a/service.js b/service.js
index 7f10cf6..bccac68 100644
--- a/service.js
+++ b/service.js
@@ -32,7 +32,7 @@
     return;
   }
 
-  if (logHelper.isActive(update.state)) {
+  if (netlogSummary.isActive(update.state)) {
     this.isActive = true;
   }
   if (this.states.length > 0) {
diff --git a/service_states.html b/service_states.html
index 3a5f8ce..d5fbead 100644
--- a/service_states.html
+++ b/service_states.html
@@ -9,6 +9,7 @@
     <script src="log_helper.js"></script>
     <script src="log_summary.js"></script>
     <script src="manager.js"></script>
+    <script src="netlog_summary.js"></script>
     <script src="service.js"></script>
     <script src="process_log.js"></script>
     <script src="syslog_summary.js"></script>
diff --git a/syslog_summary.js b/syslog_summary.js
index 5e844a4..26ead6d 100644
--- a/syslog_summary.js
+++ b/syslog_summary.js
@@ -15,7 +15,6 @@
  */
 syslogSummary.KERNEL_INFO = / kernel: \[/;
 
-
 /**
  * This method processes each log line in the supplied String array.  Each log
  * line is checked to see if matches one of the regular expressions from the
diff --git a/test/spec/LogHelperSpec.js b/test/spec/LogHelperSpec.js
index 9769931..e966aac 100644
--- a/test/spec/LogHelperSpec.js
+++ b/test/spec/LogHelperSpec.js
@@ -19,15 +19,52 @@
     expect(logHelper.formatElapsedMS('10000000')).toEqual('02:46:40.000');
   });
 
-  it('should return true for active states and false for others', function() {
-    expect(logHelper.isActive('Unknown')).toBe(false);
-    expect(logHelper.isActive('Idle')).toBe(false);
-    expect(logHelper.isActive('Associating')).toBe(true);
-    expect(logHelper.isActive('Configuring')).toBe(true);
-    expect(logHelper.isActive('Connected')).toBe(true);
-    expect(logHelper.isActive('Portal')).toBe(true);
-    expect(logHelper.isActive('Failure')).toBe(true);
-    expect(logHelper.isActive('Online')).toBe(true);
+  it('should detect syslogs', function() {
+    var time1 = '2015-01-06T23:33:03.478905-08:00';
+    var time2 = '2015-01-06T23:33:06.680764-08:00';
+    var time3 = '2015-01-06T23:33:06.681832-08:00';
+
+    var basicLog = [
+        time1 + ' wpa_supplicant[863]: nl80211: Scan trigger',
+        time2 + ' wpa_supplicant[863]: nl80211: Event message available',
+        time3 + ' wpa_supplicant[863]: nl80211: New scan results available'
+    ];
+    var log;
+    var logLines = [
+        '---------- END ----------',
+        '',
+        'netlog=<multiline>',
+        '---------- START ----------'
+    ];
+    log = logLines.concat(basicLog);
+    log.push('---------- END ----------');
+    var logHolder = logHelper.detectFileType(log);
+    expect(logHolder.fileType).toEqual('system_log');
   });
+
+  it('should detect netlogs', function() {
+    var time1 = '2015-01-06T23:33:03.478905-08:00';
+    var time2 = '2015-01-06T23:33:06.680764-08:00';
+    var time3 = '2015-01-06T23:33:06.681832-08:00';
+
+    var basicLog = [
+        time1 + ' Service 0 updated; state: Associating failure Unknown',
+        time2 + ' Service 0: state Idle -> Associating',
+        time3 + ' wpa_supplicant[863]: nl80211: New scan results available'
+    ];
+    var logHolder = logHelper.detectFileType(basicLog);
+    expect(logHolder.fileType).toEqual('netlog');
+  });
+
+  it('should detect an unknown file type', function() {
+    var randomFile = [
+        'This is not a real log',
+        'It should not be processed',
+        ' wpa_supplicant[863]: nl80211: New scan results available'
+    ];
+    var logHolder = logHelper.detectFileType(randomFile);
+    expect(logHolder.fileType).toEqual('unknown');
+  });
+
 });
 
diff --git a/test/spec/LogSummarySpec.js b/test/spec/NetlogSummarySpec.js
similarity index 70%
rename from test/spec/LogSummarySpec.js
rename to test/spec/NetlogSummarySpec.js
index fc70073..5d4a622 100644
--- a/test/spec/LogSummarySpec.js
+++ b/test/spec/NetlogSummarySpec.js
@@ -3,10 +3,10 @@
 // found in the LICENSE file.
 
 /**
- * @fileoverview Jasmine test file for log_summary.js.
+ * @fileoverview Jasmine test file for netlog_summary.js.
  */
 
-describe('LogSummary', function() {
+describe('NetlogSummary', function() {
   var logSummary;
   var basicLog;
   var time1;
@@ -27,34 +27,29 @@
 
   });
 
+  it('should return true for active states and false for others', function() {
+    expect(netlogSummary.isActive('Unknown')).toBe(false);
+    expect(netlogSummary.isActive('Idle')).toBe(false);
+    expect(netlogSummary.isActive('Associating')).toBe(true);
+    expect(netlogSummary.isActive('Configuring')).toBe(true);
+    expect(netlogSummary.isActive('Connected')).toBe(true);
+    expect(netlogSummary.isActive('Portal')).toBe(true);
+    expect(netlogSummary.isActive('Failure')).toBe(true);
+    expect(netlogSummary.isActive('Online')).toBe(true);
+  });
+
   it('should gracefully handle empty files', function() {
     var empty = [];
-    expect(logSummary.processLogLines(empty)).toBe(null);
+    expect(netlogSummary.processLogLines(empty, logSummary)).toBe(null);
   });
 
   it('should gracefully handle unrelated files', function() {
     var text = ['a', 'b'];
-    expect(logSummary.processLogLines(text)).toBe(null);
+    expect(netlogSummary.processLogLines(text, logSummary)).toBe(null);
   });
 
   it('should handle net.log files directly', function() {
-    var logText = logSummary.processLogLines(basicLog);
-    expect(logSummary.logStartTime).toEqual(Date.parse(time1));
-    expect(logSummary.logEndTime).toEqual(Date.parse(time3));
-    expect(logSummary.managers.length).toBe(1);
-  });
-
-  it('should handle system logs that include a shill log section', function() {
-    var log;
-    var logLines = [
-        '---------- END ----------',
-        '',
-        'netlog=<multiline>',
-        '---------- START ----------'
-        ];
-    log = logLines.concat(basicLog);
-    log.push('---------- END ----------');
-    var logText = logSummary.processLogLines(log);
+    var logText = netlogSummary.processLogLines(basicLog, logSummary);
     expect(logSummary.logStartTime).toEqual(Date.parse(time1));
     expect(logSummary.logEndTime).toEqual(Date.parse(time3));
     expect(logSummary.managers.length).toBe(1);
@@ -64,7 +59,7 @@
     var log;
     var logLines = ['licant[781]: wlan0:    skip - SSID mismatch'];
     log = logLines.concat(basicLog);
-    var logText = logSummary.processLogLines(log);
+    var logText = netlogSummary.processLogLines(log, logSummary);
     expect(logSummary.logStartTime).toEqual(Date.parse(time1));
     expect(logSummary.logEndTime).toEqual(Date.parse(time3));
     expect(logSummary.managers.length).toBe(1);
@@ -76,7 +71,7 @@
         time2 + ' shill[1066]: [INFO:manager.cc(204)] Manager started.',
         time3 + ' shill[937]: [INFO:manager.cc(204)] Manager started.'
         ];
-    var logText = logSummary.processLogLines(log);
+    var logText = netlogSummary.processLogLines(log, logSummary);
     expect(logSummary.logStartTime).toEqual(Date.parse(time1));
     expect(logSummary.logEndTime).toEqual(Date.parse(time3));
     expect(logSummary.managers.length).toBe(3);
@@ -87,21 +82,21 @@
         time1 + ' shill[1066]: [INFO:manager.cc(204)] Manager started.',
         time2 + ' shill[937]: [INFO:manager.cc(204)] Manager started.'
     ];
-    var logText = logSummary.processLogLines(log);
+    var logText = netlogSummary.processLogLines(log, logSummary);
     expect(logSummary.logStartTime).toEqual(Date.parse(time1));
     expect(logSummary.logEndTime).toEqual(Date.parse(time2));
     expect(logSummary.managers.length).toBe(2);
   });
 
   it('should properly set the log end time', function() {
-    var logText = logSummary.processLogLines(basicLog);
+    var logText = netlogSummary.processLogLines(basicLog, logSummary);
     expect(logSummary.logStartTime).toEqual(Date.parse(time1));
     expect(logSummary.logEndTime).toEqual(Date.parse(time3));
   });
 
   it('should properly handle a single line log', function() {
     var log = [time1 + ' wpa_supplicant[863]: nl80211: Scan trigger'];
-    var logText = logSummary.processLogLines(log);
+    var logText = netlogSummary.processLogLines(log, logSummary);
     expect(logSummary.logStartTime).toEqual(Date.parse(time1));
     expect(logSummary.logEndTime).toEqual(Date.parse(time1));
   });