Report plugin performance in analytics

Change-Id: I22e37031330e2d65aa1317965d1536932f5e6cc2
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/246764
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
diff --git a/pkg/analysis_server/lib/src/analytics/google_analytics_manager.dart b/pkg/analysis_server/lib/src/analytics/google_analytics_manager.dart
index 95b14ff..626004f 100644
--- a/pkg/analysis_server/lib/src/analytics/google_analytics_manager.dart
+++ b/pkg/analysis_server/lib/src/analytics/google_analytics_manager.dart
@@ -61,27 +61,10 @@
     if (sessionData == null) {
       return;
     }
-    // Send session data.
-    var endTime = DateTime.now().millisecondsSinceEpoch;
-    var duration = endTime - sessionData.startTime.millisecondsSinceEpoch;
-    analytics.sendEvent('language_server', 'session', parameters: {
-      'flags': sessionData.commandLineArguments,
-      'clientId': sessionData.clientId,
-      'sdkVersion': sessionData.sdkVersion,
-      'duration': duration.toString(),
-      'plugins': _pluginData.usageCountData,
-    });
-    // Send response data.
-    for (var data in _completedRequests.values) {
-      analytics.sendEvent('language_server', 'request', parameters: {
-        'latency': data.latencyTimes.toAnalyticsString(),
-        'name': data.method,
-        'duration': data.responseTimes.toAnalyticsString(),
-        // TODO(brianwilkerson) Report the latencies for each of the plugins,
-        //  probably as a map from plugin name to latency information.
-        'plugins': '',
-      });
-    }
+    _sendSessionData(sessionData);
+    _sendServerResponseTimes();
+    _sendPluginResponseTimes();
+
     analytics.waitForLastPing(timeout: Duration(milliseconds: 200)).then((_) {
       analytics.close();
     });
@@ -138,6 +121,44 @@
     var responseTime = sendTime.millisecondsSinceEpoch - startTime;
     requestData.responseTimes.addValue(responseTime);
   }
+
+  /// Send information about the response times of plugins.
+  void _sendPluginResponseTimes() {
+    var responseTimes = PluginManager.pluginResponseTimes;
+    for (var pluginEntry in responseTimes.entries) {
+      for (var responseEntry in pluginEntry.value.entries) {
+        analytics.sendEvent('language_server', 'pluginRequest', parameters: {
+          'pluginId': pluginEntry.key.pluginId,
+          'method': responseEntry.key,
+          'duration': responseEntry.value.toAnalyticsString(),
+        });
+      }
+    }
+  }
+
+  /// Send information about the response times of server.
+  void _sendServerResponseTimes() {
+    for (var data in _completedRequests.values) {
+      analytics.sendEvent('language_server', 'request', parameters: {
+        'latency': data.latencyTimes.toAnalyticsString(),
+        'method': data.method,
+        'duration': data.responseTimes.toAnalyticsString(),
+      });
+    }
+  }
+
+  /// Send information about the session.
+  void _sendSessionData(_SessionData sessionData) {
+    var endTime = DateTime.now().millisecondsSinceEpoch;
+    var duration = endTime - sessionData.startTime.millisecondsSinceEpoch;
+    analytics.sendEvent('language_server', 'session', parameters: {
+      'flags': sessionData.commandLineArguments,
+      'clientId': sessionData.clientId,
+      'sdkVersion': sessionData.sdkVersion,
+      'duration': duration.toString(),
+      'plugins': _pluginData.usageCountData,
+    });
+  }
 }
 
 /// Data about a request that was received and is being handled.
diff --git a/pkg/analysis_server/lib/src/plugin/plugin_manager.dart b/pkg/analysis_server/lib/src/plugin/plugin_manager.dart
index 7c4e7ef..9c89392 100644
--- a/pkg/analysis_server/lib/src/plugin/plugin_manager.dart
+++ b/pkg/analysis_server/lib/src/plugin/plugin_manager.dart
@@ -7,6 +7,7 @@
 import 'dart:convert';
 import 'dart:io' show Platform, Process;
 
+import 'package:analysis_server/src/analytics/percentile_calculator.dart';
 import 'package:analysis_server/src/plugin/notification_manager.dart';
 import 'package:analyzer/dart/analysis/context_root.dart' as analyzer;
 import 'package:analyzer/exception/exception.dart';
@@ -259,8 +260,8 @@
   /// A table, keyed by both a plugin and a request method, to a list of the
   /// times that it took the plugin to return a response to requests with the
   /// method.
-  static Map<PluginInfo, Map<String, List<int>>> pluginResponseTimes =
-      <PluginInfo, Map<String, List<int>>>{};
+  static Map<PluginInfo, Map<String, PercentileCalculator>>
+      pluginResponseTimes = <PluginInfo, Map<String, PercentileCalculator>>{};
 
   /// The console environment key used by the pub tool.
   static const String _pubEnvironmentKey = 'PUB_ENVIRONMENT';
@@ -792,9 +793,9 @@
   /// given [method] in the given [time].
   static void recordResponseTime(PluginInfo plugin, String method, int time) {
     pluginResponseTimes
-        .putIfAbsent(plugin, () => <String, List<int>>{})
-        .putIfAbsent(method, () => <int>[])
-        .add(time);
+        .putIfAbsent(plugin, () => <String, PercentileCalculator>{})
+        .putIfAbsent(method, () => PercentileCalculator())
+        .addValue(time);
   }
 
   /// Returns the environment value that should be used when running pub.
diff --git a/pkg/analysis_server/lib/src/status/diagnostics.dart b/pkg/analysis_server/lib/src/status/diagnostics.dart
index 10c6d66..cb3dc90 100644
--- a/pkg/analysis_server/lib/src/status/diagnostics.dart
+++ b/pkg/analysis_server/lib/src/status/diagnostics.dart
@@ -1134,7 +1134,7 @@
             var buffer = StringBuffer();
             buffer.write(requestName);
             buffer.write(' ');
-            buffer.write(data);
+            buffer.write(data.toAnalyticsString());
             p(buffer.toString());
           }
         }