|  | // Copyright (c) 2022, 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:convert'; | 
|  |  | 
|  | import 'package:analysis_server/src/analytics/percentile_calculator.dart'; | 
|  | import 'package:analysis_server/src/plugin/plugin_manager.dart'; | 
|  | import 'package:path/path.dart' as path; | 
|  |  | 
|  | /// Data about the plugins associated with the context roots. | 
|  | class PluginData { | 
|  | /// The number of times that plugin information has been recorded. | 
|  | int recordCount = 0; | 
|  |  | 
|  | /// A table mapping the ids of running plugins to the number of context roots | 
|  | /// associated with each of the plugins. | 
|  | Map<String, PercentileCalculator> usageCounts = {}; | 
|  |  | 
|  | /// Initialize a newly created holder of plugin data. | 
|  | PluginData(); | 
|  |  | 
|  | String get usageCountData { | 
|  | return json.encode({ | 
|  | 'recordCount': recordCount, | 
|  | 'rootCounts': _encodeUsageCounts(), | 
|  | }); | 
|  | } | 
|  |  | 
|  | /// Use the [pluginManager] to record data about the plugins that are | 
|  | /// currently running. | 
|  | void recordPlugins(PluginManager pluginManager) { | 
|  | recordCount++; | 
|  | var plugins = pluginManager.plugins; | 
|  | for (var i = 0; i < plugins.length; i++) { | 
|  | var info = plugins[i]; | 
|  | usageCounts | 
|  | .putIfAbsent(info.safePluginId, () => PercentileCalculator()) | 
|  | .addValue(info.contextRoots.length); | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Return an encoding of the [usageCounts]. | 
|  | Map<String, Object> _encodeUsageCounts() { | 
|  | var encoded = <String, Object>{}; | 
|  | for (var entry in usageCounts.entries) { | 
|  | encoded[entry.key] = entry.value.toJson(); | 
|  | } | 
|  | return encoded; | 
|  | } | 
|  | } | 
|  |  | 
|  | extension PluginInfoExtension on PluginInfo { | 
|  | /// Return an id for this plugin that doesn't contain any PII. | 
|  | /// | 
|  | /// If the plugin is installed in the pub cache and hosted on `pub.dev`, then | 
|  | /// the returned name will be the name and version of the containing package | 
|  | /// as listed on `pub.dev`. If not, then it might be an internal name so we | 
|  | /// default to 'unknown'. | 
|  | String get safePluginId { | 
|  | var components = path.split(pluginId); | 
|  | if (components.contains('.pub-cache')) { | 
|  | var index = components.lastIndexOf('analyzer_plugin'); | 
|  | if (index > 2 && | 
|  | components[index - 1] == 'tools' && | 
|  | components[index - 3] == 'pub.dev') { | 
|  | return components[index - 2]; | 
|  | } | 
|  | } | 
|  | return 'unknown'; | 
|  | } | 
|  | } |