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 |