| // 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 syslog messages. |
| */ |
| |
| var androidlogSummary = {}; |
| |
| /** |
| * RegExp for android log line. |
| * @type {RegExp} |
| */ |
| androidlogSummary.CONNECTIVITY_SERVICE = / ConnectivityService: /; |
| |
| /** |
| * Array of Objects holding regexs and handlers for Android subsections |
| * |
| * Each Regular expression includes a sample log line. The initial part of the |
| * log line sample is represented as [timestamp]. |
| * |
| * @type {Object[]} |
| * @return {string} CSS class for log line |
| */ |
| androidlogSummary.taggedLines = { |
| 'supplicant_disconnected': { |
| // Sample: |
| // [timestamp] wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED |
| // bssid=24:de:c6:e0:89:51 reason=3 locally_generated=1 |
| re: /wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED/, |
| handler: function(processingState, result) { |
| logHelper.addNote(processingState.wifiStateMachine, |
| processingState.time, |
| result[0]); |
| return 'supplicant'; |
| } |
| }, |
| 'wifistatemachine_setdetailed': { |
| // Sample: |
| // [timestamp] WifiStateMachine: setDetailed state, old =OBTAINING_IPADDR |
| // and new state=DISCONNECTED hidden=false |
| re: /WifiStateMachine: setDetailed state, old =(\w+) and new state=(\w+)/, |
| handler: function(processingState, result) { |
| var oldState = result[1]; |
| var newState = result[2]; |
| var stateTimestamp = processingState.time; |
| var states = processingState.wifiStateMachine.networkDetailedStates; |
| var newStateStart = {'x': stateTimestamp, 'y': newState}; |
| var prevStateEnd = {'x': stateTimestamp, 'y': oldState}; |
| if (states.length > 0) { |
| var lastUpdate = states[states.length - 1]; |
| if (oldState != lastUpdate.y) { |
| console.log('warning: last update does not match previous state.' + |
| 'Expected: ' + lastUpdate.y + ' Instead: ' + oldState); |
| } |
| if (lastUpdate.y == newState) { |
| // this state is already represented, return |
| return 'wsmState'; |
| } |
| } else { |
| // Start time unknown: use update timestamp as start time. |
| var prevStateStart = {'x': stateTimestamp, 'y': oldState}; |
| states.push(prevStateStart); |
| } |
| states.push(prevStateEnd); |
| states.push(newStateStart); |
| logHelper.addNote(processingState.wifiStateMachine, |
| stateTimestamp, |
| result[0]); |
| return 'wsmState'; |
| } |
| }, |
| 'supplicant_state': { |
| // Sample: |
| // [timestamp] wpa_supplicant: wlan0: State: ASSOCIATED -> COMPLETED |
| re: /wpa_supplicant\[?.*\]?: .*: State: (.*) -> (.*)/, |
| handler: function(processingState, result) { |
| var wifiStateMachine = processingState.wifiStateMachine; |
| var oldState = result[1].toUpperCase(); |
| var newState = result[2].toUpperCase(); |
| var updateTimestamp = processingState.time; |
| var elapsedTime = Date.parse(updateTimestamp) - |
| wifiStateMachine.startTime; |
| var update = {oldState: oldState, |
| newState: newState, |
| time: elapsedTime}; |
| logHelper.addSupplicantState(wifiStateMachine.supplicantStates, update); |
| logHelper.addNote(processingState.wifiStateMachine, |
| updateTimestamp, |
| result[0]); |
| return 'supplicant'; |
| } |
| } |
| }; |
| |
| /** |
| * 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. |
| * |
| * @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. |
| */ |
| androidlogSummary.processLogLines = function(logLines, logSummary) { |
| |
| /** |
| * 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 {String} time timestamp of current log line |
| * @param {String[]} results results from regex test |
| */ |
| function AndroidlogProcessingState(logSummary, time, results) { |
| this.logSummary = logSummary; |
| this.time = time; |
| this.results = results; |
| } |
| |
| var logLineTime; |
| var logText = []; |
| var parsedLogLineTime; |
| var processingState = new AndroidlogProcessingState(logSummary, null, null); |
| var logType = 'android'; |
| |
| for (var i = 0; i < logLines.length; i++) { |
| console.log('processing log line: ' + logLines[i]); |
| logLineTime = logLines[i].match(logHelper.ANDROID_TIME_FORMAT); |
| if (logLineTime === null) { |
| console.log('not a valid time... skip the log line'); |
| continue; |
| } |
| processingState.time = logLineTime[0]; |
| parsedLogLineTime = Date.parse(processingState.time); |
| |
| if (logSummary.logStartTime == -1) { |
| logSummary.logStartTime = parsedLogLineTime; |
| // This is the start of our log so we need to add the first |
| // WifiStateMachine instance. |
| processingState.wifiStateMachine = |
| new WifiStateMachine(1, |
| parsedLogLineTime, |
| logHelper.getOffsetMS(processingState.time)); |
| logSummary.wifiStateMachines.push(processingState.wifiStateMachine); |
| } |
| |
| if (parsedLogLineTime < logSummary.logEndTime) { |
| console.log('warning: log time has rolled back.'); |
| } else { |
| logSummary.logEndTime = parsedLogLineTime; |
| } |
| |
| var tempLogText = {text: logLines[i], |
| tag: null, |
| type: 'basic', |
| file: logType, |
| ts: parsedLogLineTime}; |
| |
| for (var taggedLine in androidlogSummary.taggedLines) { |
| var result = logLines[i].match( |
| androidlogSummary.taggedLines[taggedLine].re); |
| if (result !== null) { |
| tempLogText.type = |
| androidlogSummary.taggedLines[taggedLine].handler(processingState, |
| result); |
| // Since this line does have a match with the flagged log lines, create |
| // a tag that allows the summary notes to link to the displayed log. |
| tempLogText.tag = processingState.time; |
| break; |
| } |
| } |
| |
| logText.push(tempLogText); |
| } |
| |
| if (logSummary.wifiStateMachines.length > 0) { |
| logSummary.wifiStateMachines[logSummary.wifiStateMachines.length - 1] |
| .endTime = logSummary.logEndTime; |
| } |
| return logText; |
| }; |
| |
| /** |
| * This method processes each log line in the supplied String array to determine |
| * if the log is an android log. |
| * |
| * @param {String[]} logLines String array for lines in a log. |
| * @return {boolean} Returns true is the log is an android log, false otherwise. |
| */ |
| androidlogSummary.androidlogTypeCheck = function(logLines) { |
| for (var i = 0; i < logLines.length; i++) { |
| if (logHelper.ANDROID_MAIN_SECTION.test(logLines[i]) || |
| logHelper.ANDROID_BUG_REPORT.test(logLines[i]) || |
| androidlogSummary.CONNECTIVITY_SERVICE.test(logLines[i])) { |
| return true; |
| } |
| } |
| return false; |
| }; |