| OLD | NEW |
| 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 /** | 5 /** |
| 6 * A representation of the contents of an instrumentation log. | 6 * A representation of the contents of an instrumentation log. |
| 7 */ | 7 */ |
| 8 library analysis_server.tool.instrumentation.log; | 8 library analysis_server.tool.instrumentation.log.log; |
| 9 | 9 |
| 10 import 'dart:collection'; | |
| 11 import 'dart:convert'; | 10 import 'dart:convert'; |
| 12 | 11 |
| 13 import 'package:analyzer/instrumentation/instrumentation.dart'; | 12 import 'package:analyzer/instrumentation/instrumentation.dart'; |
| 14 | 13 |
| 15 /** | 14 /** |
| 15 * A boolean-valued function of one argument. |
| 16 */ |
| 17 typedef bool Predicate<T>(T value); |
| 18 |
| 19 /** |
| 20 * A description of a group of log entries. |
| 21 */ |
| 22 class EntryGroup { |
| 23 /** |
| 24 * A list of all of the instances of this class. |
| 25 */ |
| 26 static final List<EntryGroup> groups = <EntryGroup>[ |
| 27 new EntryGroup._( |
| 28 'nonTask', 'Non-task', (LogEntry entry) => entry is! TaskEntry), |
| 29 new EntryGroup._( |
| 30 'errors', |
| 31 'Errors', |
| 32 (LogEntry entry) => |
| 33 entry is ErrorEntry || |
| 34 entry is ExceptionEntry || |
| 35 (entry is NotificationEntry && entry.isServerError)), |
| 36 new EntryGroup._('malformed', 'Malformed', |
| 37 (LogEntry entry) => entry is MalformedLogEntry), |
| 38 new EntryGroup._('all', 'All', (LogEntry entry) => true), |
| 39 ]; |
| 40 |
| 41 /** |
| 42 * The unique id of the group. |
| 43 */ |
| 44 final String id; |
| 45 |
| 46 /** |
| 47 * The human-readable name of the group. |
| 48 */ |
| 49 final String name; |
| 50 |
| 51 /** |
| 52 * The filter used to determine which entries belong to the group. The filter |
| 53 * should return `true` for members and `false` for non-members. |
| 54 */ |
| 55 final Predicate<LogEntry> filter; |
| 56 |
| 57 /** |
| 58 * Initialize a newly created entry group with the given state. |
| 59 */ |
| 60 EntryGroup._(this.id, this.name, this.filter); |
| 61 |
| 62 /** |
| 63 * Given a list of [entries], return all of the entries in the list that are |
| 64 * members of this group. |
| 65 */ |
| 66 List<LogEntry> computeMembers(List<LogEntry> entries) { |
| 67 return entries.where(filter).toList(); |
| 68 } |
| 69 |
| 70 /** |
| 71 * Return the entry group with the given [id], or `null` if there is no group |
| 72 * with the given id. |
| 73 */ |
| 74 static EntryGroup withId(String id) { |
| 75 for (EntryGroup group in groups) { |
| 76 if (group.id == id) { |
| 77 return group; |
| 78 } |
| 79 } |
| 80 return null; |
| 81 } |
| 82 } |
| 83 |
| 84 /** |
| 16 * A range of log entries, represented by the index of the first and last | 85 * A range of log entries, represented by the index of the first and last |
| 17 * entries in the range. | 86 * entries in the range. |
| 18 */ | 87 */ |
| 19 class EntryRange { | 88 class EntryRange { |
| 20 /** | 89 /** |
| 21 * The index of the first entry in the range. | 90 * The index of the first entry in the range. |
| 22 */ | 91 */ |
| 23 int firstIndex; | 92 int firstIndex; |
| 24 | 93 |
| 25 /** | 94 /** |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 100 * The paths of the log files containing the entries. | 169 * The paths of the log files containing the entries. |
| 101 */ | 170 */ |
| 102 List<String> logFilePaths; | 171 List<String> logFilePaths; |
| 103 | 172 |
| 104 /** | 173 /** |
| 105 * The entries in the instrumentation log. | 174 * The entries in the instrumentation log. |
| 106 */ | 175 */ |
| 107 List<LogEntry> logEntries; | 176 List<LogEntry> logEntries; |
| 108 | 177 |
| 109 /** | 178 /** |
| 110 * The entries in the instrumentation log that are not instances of | 179 * A table mapping the entry groups that have been computed to the list of |
| 111 * [TaskEntry]. | 180 * entries in that group. |
| 112 */ | 181 */ |
| 113 List<LogEntry> nonTaskEntries; | 182 Map<EntryGroup, List<LogEntry>> entryGroups = <EntryGroup, List<LogEntry>>{}; |
| 114 | 183 |
| 115 /** | 184 /** |
| 116 * A table mapping entries that are paired with another entry to the entry | 185 * A table mapping entries that are paired with another entry to the entry |
| 117 * with which they are paired. | 186 * with which they are paired. |
| 118 */ | 187 */ |
| 119 Map<LogEntry, LogEntry> _pairedEntries = new HashMap<LogEntry, LogEntry>(); | 188 Map<LogEntry, LogEntry> _pairedEntries = <LogEntry, LogEntry>{}; |
| 120 | 189 |
| 121 /** | 190 /** |
| 122 * A table mapping the id's of requests to the entry representing the request. | 191 * A table mapping the id's of requests to the entry representing the request. |
| 123 */ | 192 */ |
| 124 Map<String, RequestEntry> _requestMap = new HashMap<String, RequestEntry>(); | 193 Map<String, RequestEntry> _requestMap = <String, RequestEntry>{}; |
| 125 | 194 |
| 126 /** | 195 /** |
| 127 * A table mapping the id's of responses to the entry representing the | 196 * A table mapping the id's of responses to the entry representing the |
| 128 * response. | 197 * response. |
| 129 */ | 198 */ |
| 130 Map<String, ResponseEntry> _responseMap = | 199 Map<String, ResponseEntry> _responseMap = <String, ResponseEntry>{}; |
| 131 new HashMap<String, ResponseEntry>(); | |
| 132 | 200 |
| 133 /** | 201 /** |
| 134 * A table mapping the ids of completion events to the events with those ids. | 202 * A table mapping the ids of completion events to the events with those ids. |
| 135 */ | 203 */ |
| 136 Map<String, List<NotificationEntry>> _completionMap = | 204 Map<String, List<NotificationEntry>> _completionMap = |
| 137 new HashMap<String, List<NotificationEntry>>(); | 205 <String, List<NotificationEntry>>{}; |
| 138 | 206 |
| 139 /** | 207 /** |
| 140 * The ranges of entries that are between analysis start and analysis end | 208 * The ranges of entries that are between analysis start and analysis end |
| 141 * notifications. | 209 * notifications. |
| 142 */ | 210 */ |
| 143 List<EntryRange> analysisRanges; | 211 List<EntryRange> analysisRanges; |
| 144 | 212 |
| 145 /** | 213 /** |
| 146 * Initialize a newly created instrumentation log by parsing each of the lines | 214 * Initialize a newly created instrumentation log by parsing each of the lines |
| 147 * in the [logContent] into a separate entry. The log contents should be the | 215 * in the [logContent] into a separate entry. The log contents should be the |
| 148 * contents of the files whose paths are in the given list of [logFilePaths]. | 216 * contents of the files whose paths are in the given list of [logFilePaths]. |
| 149 */ | 217 */ |
| 150 InstrumentationLog(this.logFilePaths, List<String> logContent) { | 218 InstrumentationLog(this.logFilePaths, List<String> logContent) { |
| 151 _parseLogContent(logContent); | 219 _parseLogContent(logContent); |
| 152 } | 220 } |
| 153 | 221 |
| 154 /** | 222 /** |
| 155 * Return a list of the completion events associated with the given [id]. | 223 * Return a list of the completion events associated with the given [id]. |
| 156 */ | 224 */ |
| 157 List<NotificationEntry> completionEventsWithId(String id) => | 225 List<NotificationEntry> completionEventsWithId(String id) => |
| 158 _completionMap[id]; | 226 _completionMap[id]; |
| 159 | 227 |
| 160 /** | 228 /** |
| 229 * Return the log entries that are contained in the given [group]. |
| 230 */ |
| 231 List<LogEntry> entriesInGroup(EntryGroup group) => |
| 232 entryGroups.putIfAbsent(group, () => group.computeMembers(logEntries)); |
| 233 |
| 234 /** |
| 161 * Return the entry that is paired with the given [entry], or `null` if there | 235 * Return the entry that is paired with the given [entry], or `null` if there |
| 162 * is no entry paired with it. | 236 * is no entry paired with it. |
| 163 */ | 237 */ |
| 164 LogEntry pairedEntry(LogEntry entry) => _pairedEntries[entry]; | 238 LogEntry pairedEntry(LogEntry entry) => _pairedEntries[entry]; |
| 165 | 239 |
| 166 /** | 240 /** |
| 167 * Return the response that corresponds to the given request. | 241 * Return the response that corresponds to the given request. |
| 168 */ | 242 */ |
| 169 RequestEntry requestFor(ResponseEntry entry) => _requestMap[entry.id]; | 243 RequestEntry requestFor(ResponseEntry entry) => _requestMap[entry.id]; |
| 170 | 244 |
| 171 /** | 245 /** |
| 172 * Return the response that corresponds to the given request. | 246 * Return the response that corresponds to the given request. |
| 173 */ | 247 */ |
| 174 ResponseEntry responseFor(RequestEntry entry) => _responseMap[entry.id]; | 248 ResponseEntry responseFor(RequestEntry entry) => _responseMap[entry.id]; |
| 175 | 249 |
| 176 /** | 250 /** |
| 177 * Return a list containing all of the task entries between the start of | 251 * Return a list containing all of the task entries between the start of |
| 178 * analysis notification at the given [startIndex] and the matching end of | 252 * analysis notification at the given [startIndex] and the matching end of |
| 179 * analysis notification (or the end of the log if the log does not contain a | 253 * analysis notification (or the end of the log if the log does not contain a |
| 180 * corresponding end notification. | 254 * corresponding end notification. |
| 181 */ | 255 */ |
| 182 List<TaskEntry> taskEntriesFor(int startIndex) { | 256 List<TaskEntry> taskEntriesFor(int startIndex) { |
| 183 List<TaskEntry> taskEntries = <TaskEntry>[]; | 257 List<TaskEntry> taskEntries = <TaskEntry>[]; |
| 184 NotificationEntry startEntry = nonTaskEntries[startIndex]; | 258 NotificationEntry startEntry = logEntries[startIndex]; |
| 185 LogEntry endEntry = pairedEntry(startEntry); | 259 LogEntry endEntry = pairedEntry(startEntry); |
| 186 int lastIndex = endEntry == null ? logEntries.length : endEntry.index; | 260 int lastIndex = endEntry == null ? logEntries.length : endEntry.index; |
| 187 for (int i = startEntry.index + 1; i < lastIndex; i++) { | 261 for (int i = startEntry.index + 1; i < lastIndex; i++) { |
| 188 LogEntry entry = logEntries[i]; | 262 LogEntry entry = logEntries[i]; |
| 189 if (entry is TaskEntry) { | 263 if (entry is TaskEntry) { |
| 190 taskEntries.add(entry); | 264 taskEntries.add(entry); |
| 191 } | 265 } |
| 192 } | 266 } |
| 193 return taskEntries; | 267 return taskEntries; |
| 194 } | 268 } |
| 195 | 269 |
| 196 /** | 270 /** |
| 271 * Return `true` if the given [logContent] appears to be from session data. |
| 272 */ |
| 273 bool _isSessionData(List<String> logContent) { |
| 274 if (logContent.length < 2) { |
| 275 return false; |
| 276 } |
| 277 String firstLine = logContent[0]; |
| 278 return firstLine.startsWith('-----') && logContent[1].startsWith('~') || |
| 279 firstLine.startsWith('~'); |
| 280 } |
| 281 |
| 282 /** |
| 197 * Merge any multi-line entries into a single line so that every element in | 283 * Merge any multi-line entries into a single line so that every element in |
| 198 * the given [logContent] is a single entry. | 284 * the given [logContent] is a single entry. |
| 199 */ | 285 */ |
| 200 void _mergeEntries(List<String> logContent) { | 286 void _mergeEntries(List<String> logContent) { |
| 201 bool isStartOfEntry(String line) { | 287 bool isStartOfEntry(String line) { |
| 202 return line.startsWith(LogEntry.entryRegExp); | 288 return line.startsWith(LogEntry.entryRegExp); |
| 203 } | 289 } |
| 204 | 290 |
| 205 String merge(String line, List<String> extraLines) { | 291 String merge(String line, List<String> extraLines) { |
| 206 StringBuffer buffer = new StringBuffer(); | 292 StringBuffer buffer = new StringBuffer(); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 226 if (extraLines.isNotEmpty) { | 312 if (extraLines.isNotEmpty) { |
| 227 throw new StateError( | 313 throw new StateError( |
| 228 '${extraLines.length} non-entry lines before any entry'); | 314 '${extraLines.length} non-entry lines before any entry'); |
| 229 } | 315 } |
| 230 } | 316 } |
| 231 | 317 |
| 232 /** | 318 /** |
| 233 * Parse the given [logContent] into a list of log entries. | 319 * Parse the given [logContent] into a list of log entries. |
| 234 */ | 320 */ |
| 235 void _parseLogContent(List<String> logContent) { | 321 void _parseLogContent(List<String> logContent) { |
| 236 _mergeEntries(logContent); | 322 if (_isSessionData(logContent)) { |
| 323 if (logContent[0].startsWith('-----')) { |
| 324 logContent.removeAt(0); |
| 325 } |
| 326 int lastIndex = logContent.length - 1; |
| 327 if (logContent[lastIndex].startsWith('extraction complete')) { |
| 328 logContent.removeAt(lastIndex); |
| 329 } |
| 330 } else { |
| 331 _mergeEntries(logContent); |
| 332 } |
| 237 logEntries = <LogEntry>[]; | 333 logEntries = <LogEntry>[]; |
| 238 nonTaskEntries = <LogEntry>[]; | |
| 239 analysisRanges = <EntryRange>[]; | 334 analysisRanges = <EntryRange>[]; |
| 240 NotificationEntry analysisStartEntry = null; | 335 NotificationEntry analysisStartEntry = null; |
| 241 int analysisStartIndex = -1; | 336 int analysisStartIndex = -1; |
| 242 NotificationEntry pubStartEntry = null; | 337 NotificationEntry pubStartEntry = null; |
| 243 for (String line in logContent) { | 338 for (String line in logContent) { |
| 244 LogEntry entry = new LogEntry.from(logEntries.length, line); | 339 LogEntry entry = new LogEntry.from(logEntries.length, line); |
| 245 if (entry != null) { | 340 if (entry != null) { |
| 246 logEntries.add(entry); | 341 logEntries.add(entry); |
| 247 if (entry is! TaskEntry) { | |
| 248 nonTaskEntries.add(entry); | |
| 249 } | |
| 250 if (entry is RequestEntry) { | 342 if (entry is RequestEntry) { |
| 251 _requestMap[entry.id] = entry; | 343 _requestMap[entry.id] = entry; |
| 252 } else if (entry is ResponseEntry) { | 344 } else if (entry is ResponseEntry) { |
| 253 _responseMap[entry.id] = entry; | 345 _responseMap[entry.id] = entry; |
| 254 RequestEntry request = _requestMap[entry.id]; | 346 RequestEntry request = _requestMap[entry.id]; |
| 255 _pairedEntries[entry] = request; | 347 _pairedEntries[entry] = request; |
| 256 _pairedEntries[request] = entry; | 348 _pairedEntries[request] = entry; |
| 257 } else if (entry is NotificationEntry) { | 349 } else if (entry is NotificationEntry) { |
| 258 if (entry.isServerStatus) { | 350 if (entry.isServerStatus) { |
| 259 var analysisStatus = entry.param('analysis'); | 351 var analysisStatus = entry.param('analysis'); |
| (...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 432 */ | 524 */ |
| 433 static final RegExp entryRegExp = new RegExp('[0-9]+\\:'); | 525 static final RegExp entryRegExp = new RegExp('[0-9]+\\:'); |
| 434 | 526 |
| 435 /** | 527 /** |
| 436 * A table mapping kinds to the names of those kinds. | 528 * A table mapping kinds to the names of those kinds. |
| 437 */ | 529 */ |
| 438 static final Map<String, String> kindMap = { | 530 static final Map<String, String> kindMap = { |
| 439 'Err': 'Error', | 531 'Err': 'Error', |
| 440 'Ex': 'Exception', | 532 'Ex': 'Exception', |
| 441 'Log': 'Log message', | 533 'Log': 'Log message', |
| 534 'Mal': 'Malformed entry', |
| 442 'Noti': 'Notification', | 535 'Noti': 'Notification', |
| 443 'Read': 'Read file', | 536 'Read': 'Read file', |
| 444 'Req': 'Request', | 537 'Req': 'Request', |
| 445 'Res': 'Response', | 538 'Res': 'Response', |
| 446 'Perf': 'Performance data', | 539 'Perf': 'Performance data', |
| 447 'SPResult': 'Subprocess result', | 540 'SPResult': 'Subprocess result', |
| 448 'SPStart': 'Subprocess start', | 541 'SPStart': 'Subprocess start', |
| 449 'Task': 'Task', | 542 'Task': 'Task', |
| 450 'Ver': 'Version information', | 543 'Ver': 'Version information', |
| 451 'Watch': 'Watch event', | 544 'Watch': 'Watch event', |
| (...skipping 20 matching lines...) Expand all Loading... |
| 472 */ | 565 */ |
| 473 LogEntry(this.index, this.timeStamp); | 566 LogEntry(this.index, this.timeStamp); |
| 474 | 567 |
| 475 /** | 568 /** |
| 476 * Create a log entry from the given encoded form of the [entry]. | 569 * Create a log entry from the given encoded form of the [entry]. |
| 477 */ | 570 */ |
| 478 factory LogEntry.from(int index, String entry) { | 571 factory LogEntry.from(int index, String entry) { |
| 479 if (entry.isEmpty) { | 572 if (entry.isEmpty) { |
| 480 return null; | 573 return null; |
| 481 } | 574 } |
| 482 List<String> components = _parseComponents(entry); | |
| 483 int timeStamp; | |
| 484 try { | 575 try { |
| 485 timeStamp = int.parse(components[0]); | 576 List<String> components = _parseComponents(entry); |
| 577 int timeStamp; |
| 578 String component = components[0]; |
| 579 if (component.startsWith('~')) { |
| 580 component = component.substring(1); |
| 581 } |
| 582 timeStamp = int.parse(component); |
| 583 String entryKind = components[1]; |
| 584 if (entryKind == InstrumentationService.TAG_ANALYSIS_TASK) { |
| 585 return new TaskEntry(index, timeStamp, components[2], components[3]); |
| 586 } else if (entryKind == InstrumentationService.TAG_ERROR) { |
| 587 return new ErrorEntry( |
| 588 index, timeStamp, entryKind, components.sublist(2)); |
| 589 } else if (entryKind == InstrumentationService.TAG_EXCEPTION) { |
| 590 return new ExceptionEntry( |
| 591 index, timeStamp, entryKind, components.sublist(2)); |
| 592 } else if (entryKind == InstrumentationService.TAG_FILE_READ) { |
| 593 // Fall through |
| 594 } else if (entryKind == InstrumentationService.TAG_LOG_ENTRY) { |
| 595 // Fall through |
| 596 } else if (entryKind == InstrumentationService.TAG_NOTIFICATION) { |
| 597 Map requestData = JSON.decode(components[2]); |
| 598 return new NotificationEntry(index, timeStamp, requestData); |
| 599 } else if (entryKind == InstrumentationService.TAG_PERFORMANCE) { |
| 600 // Fall through |
| 601 } else if (entryKind == InstrumentationService.TAG_REQUEST) { |
| 602 Map requestData = JSON.decode(components[2]); |
| 603 return new RequestEntry(index, timeStamp, requestData); |
| 604 } else if (entryKind == InstrumentationService.TAG_RESPONSE) { |
| 605 Map responseData = JSON.decode(components[2]); |
| 606 return new ResponseEntry(index, timeStamp, responseData); |
| 607 } else if (entryKind == InstrumentationService.TAG_SUBPROCESS_START) { |
| 608 // Fall through |
| 609 } else if (entryKind == InstrumentationService.TAG_SUBPROCESS_RESULT) { |
| 610 // Fall through |
| 611 } else if (entryKind == InstrumentationService.TAG_VERSION) { |
| 612 // Fall through |
| 613 } else if (entryKind == InstrumentationService.TAG_WATCH_EVENT) { |
| 614 // Fall through |
| 615 } |
| 616 return new GenericEntry( |
| 617 index, timeStamp, entryKind, components.sublist(2)); |
| 486 } catch (exception) { | 618 } catch (exception) { |
| 487 print('Invalid time stamp in "${components[0]}"; entry = "$entry"'); | 619 LogEntry logEntry = new MalformedLogEntry(index, entry); |
| 488 return null; | 620 logEntry.recordProblem(exception.toString()); |
| 621 return logEntry; |
| 489 } | 622 } |
| 490 String entryKind = components[1]; | |
| 491 if (entryKind == InstrumentationService.TAG_ANALYSIS_TASK) { | |
| 492 return new TaskEntry(index, timeStamp, components[2], components[3]); | |
| 493 } else if (entryKind == InstrumentationService.TAG_ERROR) { | |
| 494 return new ErrorEntry(index, timeStamp, entryKind, components.sublist(2)); | |
| 495 } else if (entryKind == InstrumentationService.TAG_EXCEPTION) { | |
| 496 return new ExceptionEntry( | |
| 497 index, timeStamp, entryKind, components.sublist(2)); | |
| 498 } else if (entryKind == InstrumentationService.TAG_FILE_READ) { | |
| 499 // Fall through | |
| 500 } else if (entryKind == InstrumentationService.TAG_LOG_ENTRY) { | |
| 501 // Fall through | |
| 502 } else if (entryKind == InstrumentationService.TAG_NOTIFICATION) { | |
| 503 Map requestData = JSON.decode(components[2]); | |
| 504 return new NotificationEntry(index, timeStamp, requestData); | |
| 505 } else if (entryKind == InstrumentationService.TAG_PERFORMANCE) { | |
| 506 // Fall through | |
| 507 } else if (entryKind == InstrumentationService.TAG_REQUEST) { | |
| 508 Map requestData = JSON.decode(components[2]); | |
| 509 return new RequestEntry(index, timeStamp, requestData); | |
| 510 } else if (entryKind == InstrumentationService.TAG_RESPONSE) { | |
| 511 Map responseData = JSON.decode(components[2]); | |
| 512 return new ResponseEntry(index, timeStamp, responseData); | |
| 513 } else if (entryKind == InstrumentationService.TAG_SUBPROCESS_START) { | |
| 514 // Fall through | |
| 515 } else if (entryKind == InstrumentationService.TAG_SUBPROCESS_RESULT) { | |
| 516 // Fall through | |
| 517 } else if (entryKind == InstrumentationService.TAG_VERSION) { | |
| 518 // Fall through | |
| 519 } else if (entryKind == InstrumentationService.TAG_WATCH_EVENT) { | |
| 520 // Fall through | |
| 521 } | |
| 522 return new GenericEntry(index, timeStamp, entryKind, components.sublist(2)); | |
| 523 } | 623 } |
| 524 | 624 |
| 525 /** | 625 /** |
| 526 * Return `true` if any problems were found while processing the log file. | 626 * Return `true` if any problems were found while processing the log file. |
| 527 */ | 627 */ |
| 528 bool get hasProblems => _problems != null; | 628 bool get hasProblems => _problems != null; |
| 529 | 629 |
| 530 /** | 630 /** |
| 531 * Return the value of the component used to indicate the kind of the entry. | 631 * Return the value of the component used to indicate the kind of the entry. |
| 532 * This is the abbreviation recorded in the entry. | 632 * This is the abbreviation recorded in the entry. |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 601 } else { | 701 } else { |
| 602 component.writeCharCode(char); | 702 component.writeCharCode(char); |
| 603 } | 703 } |
| 604 } | 704 } |
| 605 components.add(component.toString()); | 705 components.add(component.toString()); |
| 606 return components; | 706 return components; |
| 607 } | 707 } |
| 608 } | 708 } |
| 609 | 709 |
| 610 /** | 710 /** |
| 711 * A representation of a malformed log entry. |
| 712 */ |
| 713 class MalformedLogEntry extends LogEntry { |
| 714 final String entry; |
| 715 |
| 716 MalformedLogEntry(int index, this.entry) : super(index, -1); |
| 717 |
| 718 @override |
| 719 String get kind => 'Mal'; |
| 720 |
| 721 @override |
| 722 void _appendDetails(StringBuffer buffer) { |
| 723 super._appendDetails(buffer); |
| 724 buffer.write(entry); |
| 725 buffer.write('<br>'); |
| 726 } |
| 727 } |
| 728 |
| 729 /** |
| 611 * A log entry representing a notification that was sent from the server to the | 730 * A log entry representing a notification that was sent from the server to the |
| 612 * client. | 731 * client. |
| 613 */ | 732 */ |
| 614 class NotificationEntry extends JsonBasedEntry { | 733 class NotificationEntry extends JsonBasedEntry { |
| 615 /** | 734 /** |
| 616 * Initialize a newly created response to have the given [timeStamp] and | 735 * Initialize a newly created response to have the given [timeStamp] and |
| 617 * [notificationData]. | 736 * [notificationData]. |
| 618 */ | 737 */ |
| 619 NotificationEntry(int index, int timeStamp, Map notificationData) | 738 NotificationEntry(int index, int timeStamp, Map notificationData) |
| 620 : super(index, timeStamp, notificationData); | 739 : super(index, timeStamp, notificationData); |
| 621 | 740 |
| 622 /** | 741 /** |
| 623 * Return the event field of the request. | 742 * Return the event field of the request. |
| 624 */ | 743 */ |
| 625 String get event => data['event']; | 744 String get event => data['event']; |
| 626 | 745 |
| 627 /** | 746 /** |
| 747 * Return `true` if this is a server error notification. |
| 748 */ |
| 749 bool get isServerError => event == 'server.error'; |
| 750 |
| 751 /** |
| 628 * Return `true` if this is a server status notification. | 752 * Return `true` if this is a server status notification. |
| 629 */ | 753 */ |
| 630 bool get isServerStatus => event == 'server.status'; | 754 bool get isServerStatus => event == 'server.status'; |
| 631 | 755 |
| 632 @override | 756 @override |
| 633 String get kind => 'Noti'; | 757 String get kind => 'Noti'; |
| 634 | 758 |
| 635 /** | 759 /** |
| 636 * Return the value of the parameter with the given [parameterName], or `null` | 760 * Return the value of the parameter with the given [parameterName], or `null` |
| 637 * if there is no such parameter. | 761 * if there is no such parameter. |
| (...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 798 int slash = context.lastIndexOf('/'); | 922 int slash = context.lastIndexOf('/'); |
| 799 if (slash < 0) { | 923 if (slash < 0) { |
| 800 slash = context.lastIndexOf('\\'); | 924 slash = context.lastIndexOf('\\'); |
| 801 } | 925 } |
| 802 if (slash >= 0) { | 926 if (slash >= 0) { |
| 803 String prefix = context.substring(0, slash); | 927 String prefix = context.substring(0, slash); |
| 804 _target = _target.replaceAll(prefix, '...'); | 928 _target = _target.replaceAll(prefix, '...'); |
| 805 } | 929 } |
| 806 } | 930 } |
| 807 } | 931 } |
| OLD | NEW |