Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(67)

Unified Diff: pkg/analysis_server/tool/instrumentation/log/log.dart

Issue 2390693002: Handle session logs and add event subset selection (Closed)
Patch Set: Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | pkg/analysis_server/tool/instrumentation/log_viewer.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/analysis_server/tool/instrumentation/log/log.dart
diff --git a/pkg/analysis_server/tool/instrumentation/log/log.dart b/pkg/analysis_server/tool/instrumentation/log/log.dart
index 7042fc467dd5e13f07f925411b9e1cd82f0d087b..2378c27a33454801dad5055e845af436dd99272e 100644
--- a/pkg/analysis_server/tool/instrumentation/log/log.dart
+++ b/pkg/analysis_server/tool/instrumentation/log/log.dart
@@ -5,14 +5,83 @@
/**
* A representation of the contents of an instrumentation log.
*/
-library analysis_server.tool.instrumentation.log;
+library analysis_server.tool.instrumentation.log.log;
-import 'dart:collection';
import 'dart:convert';
import 'package:analyzer/instrumentation/instrumentation.dart';
/**
+ * A boolean-valued function of one argument.
+ */
+typedef bool Predicate<T>(T value);
+
+/**
+ * A description of a group of log entries.
+ */
+class EntryGroup {
+ /**
+ * A list of all of the instances of this class.
+ */
+ static final List<EntryGroup> groups = <EntryGroup>[
+ new EntryGroup._(
+ 'nonTask', 'Non-task', (LogEntry entry) => entry is! TaskEntry),
+ new EntryGroup._(
+ 'errors',
+ 'Errors',
+ (LogEntry entry) =>
+ entry is ErrorEntry ||
+ entry is ExceptionEntry ||
+ (entry is NotificationEntry && entry.isServerError)),
+ new EntryGroup._('malformed', 'Malformed',
+ (LogEntry entry) => entry is MalformedLogEntry),
+ new EntryGroup._('all', 'All', (LogEntry entry) => true),
+ ];
+
+ /**
+ * The unique id of the group.
+ */
+ final String id;
+
+ /**
+ * The human-readable name of the group.
+ */
+ final String name;
+
+ /**
+ * The filter used to determine which entries belong to the group. The filter
+ * should return `true` for members and `false` for non-members.
+ */
+ final Predicate<LogEntry> filter;
+
+ /**
+ * Initialize a newly created entry group with the given state.
+ */
+ EntryGroup._(this.id, this.name, this.filter);
+
+ /**
+ * Given a list of [entries], return all of the entries in the list that are
+ * members of this group.
+ */
+ List<LogEntry> computeMembers(List<LogEntry> entries) {
+ return entries.where(filter).toList();
+ }
+
+ /**
+ * Return the entry group with the given [id], or `null` if there is no group
+ * with the given id.
+ */
+ static EntryGroup withId(String id) {
+ for (EntryGroup group in groups) {
+ if (group.id == id) {
+ return group;
+ }
+ }
+ return null;
+ }
+}
+
+/**
* A range of log entries, represented by the index of the first and last
* entries in the range.
*/
@@ -107,34 +176,33 @@ class InstrumentationLog {
List<LogEntry> logEntries;
/**
- * The entries in the instrumentation log that are not instances of
- * [TaskEntry].
+ * A table mapping the entry groups that have been computed to the list of
+ * entries in that group.
*/
- List<LogEntry> nonTaskEntries;
+ Map<EntryGroup, List<LogEntry>> entryGroups = <EntryGroup, List<LogEntry>>{};
/**
* A table mapping entries that are paired with another entry to the entry
* with which they are paired.
*/
- Map<LogEntry, LogEntry> _pairedEntries = new HashMap<LogEntry, LogEntry>();
+ Map<LogEntry, LogEntry> _pairedEntries = <LogEntry, LogEntry>{};
/**
* A table mapping the id's of requests to the entry representing the request.
*/
- Map<String, RequestEntry> _requestMap = new HashMap<String, RequestEntry>();
+ Map<String, RequestEntry> _requestMap = <String, RequestEntry>{};
/**
* A table mapping the id's of responses to the entry representing the
* response.
*/
- Map<String, ResponseEntry> _responseMap =
- new HashMap<String, ResponseEntry>();
+ Map<String, ResponseEntry> _responseMap = <String, ResponseEntry>{};
/**
* A table mapping the ids of completion events to the events with those ids.
*/
Map<String, List<NotificationEntry>> _completionMap =
- new HashMap<String, List<NotificationEntry>>();
+ <String, List<NotificationEntry>>{};
/**
* The ranges of entries that are between analysis start and analysis end
@@ -158,6 +226,12 @@ class InstrumentationLog {
_completionMap[id];
/**
+ * Return the log entries that are contained in the given [group].
+ */
+ List<LogEntry> entriesInGroup(EntryGroup group) =>
+ entryGroups.putIfAbsent(group, () => group.computeMembers(logEntries));
+
+ /**
* Return the entry that is paired with the given [entry], or `null` if there
* is no entry paired with it.
*/
@@ -181,7 +255,7 @@ class InstrumentationLog {
*/
List<TaskEntry> taskEntriesFor(int startIndex) {
List<TaskEntry> taskEntries = <TaskEntry>[];
- NotificationEntry startEntry = nonTaskEntries[startIndex];
+ NotificationEntry startEntry = logEntries[startIndex];
LogEntry endEntry = pairedEntry(startEntry);
int lastIndex = endEntry == null ? logEntries.length : endEntry.index;
for (int i = startEntry.index + 1; i < lastIndex; i++) {
@@ -194,6 +268,18 @@ class InstrumentationLog {
}
/**
+ * Return `true` if the given [logContent] appears to be from session data.
+ */
+ bool _isSessionData(List<String> logContent) {
+ if (logContent.length < 2) {
+ return false;
+ }
+ String firstLine = logContent[0];
+ return firstLine.startsWith('-----') && logContent[1].startsWith('~') ||
+ firstLine.startsWith('~');
+ }
+
+ /**
* Merge any multi-line entries into a single line so that every element in
* the given [logContent] is a single entry.
*/
@@ -233,9 +319,18 @@ class InstrumentationLog {
* Parse the given [logContent] into a list of log entries.
*/
void _parseLogContent(List<String> logContent) {
- _mergeEntries(logContent);
+ if (_isSessionData(logContent)) {
+ if (logContent[0].startsWith('-----')) {
+ logContent.removeAt(0);
+ }
+ int lastIndex = logContent.length - 1;
+ if (logContent[lastIndex].startsWith('extraction complete')) {
+ logContent.removeAt(lastIndex);
+ }
+ } else {
+ _mergeEntries(logContent);
+ }
logEntries = <LogEntry>[];
- nonTaskEntries = <LogEntry>[];
analysisRanges = <EntryRange>[];
NotificationEntry analysisStartEntry = null;
int analysisStartIndex = -1;
@@ -244,9 +339,6 @@ class InstrumentationLog {
LogEntry entry = new LogEntry.from(logEntries.length, line);
if (entry != null) {
logEntries.add(entry);
- if (entry is! TaskEntry) {
- nonTaskEntries.add(entry);
- }
if (entry is RequestEntry) {
_requestMap[entry.id] = entry;
} else if (entry is ResponseEntry) {
@@ -439,6 +531,7 @@ abstract class LogEntry {
'Err': 'Error',
'Ex': 'Exception',
'Log': 'Log message',
+ 'Mal': 'Malformed entry',
'Noti': 'Notification',
'Read': 'Read file',
'Req': 'Request',
@@ -479,47 +572,54 @@ abstract class LogEntry {
if (entry.isEmpty) {
return null;
}
- List<String> components = _parseComponents(entry);
- int timeStamp;
try {
- timeStamp = int.parse(components[0]);
- } catch (exception) {
- print('Invalid time stamp in "${components[0]}"; entry = "$entry"');
- return null;
- }
- String entryKind = components[1];
- if (entryKind == InstrumentationService.TAG_ANALYSIS_TASK) {
- return new TaskEntry(index, timeStamp, components[2], components[3]);
- } else if (entryKind == InstrumentationService.TAG_ERROR) {
- return new ErrorEntry(index, timeStamp, entryKind, components.sublist(2));
- } else if (entryKind == InstrumentationService.TAG_EXCEPTION) {
- return new ExceptionEntry(
+ List<String> components = _parseComponents(entry);
+ int timeStamp;
+ String component = components[0];
+ if (component.startsWith('~')) {
+ component = component.substring(1);
+ }
+ timeStamp = int.parse(component);
+ String entryKind = components[1];
+ if (entryKind == InstrumentationService.TAG_ANALYSIS_TASK) {
+ return new TaskEntry(index, timeStamp, components[2], components[3]);
+ } else if (entryKind == InstrumentationService.TAG_ERROR) {
+ return new ErrorEntry(
+ index, timeStamp, entryKind, components.sublist(2));
+ } else if (entryKind == InstrumentationService.TAG_EXCEPTION) {
+ return new ExceptionEntry(
+ index, timeStamp, entryKind, components.sublist(2));
+ } else if (entryKind == InstrumentationService.TAG_FILE_READ) {
+ // Fall through
+ } else if (entryKind == InstrumentationService.TAG_LOG_ENTRY) {
+ // Fall through
+ } else if (entryKind == InstrumentationService.TAG_NOTIFICATION) {
+ Map requestData = JSON.decode(components[2]);
+ return new NotificationEntry(index, timeStamp, requestData);
+ } else if (entryKind == InstrumentationService.TAG_PERFORMANCE) {
+ // Fall through
+ } else if (entryKind == InstrumentationService.TAG_REQUEST) {
+ Map requestData = JSON.decode(components[2]);
+ return new RequestEntry(index, timeStamp, requestData);
+ } else if (entryKind == InstrumentationService.TAG_RESPONSE) {
+ Map responseData = JSON.decode(components[2]);
+ return new ResponseEntry(index, timeStamp, responseData);
+ } else if (entryKind == InstrumentationService.TAG_SUBPROCESS_START) {
+ // Fall through
+ } else if (entryKind == InstrumentationService.TAG_SUBPROCESS_RESULT) {
+ // Fall through
+ } else if (entryKind == InstrumentationService.TAG_VERSION) {
+ // Fall through
+ } else if (entryKind == InstrumentationService.TAG_WATCH_EVENT) {
+ // Fall through
+ }
+ return new GenericEntry(
index, timeStamp, entryKind, components.sublist(2));
- } else if (entryKind == InstrumentationService.TAG_FILE_READ) {
- // Fall through
- } else if (entryKind == InstrumentationService.TAG_LOG_ENTRY) {
- // Fall through
- } else if (entryKind == InstrumentationService.TAG_NOTIFICATION) {
- Map requestData = JSON.decode(components[2]);
- return new NotificationEntry(index, timeStamp, requestData);
- } else if (entryKind == InstrumentationService.TAG_PERFORMANCE) {
- // Fall through
- } else if (entryKind == InstrumentationService.TAG_REQUEST) {
- Map requestData = JSON.decode(components[2]);
- return new RequestEntry(index, timeStamp, requestData);
- } else if (entryKind == InstrumentationService.TAG_RESPONSE) {
- Map responseData = JSON.decode(components[2]);
- return new ResponseEntry(index, timeStamp, responseData);
- } else if (entryKind == InstrumentationService.TAG_SUBPROCESS_START) {
- // Fall through
- } else if (entryKind == InstrumentationService.TAG_SUBPROCESS_RESULT) {
- // Fall through
- } else if (entryKind == InstrumentationService.TAG_VERSION) {
- // Fall through
- } else if (entryKind == InstrumentationService.TAG_WATCH_EVENT) {
- // Fall through
+ } catch (exception) {
+ LogEntry logEntry = new MalformedLogEntry(index, entry);
+ logEntry.recordProblem(exception.toString());
+ return logEntry;
}
- return new GenericEntry(index, timeStamp, entryKind, components.sublist(2));
}
/**
@@ -608,6 +708,25 @@ abstract class LogEntry {
}
/**
+ * A representation of a malformed log entry.
+ */
+class MalformedLogEntry extends LogEntry {
+ final String entry;
+
+ MalformedLogEntry(int index, this.entry) : super(index, -1);
+
+ @override
+ String get kind => 'Mal';
+
+ @override
+ void _appendDetails(StringBuffer buffer) {
+ super._appendDetails(buffer);
+ buffer.write(entry);
+ buffer.write('<br>');
+ }
+}
+
+/**
* A log entry representing a notification that was sent from the server to the
* client.
*/
@@ -625,6 +744,11 @@ class NotificationEntry extends JsonBasedEntry {
String get event => data['event'];
/**
+ * Return `true` if this is a server error notification.
+ */
+ bool get isServerError => event == 'server.error';
+
+ /**
* Return `true` if this is a server status notification.
*/
bool get isServerStatus => event == 'server.status';
« no previous file with comments | « no previous file | pkg/analysis_server/tool/instrumentation/log_viewer.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698