Index: pkg/analysis_server/lib/src/status/get_handler.dart |
diff --git a/pkg/analysis_server/lib/src/status/get_handler.dart b/pkg/analysis_server/lib/src/status/get_handler.dart |
index 05937c040747f61a568b0769294fc654b37e40df..b92c38cbd6976585b03e8c6e89329226a91bbc61 100644 |
--- a/pkg/analysis_server/lib/src/status/get_handler.dart |
+++ b/pkg/analysis_server/lib/src/status/get_handler.dart |
@@ -24,6 +24,7 @@ import 'package:analysis_server/src/services/index/store/split_store.dart'; |
import 'package:analysis_server/src/socket_server.dart'; |
import 'package:analysis_server/src/status/ast_writer.dart'; |
import 'package:analysis_server/src/status/element_writer.dart'; |
+import 'package:analysis_server/src/status/validator.dart'; |
import 'package:analysis_server/src/utilities/average.dart'; |
import 'package:analyzer/file_system/file_system.dart'; |
import 'package:analyzer/src/context/cache.dart'; |
@@ -93,6 +94,17 @@ class GetHandler { |
static const String COMMUNICATION_PERFORMANCE_PATH = '/perf/communication'; |
/** |
+ * The path used to request diagnostic information for a single context. |
+ */ |
+ static const String CONTEXT_DIAGNOSTICS_PATH = '/diagnostic/context'; |
+ |
+ /** |
+ * The path used to request running a validation report for a single context. |
+ */ |
+ static const String CONTEXT_VALIDATION_DIAGNOSTICS_PATH = |
+ '/diagnostic/contextValidation'; |
+ |
+ /** |
* The path used to request information about a specific context. |
*/ |
static const String CONTEXT_PATH = '/context'; |
@@ -221,7 +233,7 @@ class GetHandler { |
*/ |
void handleGetRequest(HttpRequest request) { |
String path = request.uri.path; |
- if (path == STATUS_PATH) { |
+ if (path == '/' || path == STATUS_PATH) { |
_returnServerStatus(request); |
} else if (path == ANALYSIS_PERFORMANCE_PATH) { |
_returnAnalysisPerformance(request); |
@@ -235,6 +247,10 @@ class GetHandler { |
_returnCompletionInfo(request); |
} else if (path == COMMUNICATION_PERFORMANCE_PATH) { |
_returnCommunicationPerformance(request); |
+ } else if (path == CONTEXT_DIAGNOSTICS_PATH) { |
+ _returnContextDiagnostics(request); |
+ } else if (path == CONTEXT_VALIDATION_DIAGNOSTICS_PATH) { |
+ _returnContextValidationDiagnostics(request); |
} else if (path == CONTEXT_PATH) { |
_returnContextInfo(request); |
} else if (path == DIAGNOSTIC_PATH) { |
@@ -973,6 +989,34 @@ class GetHandler { |
} |
/** |
+ * Return a response displaying diagnostic information for a single context. |
+ */ |
+ void _returnContextDiagnostics(HttpRequest request) { |
+ AnalysisServer analysisServer = _server.analysisServer; |
+ if (analysisServer == null) { |
+ return _returnFailure(request, 'Analysis server is not running'); |
+ } |
+ String contextFilter = request.uri.queryParameters[CONTEXT_QUERY_PARAM]; |
+ if (contextFilter == null) { |
+ return _returnFailure( |
+ request, 'Query parameter $CONTEXT_QUERY_PARAM required'); |
+ } |
+ Folder folder = _findFolder(analysisServer, contextFilter); |
+ if (folder == null) { |
+ return _returnFailure(request, 'Invalid context: $contextFilter'); |
+ } |
+ |
+ InternalAnalysisContext context = analysisServer.folderMap[folder]; |
+ |
+ _writeResponse(request, (StringBuffer buffer) { |
+ _writePage(buffer, 'Analysis Server - Context Diagnostics', |
+ ['Context: $contextFilter'], (StringBuffer buffer) { |
+ _writeContextDiagnostics(buffer, context); |
+ }); |
+ }); |
+ } |
+ |
+ /** |
* Return a response containing information about a single source file in the |
* cache. |
*/ |
@@ -1032,9 +1076,6 @@ class GetHandler { |
explicitNames.sort(); |
implicitNames.sort(); |
- AnalysisDriver driver = (context as AnalysisContextImpl).driver; |
- List<WorkItem> workItems = driver.currentWorkOrder?.workItems; |
- |
_overlayContents.clear(); |
context.visitContentCache((String fullName, int stamp, String contents) { |
_overlayContents[fullName] = contents; |
@@ -1065,69 +1106,54 @@ class GetHandler { |
_writePage( |
buffer, 'Analysis Server - Context', ['Context: $contextFilter'], |
(StringBuffer buffer) { |
- buffer.write('<h3>Most Recently Perfomed Tasks</h3>'); |
- AnalysisTask.LAST_TASKS.forEach((String description) { |
- buffer.write('<p>$description</p>'); |
- }); |
- |
- String _describe(WorkItem item) { |
- if (item == null) { |
- return 'None'; |
- } |
- return '${item.descriptor?.name} computing ${item.spawningResult?.name} for ${item.target?.toString()}'; |
- } |
- |
- buffer.write('<h3>Work Items</h3>'); |
- buffer.write( |
- '<p><b>Current:</b> ${_describe(driver.currentWorkOrder?.current)}</p>'); |
- if (workItems != null) { |
- buffer.writeAll(workItems.reversed |
- .map((item) => '<p>${_describe(item)}</p>') |
- ?.toList()); |
- } |
- |
buffer.write('<h3>Configuration</h3>'); |
- AnalysisOptionsImpl options = context.analysisOptions; |
- buffer.write('<p><b>Options</b></p>'); |
- buffer.write('<p>'); |
- _writeOption( |
- buffer, 'Analyze functon bodies', options.analyzeFunctionBodies); |
- _writeOption(buffer, 'Cache size', options.cacheSize); |
- _writeOption( |
- buffer, 'Enable generic methods', options.enableGenericMethods); |
- _writeOption(buffer, 'Enable strict call checks', |
- options.enableStrictCallChecks); |
- _writeOption(buffer, 'Enable super mixins', options.enableSuperMixins); |
- _writeOption(buffer, 'Generate dart2js hints', options.dart2jsHint); |
- _writeOption(buffer, 'Generate errors in implicit files', |
- options.generateImplicitErrors); |
- _writeOption( |
- buffer, 'Generate errors in SDK files', options.generateSdkErrors); |
- _writeOption(buffer, 'Generate hints', options.hint); |
- _writeOption(buffer, 'Incremental resolution', options.incremental); |
- _writeOption(buffer, 'Incremental resolution with API changes', |
- options.incrementalApi); |
- _writeOption(buffer, 'Preserve comments', options.preserveComments); |
- _writeOption(buffer, 'Strong mode', options.strongMode); |
- _writeOption(buffer, 'Strong mode hints', options.strongModeHints, |
- last: true); |
- buffer.write('</p>'); |
- |
- List<Linter> lints = context.getConfigurationData(CONFIGURED_LINTS_KEY); |
- buffer.write('<p><b>Lints</b></p>'); |
- if (lints.isEmpty) { |
- buffer.write('<p><none></p>'); |
- } else { |
- for (Linter lint in lints) { |
- buffer.write('<p> ${lint.runtimeType}</p>'); |
+ _writeTwoColumns(buffer, (StringBuffer buffer) { |
+ AnalysisOptionsImpl options = context.analysisOptions; |
+ buffer.write('<p><b>Options</b></p>'); |
+ buffer.write('<p>'); |
+ _writeOption( |
+ buffer, 'Analyze functon bodies', options.analyzeFunctionBodies); |
+ _writeOption(buffer, 'Cache size', options.cacheSize); |
+ _writeOption( |
+ buffer, 'Enable generic methods', options.enableGenericMethods); |
+ _writeOption(buffer, 'Enable strict call checks', |
+ options.enableStrictCallChecks); |
+ _writeOption( |
+ buffer, 'Enable super mixins', options.enableSuperMixins); |
+ _writeOption(buffer, 'Generate dart2js hints', options.dart2jsHint); |
+ _writeOption(buffer, 'Generate errors in implicit files', |
+ options.generateImplicitErrors); |
+ _writeOption(buffer, 'Generate errors in SDK files', |
+ options.generateSdkErrors); |
+ _writeOption(buffer, 'Generate hints', options.hint); |
+ _writeOption(buffer, 'Incremental resolution', options.incremental); |
+ _writeOption(buffer, 'Incremental resolution with API changes', |
+ options.incrementalApi); |
+ _writeOption(buffer, 'Preserve comments', options.preserveComments); |
+ _writeOption(buffer, 'Strong mode', options.strongMode); |
+ _writeOption(buffer, 'Strong mode hints', options.strongModeHints, |
+ last: true); |
+ buffer.write('</p>'); |
+ }, (StringBuffer buffer) { |
+ List<Linter> lints = |
+ context.getConfigurationData(CONFIGURED_LINTS_KEY); |
+ buffer.write('<p><b>Lints</b></p>'); |
+ if (lints.isEmpty) { |
+ buffer.write('<p>none</p>'); |
+ } else { |
+ for (Linter lint in lints) { |
+ buffer.write('<p>'); |
+ buffer.write(lint.runtimeType); |
+ buffer.write('</p>'); |
+ } |
} |
- } |
- List<ErrorFilter> errorFilters = |
- context.getConfigurationData(CONFIGURED_ERROR_FILTERS); |
- int filterCount = errorFilters?.length ?? 0; |
- buffer.write('<p><b>Error Filter count</b>: $filterCount</p>'); |
+ List<ErrorFilter> errorFilters = |
+ context.getConfigurationData(CONFIGURED_ERROR_FILTERS); |
+ int filterCount = errorFilters?.length ?? 0; |
+ buffer.write('<p><b>Error Filter count</b>: $filterCount</p>'); |
+ }); |
_writeFiles(buffer, 'Priority Files', priorityNames); |
_writeFiles(buffer, 'Explicitly Analyzed Files', explicitNames); |
@@ -1135,12 +1161,57 @@ class GetHandler { |
buffer.write('<h3>Exceptions</h3>'); |
if (exceptions.isEmpty) { |
- buffer.write('<p>None</p>'); |
+ buffer.write('<p>none</p>'); |
} else { |
exceptions.forEach((CaughtException exception) { |
_writeException(buffer, exception); |
}); |
} |
+ |
+ buffer.write('<h3>Targets Without Entries</h3>'); |
+ bool foundEntry = false; |
+ MapIterator<AnalysisTarget, CacheEntry> iterator = |
+ context.analysisCache.iterator(context: context); |
+ while (iterator.moveNext()) { |
+ if (iterator.value == null) { |
+ foundEntry = true; |
+ buffer.write('<p>'); |
+ buffer.write(iterator.key.toString()); |
scheglov
2015/12/07 06:19:29
The runtimeType is also interesting.
Brian Wilkerson
2015/12/07 16:03:25
Done
|
+ buffer.write('</p>'); |
+ } |
+ } |
+ if (!foundEntry) { |
+ buffer.write('<p>none</p>'); |
+ } |
+ }); |
+ }); |
+ } |
+ |
+ /** |
+ * Return a response displaying the results of running a validation report on |
+ * a single context. |
+ */ |
+ void _returnContextValidationDiagnostics(HttpRequest request) { |
+ AnalysisServer analysisServer = _server.analysisServer; |
+ if (analysisServer == null) { |
+ return _returnFailure(request, 'Analysis server is not running'); |
+ } |
+ String contextFilter = request.uri.queryParameters[CONTEXT_QUERY_PARAM]; |
+ if (contextFilter == null) { |
+ return _returnFailure( |
+ request, 'Query parameter $CONTEXT_QUERY_PARAM required'); |
+ } |
+ Folder folder = _findFolder(analysisServer, contextFilter); |
+ if (folder == null) { |
+ return _returnFailure(request, 'Invalid context: $contextFilter'); |
+ } |
+ |
+ InternalAnalysisContext context = analysisServer.folderMap[folder]; |
+ |
+ _writeResponse(request, (StringBuffer buffer) { |
+ _writePage(buffer, 'Analysis Server - Context Validation Diagnostics', |
+ ['Context: $contextFilter'], (StringBuffer buffer) { |
+ _writeContextValidationDiagnostics(buffer, context); |
}); |
}); |
} |
@@ -1149,8 +1220,6 @@ class GetHandler { |
* Return a response displaying diagnostic information. |
*/ |
void _returnDiagnosticInfo(HttpRequest request) { |
- String value = request.requestedUri.queryParameters['index']; |
- int index = value != null ? int.parse(value, onError: (_) => 0) : 0; |
_writeResponse(request, (StringBuffer buffer) { |
_writePage(buffer, 'Analysis Server - Diagnostic info', [], |
(StringBuffer buffer) { |
@@ -1332,23 +1401,19 @@ class GetHandler { |
void _returnUnknownRequest(HttpRequest request) { |
_writeResponse(request, (StringBuffer buffer) { |
_writePage(buffer, 'Analysis Server', [], (StringBuffer buffer) { |
- buffer.write('<h3>Pages</h3>'); |
- buffer.write('<p>'); |
- buffer.write(makeLink(COMPLETION_PATH, {}, 'Completion data')); |
- buffer.write('</p>'); |
- buffer.write('<p>'); |
- buffer |
- .write(makeLink(COMMUNICATION_PERFORMANCE_PATH, {}, 'Performance')); |
- buffer.write('</p>'); |
- buffer.write('<p>'); |
- buffer.write(makeLink(STATUS_PATH, {}, 'Server status')); |
- buffer.write('</p>'); |
- buffer.write('<p>'); |
- buffer.write(makeLink(OVERLAYS_PATH, {}, 'File overlays')); |
- buffer.write('</p>'); |
- buffer.write('<p>'); |
- buffer.write(makeLink(DIAGNOSTIC_PATH, {}, 'Diagnostic info')); |
- buffer.write('</p>'); |
+ buffer.write('<h3>Unknown page: '); |
+ buffer.write(request.uri.path); |
+ buffer.write('</h3>'); |
+ buffer.write(''' |
+ <p> |
+ You have reached an un-recognized page. If you reached this page by |
+ following a link from a status page, please report the broken link to |
+ the Dart analyzer team: |
+ <a>https://github.com/dart-lang/sdk/issues/new</a>. |
+ </p><p> |
+ If you mistyped the URL, you can correct it or return to |
+ ${makeLink(STATUS_PATH, {}, 'the main status page')}. |
+ </p>'''); |
}); |
}); |
} |
@@ -1374,7 +1439,6 @@ class GetHandler { |
List<Folder> folders = folderMap.keys.toList(); |
folders.sort((Folder first, Folder second) => |
first.shortName.compareTo(second.shortName)); |
- AnalysisOptionsImpl options = analysisServer.defaultContextOptions; |
ServerOperationQueue operationQueue = analysisServer.operationQueue; |
buffer.write('<h3>Analysis Domain</h3>'); |
@@ -1394,6 +1458,9 @@ class GetHandler { |
buffer.write('<p>Status: Analyzing</p>'); |
} |
} |
+ buffer.write('<p>'); |
+ buffer.write(makeLink(OVERLAYS_PATH, {}, 'All overlay information')); |
+ buffer.write('</p>'); |
buffer.write('<p><b>Analysis Contexts</b></p>'); |
buffer.write('<p>'); |
@@ -1407,8 +1474,12 @@ class GetHandler { |
String key = folder.shortName; |
buffer.write(makeLink(CONTEXT_PATH, {CONTEXT_QUERY_PARAM: folder.path}, |
key, _hasException(folderMap[folder]))); |
+ buffer.write(' <small><b>['); |
+ buffer.write(makeLink(CONTEXT_DIAGNOSTICS_PATH, |
+ {CONTEXT_QUERY_PARAM: folder.path}, 'diagnostics')); |
+ buffer.write(']</b></small>'); |
if (!folder.getChild('.packages').exists) { |
- buffer.write(' <b>[No .packages file]</b>'); |
+ buffer.write(' <small>[no .packages file]</small>'); |
} |
}); |
// TODO(brianwilkerson) Add items for the SDK contexts (currently only one). |
@@ -1416,9 +1487,9 @@ class GetHandler { |
int freq = AnalysisServer.performOperationDelayFreqency; |
String delay = freq > 0 ? '1 ms every $freq ms' : 'off'; |
- buffer.write('<p><b>perform operation delay:</b> $delay</p>'); |
buffer.write('<p><b>Performance Data</b></p>'); |
+ buffer.write('<p>Perform operation delay: $delay</p>'); |
buffer.write('<p>'); |
buffer.write(makeLink(ANALYSIS_PERFORMANCE_PATH, {}, 'Task data')); |
buffer.write('</p>'); |
@@ -1531,6 +1602,70 @@ class GetHandler { |
} |
/** |
+ * Write diagnostic information about the given [context] to the given |
+ * [buffer]. |
+ */ |
+ void _writeContextDiagnostics( |
+ StringBuffer buffer, InternalAnalysisContext context) { |
+ AnalysisDriver driver = (context as AnalysisContextImpl).driver; |
+ List<WorkItem> workItems = driver.currentWorkOrder?.workItems; |
+ |
+ buffer.write('<p>'); |
+ buffer.write(makeLink(CONTEXT_VALIDATION_DIAGNOSTICS_PATH, |
+ {CONTEXT_QUERY_PARAM: context.name}, 'Run validation')); |
+ buffer.write('</p>'); |
+ |
+ buffer.write('<h3>Most Recently Perfomed Tasks</h3>'); |
+ AnalysisTask.LAST_TASKS.forEach((String description) { |
+ buffer.write('<p>'); |
+ buffer.write(description); |
+ buffer.write('</p>'); |
+ }); |
+ |
+ void writeWorkItem(StringBuffer buffer, WorkItem item) { |
+ if (item == null) { |
+ buffer.write('none'); |
+ } else { |
+ buffer.write(item.descriptor?.name); |
+ buffer.write(' computing '); |
+ buffer.write(item.spawningResult?.name); |
+ buffer.write(' for '); |
+ buffer.write(item.target); |
+ } |
+ } |
+ |
+ buffer.write('<h3>Work Items</h3>'); |
+ buffer.write('<p><b>Current:</b> '); |
+ writeWorkItem(buffer, driver.currentWorkOrder?.current); |
+ buffer.write('</p>'); |
+ if (workItems != null) { |
+ workItems.reversed.forEach((WorkItem item) { |
+ buffer.write('<p>'); |
+ writeWorkItem(buffer, item); |
+ buffer.write('</p>'); |
+ }); |
+ } |
+ } |
+ |
+ /** |
+ * Write diagnostic information about the given [context] to the given |
+ * [buffer]. |
+ */ |
+ void _writeContextValidationDiagnostics( |
+ StringBuffer buffer, InternalAnalysisContext context) { |
+ Stopwatch stopwatch = new Stopwatch(); |
+ stopwatch.start(); |
+ ValidationResults results = new ValidationResults(context); |
+ stopwatch.stop(); |
+ |
+ buffer.write('<h3>Validation Results</h3>'); |
+ buffer.write('<p>Re-analysis took '); |
+ buffer.write(stopwatch.elapsedMilliseconds); |
+ buffer.write(' ms</p>'); |
+ results.writeOn(buffer); |
+ } |
+ |
+ /** |
* Write the status of the diagnostic domain to the given [buffer]. |
*/ |
void _writeDiagnosticStatus(StringBuffer buffer) { |
@@ -1546,28 +1681,32 @@ class GetHandler { |
buffer.write('<h3>Timing</h3>'); |
- buffer.write('<p>'); |
- buffer.write('getDiagnostic (last call): $elapsedMs (ms)'); |
- buffer.write('<p>'); |
- buffer.write('getDiagnostic (rolling average): ' |
- '${_diagnosticCallAverage.value} (ms)'); |
- buffer.write('<p> '); |
+ buffer.write('<p>getDiagnostic (last call): '); |
+ buffer.write(elapsedMs); |
+ buffer.write(' (ms)</p>'); |
+ buffer.write('<p>getDiagnostic (rolling average): '); |
+ buffer.write(_diagnosticCallAverage.value); |
+ buffer.write(' (ms)</p> '); |
var json = response.toJson()[Response.RESULT]; |
List contexts = json['contexts']; |
+ contexts.sort((first, second) => first['name'].compareTo(second['name'])); |
for (var context in contexts) { |
- buffer.write('<p>'); |
- buffer.write('<h3>${context["name"]}</h3>'); |
- buffer.write('<p>'); |
- buffer.write('explicitFileCount: ${context["explicitFileCount"]}'); |
- buffer.write('<p>'); |
- buffer.write('implicitFileCount: ${context["implicitFileCount"]}'); |
- buffer.write('<p>'); |
- buffer.write('workItemQueueLength: ${context["workItemQueueLength"]}'); |
- buffer.write('<p>'); |
- buffer.write('workItemQueueLengthAverage: ' |
- '${context["workItemQueueLengthAverage"]}'); |
- buffer.write('<p> '); |
+ buffer.write('<p><h3>'); |
+ buffer.write(context['name']); |
+ buffer.write('</h3></p>'); |
+ buffer.write('<p>explicitFileCount: '); |
+ buffer.write(context['explicitFileCount']); |
+ buffer.write('</p>'); |
+ buffer.write('<p>implicitFileCount: '); |
+ buffer.write(context['implicitFileCount']); |
+ buffer.write('</p>'); |
+ buffer.write('<p>workItemQueueLength: '); |
+ buffer.write(context['workItemQueueLength']); |
+ buffer.write('</p>'); |
+ buffer.write('<p>workItemQueueLengthAverage: '); |
+ buffer.write(context['workItemQueueLengthAverage']); |
+ buffer.write('</p>'); |
} |
} |
@@ -1708,6 +1847,8 @@ class GetHandler { |
buffer.write( |
'h3 {background-color: #DDDDDD; margin-top: 0em; margin-bottom: 0em;}'); |
buffer.write('p {margin-top: 0.5em; margin-bottom: 0.5em;}'); |
+ buffer.write( |
+ 'p.commentary {margin-top: 1em; margin-bottom: 1em; margin-left: 2em; font-style: italic;}'); |
// response.write('span.error {text-decoration-line: underline; text-decoration-color: red; text-decoration-style: wavy;}'); |
buffer.write( |
'table.column {border: 0px solid black; width: 100%; table-layout: fixed;}'); |
@@ -1868,6 +2009,9 @@ class GetHandler { |
buffer.write(makeLink( |
COMMUNICATION_PERFORMANCE_PATH, {}, 'Communication performance')); |
buffer.write('</p>'); |
+ buffer.write('<p>'); |
+ buffer.write(makeLink(DIAGNOSTIC_PATH, {}, 'General diagnostics')); |
+ buffer.write('</p>'); |
}, (StringBuffer buffer) { |
_writeSubscriptionList(buffer, ServerService.VALUES, services); |
}); |