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

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

Issue 2338883003: Add a tool for viewing instrumentation logs (Closed)
Patch Set: Created 4 years, 3 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
Index: pkg/analysis_server/tool/instrumentation/server.dart
diff --git a/pkg/analysis_server/tool/instrumentation/server.dart b/pkg/analysis_server/tool/instrumentation/server.dart
new file mode 100644
index 0000000000000000000000000000000000000000..324244c9d3bb0d67bc1c189d89f7c16aef360578
--- /dev/null
+++ b/pkg/analysis_server/tool/instrumentation/server.dart
@@ -0,0 +1,236 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:collection';
+import 'dart:io';
+
+import 'log/log.dart';
+import 'page/log_page.dart';
+import 'page/stats_page.dart';
+import 'page/task_page.dart';
+
+/**
+ * An exception that is thrown when a request is received that cannot be
+ * handled.
+ */
+class UnknownRequest implements Exception {}
+
+/**
+ * A simple web server.
+ */
+class WebServer {
+ /**
+ * The path to the page containing a single page from the instrumentation log.
+ */
+ static final String logPath = '/log';
+
+ /**
+ * The path to the page containing statistics about the instrumentation log.
+ */
+ static final String statsPath = '/stats';
+
+ /**
+ * The path to the page containing statistics about the instrumentation log.
+ */
+ static final String taskPath = '/task';
+
+ /**
+ * The content type for HTML responses.
+ */
+ static final ContentType _htmlContent =
+ new ContentType("text", "html", charset: "utf-8");
+
+ /**
+ * The instrumentation log being served up.
+ */
+ final InstrumentationLog log;
+
+ /**
+ * Future that is completed with the HTTP server once it is running.
+ */
+ Future<HttpServer> _server;
+
+ /**
+ * Initialize a newly created server.
+ */
+ WebServer(this.log);
+
+ Map<String, String> getParameterMap(HttpRequest request) {
+ Map<String, String> parameterMap = new HashMap<String, String>();
+ String query = request.uri.query;
+ if (query != null && query.isNotEmpty) {
+ List<String> pairs = query.split('&');
+ for (String pair in pairs) {
+ List<String> parts = pair.split('=');
+ String value = parts[1].trim();
+ value = value.replaceAll('+', ' ');
+ parameterMap[parts[0].trim()] = value;
+ }
+ }
+ return parameterMap;
+ }
+
+ /**
+ * Return a table mapping the names of properties to the values of those
+ * properties that is extracted from the given HTTP [request].
+ */
+ Future<Map<String, String>> getValueMap(HttpRequest request) async {
+ StringBuffer buffer = new StringBuffer();
+ await request.forEach((List<int> element) {
+ for (int code in element) {
+ buffer.writeCharCode(code);
+ }
+ });
+ Map<String, String> valueMap = new HashMap<String, String>();
+ String parameters = buffer.toString();
+ if (parameters.isNotEmpty) {
+ List<String> pairs = parameters.split('&');
+ for (String pair in pairs) {
+ List<String> parts = pair.split('=');
+ String value = parts[1].trim();
+ value = value.replaceAll('+', ' ');
+ valueMap[parts[0].trim()] = value;
+ }
+ }
+ return valueMap;
+ }
+
+ /**
+ * Begin serving HTTP requests over the given [port].
+ */
+ void serveHttp(int port) {
+ _server = HttpServer.bind(InternetAddress.LOOPBACK_IP_V4, port);
+ _server.then(_handleServer).catchError((_) {/* Ignore errors. */});
+ }
+
+ /**
+ * Handle a GET [request] received by the HTTP server.
+ */
+ void _handleGetRequest(HttpRequest request) {
+ StringBuffer buffer = new StringBuffer();
+ try {
+ String path = request.uri.path;
+ if (path == logPath) {
+ _writeLogPage(request, buffer);
+ } else if (path == statsPath) {
+ _writeStatsPage(request, buffer);
+ } else if (path == taskPath) {
+ _writeTaskPage(request, buffer);
+ } else {
+ _returnUnknownRequest(request);
+ return;
+ }
+ } on UnknownRequest {
+ _returnUnknownRequest(request);
+ return;
+ } catch (exception, stackTrace) {
+ HttpResponse response = request.response;
+ response.statusCode = HttpStatus.OK;
+ response.headers.contentType = _htmlContent;
+ StringBuffer buffer = new StringBuffer();
+ buffer.write('<p><b>Exception while composing page:</b></p>');
+ buffer.write('<p>$exception</p>');
+ buffer.write('<p>');
+ _writeStackTrace(buffer, stackTrace);
+ buffer.write('</p>');
+ response.write(buffer.toString());
+ response.close();
+ return;
+ }
+
+ HttpResponse response = request.response;
+ response.statusCode = HttpStatus.OK;
+ response.headers.contentType = _htmlContent;
+ response.write(buffer.toString());
+ response.close();
+ }
+
+ /**
+ * Handle a POST [request] received by the HTTP server.
+ */
+ Future<Null> _handlePostRequest(HttpRequest request) async {
+ _returnUnknownRequest(request);
+ }
+
+ /**
+ * Attach a listener to a newly created HTTP server.
+ */
+ void _handleServer(HttpServer httpServer) {
+ httpServer.listen((HttpRequest request) {
+ String method = request.method;
+ if (method == 'GET') {
+ _handleGetRequest(request);
+ } else if (method == 'POST') {
+ _handlePostRequest(request);
+ } else {
+ _returnUnknownRequest(request);
+ }
+ });
+ }
+
+ /**
+ * Return an error in response to an unrecognized request received by the HTTP
+ * server.
+ */
+ void _returnUnknownRequest(HttpRequest request) {
+ HttpResponse response = request.response;
+ response.statusCode = HttpStatus.NOT_FOUND;
+ response.headers.contentType =
+ new ContentType("text", "html", charset: "utf-8");
+ response.write(
+ '<html><head></head><body><h3>Page not found: "${request.uri.path}".</h3></body></html>');
+ response.close();
+ }
+
+ void _writeLogPage(HttpRequest request, StringBuffer buffer) {
+ Map<String, String> parameterMap = getParameterMap(request);
+ String startIndex = parameterMap['start'];
+ LogPage page = new LogPage(log);
+ if (startIndex != null) {
+ page.pageStart = int.parse(startIndex);
+ } else {
+ page.pageStart = 0;
+ }
+ page.pageLength = 25;
+ page.writePage(buffer);
+ }
+
+ /**
+ * Write a representation of the given [stackTrace] to the given [sink].
+ */
+ void _writeStackTrace(StringSink sink, StackTrace stackTrace) {
+ if (stackTrace != null) {
+ String trace = stackTrace.toString().replaceAll('#', '<br>#');
+ if (trace.startsWith('<br>#')) {
+ trace = trace.substring(4);
+ }
+ sink.write('<p>');
+ sink.write(trace);
+ sink.write('</p>');
+ }
+ }
+
+ void _writeStatsPage(HttpRequest request, StringBuffer buffer) {
+ new StatsPage(log).writePage(buffer);
+ }
+
+ void _writeTaskPage(HttpRequest request, StringBuffer buffer) {
+ Map<String, String> parameterMap = getParameterMap(request);
+ String analysisStart = parameterMap['analysisStart'];
+ String start = parameterMap['start'];
+ TaskPage page = new TaskPage(log);
+ if (analysisStart == null) {
+ throw new UnknownRequest();
+ }
+ page.analysisStart = int.parse(analysisStart);
+ if (start != null) {
+ page.pageStart = int.parse(start);
+ } else {
+ page.pageStart = 0;
+ }
+ page.pageLength = 25;
+ page.writePage(buffer);
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698