mirror of
https://github.com/dart-lang/sdk
synced 2024-11-02 09:43:08 +00:00
Revert "Convert the AnalyticsManager to use the analytics package"
This reverts commit 0b8986902e
.
Reason for revert: Breaks downstream systems
Original change's description:
> Convert the AnalyticsManager to use the analytics package
>
> Change-Id: Id1822668e0ed7e12e88e990fa02247616b2e54e6
> Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/285400
> Reviewed-by: Elias Yishak <eliasyishak@google.com>
> Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
> Reviewed-by: Keerti Parthasarathy <keertip@google.com>
Change-Id: Ief9d611cf1259ae460c38fadb299f9e09d74d0f3
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/286242
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Commit-Queue: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Auto-Submit: Brian Wilkerson <brianwilkerson@google.com>
This commit is contained in:
parent
ca6e3499b8
commit
07c5db4d53
10 changed files with 274 additions and 253 deletions
|
@ -566,7 +566,7 @@ abstract class AnalysisServer {
|
|||
});
|
||||
|
||||
@mustCallSuper
|
||||
Future<void> shutdown() async {
|
||||
void shutdown() {
|
||||
// For now we record plugins only on shutdown. We might want to record them
|
||||
// every time the set of plugins changes, in which case we'll need to listen
|
||||
// to the `PluginManager.pluginsChanged` stream.
|
||||
|
@ -578,7 +578,7 @@ abstract class AnalysisServer {
|
|||
analyticsManager.createdAnalysisContexts(contextManager.analysisContexts);
|
||||
|
||||
pubPackageService.shutdown();
|
||||
await analyticsManager.shutdown();
|
||||
analyticsManager.shutdown();
|
||||
}
|
||||
|
||||
/// Return the path to the location of the byte store on disk, or `null` if
|
||||
|
|
|
@ -17,7 +17,7 @@ import 'package:analysis_server/src/protocol_server.dart';
|
|||
import 'package:analysis_server/src/status/pages.dart';
|
||||
import 'package:analyzer/dart/analysis/analysis_context.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:dash_analytics/dash_analytics.dart';
|
||||
import 'package:telemetry/telemetry.dart';
|
||||
|
||||
/// An interface for managing and reporting analytics.
|
||||
///
|
||||
|
@ -153,15 +153,21 @@ class AnalyticsManager {
|
|||
}
|
||||
|
||||
/// The server is shutting down. Report any accumulated analytics data.
|
||||
Future<void> shutdown() async {
|
||||
void shutdown() {
|
||||
final sessionData = _sessionData;
|
||||
if (sessionData == null) {
|
||||
return;
|
||||
}
|
||||
await _sendSessionData(sessionData);
|
||||
await _sendPeriodicData();
|
||||
_sendSessionData(sessionData);
|
||||
_sendServerResponseTimes();
|
||||
_sendPluginResponseTimes();
|
||||
_sendNotificationHandlingTimes();
|
||||
_sendLintUsageCounts();
|
||||
_sendSeverityAdjustments();
|
||||
|
||||
analytics.close();
|
||||
analytics.waitForLastPing(timeout: Duration(milliseconds: 200)).then((_) {
|
||||
analytics.close();
|
||||
});
|
||||
}
|
||||
|
||||
/// Record data from the given [params].
|
||||
|
@ -205,17 +211,20 @@ class AnalyticsManager {
|
|||
|
||||
/// Record that the server was started at the given [time], that it was passed
|
||||
/// the given command-line [arguments], that it was started by the client with
|
||||
/// the given [clientId] and [clientVersion].
|
||||
/// the given [clientId] and [clientVersion], and that it was invoked from an
|
||||
/// SDK with the given [sdkVersion].
|
||||
void startUp(
|
||||
{required DateTime time,
|
||||
required List<String> arguments,
|
||||
required String clientId,
|
||||
required String? clientVersion}) {
|
||||
required String? clientVersion,
|
||||
required String sdkVersion}) {
|
||||
_sessionData = SessionData(
|
||||
startTime: time,
|
||||
commandLineArguments: arguments.join(','),
|
||||
clientId: clientId,
|
||||
clientVersion: clientVersion ?? '');
|
||||
clientVersion: clientVersion ?? '',
|
||||
sdkVersion: sdkVersion);
|
||||
}
|
||||
|
||||
/// Return an HTML representation of the data that has been recorded.
|
||||
|
@ -256,6 +265,7 @@ class AnalyticsManager {
|
|||
li('duration: ${duration.toString()}');
|
||||
li('flags: ${sessionData.commandLineArguments}');
|
||||
li('parameters: ${sessionData.initializeParams}');
|
||||
li('sdkVersion: ${sessionData.sdkVersion}');
|
||||
li('plugins: ${_pluginData.usageCountData}');
|
||||
buffer.writeln('</ul>');
|
||||
|
||||
|
@ -351,21 +361,18 @@ class AnalyticsManager {
|
|||
requestData.responseTimes.addValue(responseTime);
|
||||
}
|
||||
|
||||
/// Send information about the number of times each lint is enabled in an
|
||||
/// analysis options file.
|
||||
Future<void> _sendLintUsageCounts() async {
|
||||
void _sendLintUsageCounts() {
|
||||
if (_lintUsageCounts.isNotEmpty) {
|
||||
await analytics
|
||||
.sendEvent(eventName: DashEvent.lintUsageCounts, eventData: {
|
||||
analytics.sendEvent('language_server', 'lintUsageCounts', parameters: {
|
||||
'usageCounts': json.encode(_lintUsageCounts),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// Send information about the notifications handled by the server.
|
||||
Future<void> _sendNotificationHandlingTimes() async {
|
||||
void _sendNotificationHandlingTimes() {
|
||||
for (var data in _completedNotifications.values) {
|
||||
await analytics.sendEvent(eventName: DashEvent.notification, eventData: {
|
||||
analytics.sendEvent('language_server', 'notification', parameters: {
|
||||
'latency': data.latencyTimes.toAnalyticsString(),
|
||||
'method': data.method,
|
||||
'duration': data.handlingTimes.toAnalyticsString(),
|
||||
|
@ -373,23 +380,12 @@ class AnalyticsManager {
|
|||
}
|
||||
}
|
||||
|
||||
/// Send the information that is sent periodically, which is everything other
|
||||
/// than the session data.
|
||||
Future<void> _sendPeriodicData() async {
|
||||
await _sendServerResponseTimes();
|
||||
await _sendPluginResponseTimes();
|
||||
await _sendNotificationHandlingTimes();
|
||||
await _sendLintUsageCounts();
|
||||
await _sendSeverityAdjustments();
|
||||
}
|
||||
|
||||
/// Send information about the response times of plugins.
|
||||
Future<void> _sendPluginResponseTimes() async {
|
||||
void _sendPluginResponseTimes() {
|
||||
var responseTimes = PluginManager.pluginResponseTimes;
|
||||
for (var pluginEntry in responseTimes.entries) {
|
||||
for (var responseEntry in pluginEntry.value.entries) {
|
||||
await analytics
|
||||
.sendEvent(eventName: DashEvent.pluginRequest, eventData: {
|
||||
analytics.sendEvent('language_server', 'pluginRequest', parameters: {
|
||||
'pluginId': pluginEntry.key.pluginId,
|
||||
'method': responseEntry.key,
|
||||
'duration': responseEntry.value.toAnalyticsString(),
|
||||
|
@ -399,9 +395,9 @@ class AnalyticsManager {
|
|||
}
|
||||
|
||||
/// Send information about the response times of server.
|
||||
Future<void> _sendServerResponseTimes() async {
|
||||
void _sendServerResponseTimes() {
|
||||
for (var data in _completedRequests.values) {
|
||||
await analytics.sendEvent(eventName: DashEvent.request, eventData: {
|
||||
analytics.sendEvent('language_server', 'request', parameters: {
|
||||
'latency': data.latencyTimes.toAnalyticsString(),
|
||||
'method': data.method,
|
||||
'duration': data.responseTimes.toAnalyticsString(),
|
||||
|
@ -414,25 +410,24 @@ class AnalyticsManager {
|
|||
}
|
||||
|
||||
/// Send information about the session.
|
||||
Future<void> _sendSessionData(SessionData sessionData) async {
|
||||
void _sendSessionData(SessionData sessionData) {
|
||||
var endTime = DateTime.now().millisecondsSinceEpoch;
|
||||
var duration = endTime - sessionData.startTime.millisecondsSinceEpoch;
|
||||
await analytics.sendEvent(eventName: DashEvent.session, eventData: {
|
||||
analytics.sendEvent('language_server', 'session', parameters: {
|
||||
'flags': sessionData.commandLineArguments,
|
||||
'parameters': sessionData.initializeParams,
|
||||
'clientId': sessionData.clientId,
|
||||
'clientVersion': sessionData.clientVersion,
|
||||
'sdkVersion': sessionData.sdkVersion,
|
||||
'duration': duration.toString(),
|
||||
'plugins': _pluginData.usageCountData,
|
||||
});
|
||||
}
|
||||
|
||||
/// Send information about the number of times that the severity of a
|
||||
/// diagnostic is changed in an analysis options file.
|
||||
Future<void> _sendSeverityAdjustments() async {
|
||||
void _sendSeverityAdjustments() {
|
||||
if (_severityAdjustments.isNotEmpty) {
|
||||
await analytics
|
||||
.sendEvent(eventName: DashEvent.severityAdjustments, eventData: {
|
||||
analytics
|
||||
.sendEvent('language_server', 'severityAdjustments', parameters: {
|
||||
'adjustmentCounts': json.encode(_severityAdjustments),
|
||||
});
|
||||
}
|
||||
|
|
|
@ -2,30 +2,29 @@
|
|||
// 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 'package:dash_analytics/dash_analytics.dart';
|
||||
import 'package:dash_analytics/src/config_handler.dart';
|
||||
import 'package:http/src/response.dart';
|
||||
import 'package:telemetry/telemetry.dart';
|
||||
|
||||
/// An implementation of [Analytics] that's appropriate to use when running
|
||||
/// tests.
|
||||
// TODO(brianwilkerson) Remove this class when it's easier to create a test
|
||||
// version of the `Analytics` class.
|
||||
class NoopAnalytics implements Analytics {
|
||||
/// An implementation of [Analytics] that's appropriate to use when analytics
|
||||
/// have not been enabled.
|
||||
class NoopAnalytics extends Analytics {
|
||||
@override
|
||||
Map<String, ToolInfo> get parsedTools => throw UnimplementedError();
|
||||
String? get applicationName => null;
|
||||
|
||||
@override
|
||||
bool get shouldShowMessage => false;
|
||||
String? get applicationVersion => null;
|
||||
|
||||
@override
|
||||
bool get telemetryEnabled => false;
|
||||
bool get enabled => false;
|
||||
|
||||
@override
|
||||
String get toolsMessage => throw UnimplementedError();
|
||||
set enabled(bool value) {
|
||||
// Ignored
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, Map<String, Object?>> get userPropertyMap =>
|
||||
throw UnimplementedError();
|
||||
Stream<Map<String, dynamic>> get onSend async* {
|
||||
// Ignored
|
||||
}
|
||||
|
||||
@override
|
||||
void close() {
|
||||
|
@ -33,20 +32,50 @@ class NoopAnalytics implements Analytics {
|
|||
}
|
||||
|
||||
@override
|
||||
LogFileStats? logFileStats() {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Response>? sendEvent(
|
||||
{required DashEvent eventName,
|
||||
Map<String, Object?> eventData = const {}}) {
|
||||
getSessionValue(String param) {
|
||||
// Ignored
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> setTelemetry(bool reportingBool) {
|
||||
dynamic noSuchMethod(Invocation invocation) {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future sendEvent(String category, String action,
|
||||
{String? label, int? value, Map<String, String>? parameters}) async {
|
||||
// Ignored
|
||||
}
|
||||
|
||||
@override
|
||||
Future sendException(String description, {bool? fatal}) async {
|
||||
// Ignored
|
||||
}
|
||||
|
||||
@override
|
||||
Future sendScreenView(String viewName,
|
||||
{Map<String, String>? parameters}) async {
|
||||
// Ignored
|
||||
}
|
||||
|
||||
@override
|
||||
Future sendSocial(String network, String action, String target) async {
|
||||
// Ignored
|
||||
}
|
||||
|
||||
@override
|
||||
Future sendTiming(String variableName, int time,
|
||||
{String? category, String? label}) async {
|
||||
// Ignored
|
||||
}
|
||||
|
||||
@override
|
||||
void setSessionValue(String param, value) {
|
||||
// Ignored
|
||||
}
|
||||
|
||||
@override
|
||||
Future waitForLastPing({Duration? timeout}) async {
|
||||
// Ignored
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,10 +20,14 @@ class SessionData {
|
|||
/// no version information was provided.
|
||||
final String clientVersion;
|
||||
|
||||
/// The version of the SDK from which the server was started.
|
||||
final String sdkVersion;
|
||||
|
||||
/// Initialize a newly created data holder.
|
||||
SessionData(
|
||||
{required this.startTime,
|
||||
required this.commandLineArguments,
|
||||
required this.clientId,
|
||||
required this.clientVersion});
|
||||
required this.clientVersion,
|
||||
required this.sdkVersion});
|
||||
}
|
||||
|
|
|
@ -695,8 +695,8 @@ class LegacyAnalysisServer extends AnalysisServer {
|
|||
}
|
||||
|
||||
@override
|
||||
Future<void> shutdown() async {
|
||||
await super.shutdown();
|
||||
Future<void> shutdown() {
|
||||
super.shutdown();
|
||||
|
||||
pubApi.close();
|
||||
|
||||
|
@ -704,21 +704,21 @@ class LegacyAnalysisServer extends AnalysisServer {
|
|||
// analyticsManager is being correctly initialized.
|
||||
var analytics = options.analytics;
|
||||
if (analytics != null) {
|
||||
unawaited(analytics
|
||||
.waitForLastPing(timeout: Duration(milliseconds: 200))
|
||||
.then((_) {
|
||||
analytics.waitForLastPing(timeout: Duration(milliseconds: 200)).then((_) {
|
||||
analytics.close();
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
detachableFileSystemManager?.dispose();
|
||||
|
||||
// Defer closing the channel and shutting down the instrumentation server so
|
||||
// that the shutdown response can be sent and logged.
|
||||
unawaited(Future(() {
|
||||
Future(() {
|
||||
instrumentationService.shutdown();
|
||||
channel.close();
|
||||
}));
|
||||
});
|
||||
|
||||
return Future.value();
|
||||
}
|
||||
|
||||
/// Implementation for `analysis.updateContent`.
|
||||
|
|
|
@ -368,8 +368,6 @@ class LspAnalysisServer extends AnalysisServer {
|
|||
|
||||
performanceAfterStartup = ServerPerformance();
|
||||
performance = performanceAfterStartup!;
|
||||
|
||||
_checkAnalytics();
|
||||
}
|
||||
|
||||
/// Handles a response from the client by invoking the completer that the
|
||||
|
@ -685,7 +683,7 @@ class LspAnalysisServer extends AnalysisServer {
|
|||
logErrorToClient(
|
||||
'$message\n\n${error.message}\n\n${error.code}\n\n${error.data}');
|
||||
|
||||
unawaited(shutdown());
|
||||
shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -846,17 +844,19 @@ class LspAnalysisServer extends AnalysisServer {
|
|||
}
|
||||
|
||||
@override
|
||||
Future<void> shutdown() async {
|
||||
await super.shutdown();
|
||||
Future<void> shutdown() {
|
||||
super.shutdown();
|
||||
|
||||
detachableFileSystemManager?.dispose();
|
||||
|
||||
// Defer closing the channel so that the shutdown response can be sent and
|
||||
// logged.
|
||||
unawaited(Future(() {
|
||||
Future(() {
|
||||
channel.close();
|
||||
}));
|
||||
unawaited(_pluginChangeSubscription?.cancel());
|
||||
});
|
||||
_pluginChangeSubscription?.cancel();
|
||||
|
||||
return Future.value();
|
||||
}
|
||||
|
||||
/// There was an error related to the socket from which messages are being
|
||||
|
@ -896,20 +896,6 @@ class LspAnalysisServer extends AnalysisServer {
|
|||
notifyFlutterWidgetDescriptions(path);
|
||||
}
|
||||
|
||||
/// Display a message that will allow us to enable analytics on the next run.
|
||||
void _checkAnalytics() {
|
||||
var dashAnalytics = analyticsManager.analytics;
|
||||
// The order of the conditions below is important. We need to check whether
|
||||
// the client supports `showMessageRequest` before asking whether we need to
|
||||
// show the message because the `Analytics` instance assumes that if
|
||||
// `shouldShowMessage` returns `true` then the message will be shown.
|
||||
if (_clientCapabilities!.supportsShowMessageRequest &&
|
||||
dashAnalytics.shouldShowMessage) {
|
||||
unawaited(
|
||||
showUserPrompt(MessageType.Info, dashAnalytics.toolsMessage, ['Ok']));
|
||||
}
|
||||
}
|
||||
|
||||
/// Computes analysis roots for a set of open files.
|
||||
///
|
||||
/// This is used when there are no workspace folders open directly.
|
||||
|
|
|
@ -182,13 +182,13 @@ class Driver implements ServerStarter {
|
|||
var sdkConfig = SdkConfiguration.readFromSdk();
|
||||
analysisServerOptions.configurationOverrides = sdkConfig;
|
||||
|
||||
// Legacy Analytics
|
||||
// Analytics
|
||||
var disableAnalyticsForSession = results[SUPPRESS_ANALYTICS_FLAG] as bool;
|
||||
if (results.wasParsed(TRAIN_USING)) {
|
||||
disableAnalyticsForSession = true;
|
||||
}
|
||||
|
||||
// Use sdkConfig to optionally override legacy analytics settings.
|
||||
// Use sdkConfig to optionally override analytics settings.
|
||||
final analyticsId = sdkConfig.analyticsId ?? 'UA-26406144-29';
|
||||
final forceAnalyticsEnabled = sdkConfig.analyticsForceEnabled == true;
|
||||
var analytics = telemetry.createAnalyticsInstance(
|
||||
|
@ -204,6 +204,7 @@ class Driver implements ServerStarter {
|
|||
if (analysisServerOptions.clientVersion != null) {
|
||||
analytics.setSessionValue('cd1', analysisServerOptions.clientVersion);
|
||||
}
|
||||
var analyticsManager = AnalyticsManager(NoopAnalytics());
|
||||
|
||||
bool shouldSendCallback() {
|
||||
// Check sdkConfig to optionally force reporting on.
|
||||
|
@ -254,26 +255,15 @@ class Driver implements ServerStarter {
|
|||
// can't be re-used, but the SDK is needed to create a package map provider
|
||||
// in the case where we need to run `pub` in order to get the package map.
|
||||
var defaultSdk = _createDefaultSdk(defaultSdkPath);
|
||||
|
||||
// Create the analytics manager.
|
||||
// TODO(brianwilkerson) Add support for finding the version of the Flutter
|
||||
// SDK, or `null` if we're not in a Flutter SDK.
|
||||
// TODO(brianwilkerson) Delete the line below and uncomment the 3 lines
|
||||
// below it when we have (a) fixed the `dart analyze` and `dart fix` tests
|
||||
// so that they don't send events and (b) implemented a way for users to
|
||||
// disable analytics.
|
||||
var analyticsManager = AnalyticsManager(NoopAnalytics());
|
||||
// var analyticsManager = AnalyticsManager(Analytics(
|
||||
// tool: DashTool.languageServer,
|
||||
// dartVersion: defaultSdk.sdkVersion,
|
||||
// flutterVersion: null));
|
||||
|
||||
//
|
||||
// Record the start of the session.
|
||||
//
|
||||
analyticsManager.startUp(
|
||||
time: sessionStartTime,
|
||||
arguments: _getArgumentsForAnalytics(results),
|
||||
clientId: clientId,
|
||||
clientVersion: analysisServerOptions.clientVersion);
|
||||
clientVersion: analysisServerOptions.clientVersion,
|
||||
sdkVersion: defaultSdk.sdkVersion);
|
||||
//
|
||||
// Initialize the instrumentation service.
|
||||
//
|
||||
|
|
|
@ -10,6 +10,7 @@ import 'package:analysis_server/protocol/protocol_constants.dart'
|
|||
show PROTOCOL_VERSION;
|
||||
import 'package:analysis_server/protocol/protocol_generated.dart';
|
||||
import 'package:analysis_server/src/analysis_server.dart';
|
||||
import 'package:analysis_server/src/analytics/noop_analytics.dart';
|
||||
import 'package:analysis_server/src/legacy_analysis_server.dart';
|
||||
import 'package:analysis_server/src/lsp/lsp_analysis_server.dart'
|
||||
show LspAnalysisServer;
|
||||
|
@ -159,44 +160,39 @@ String writeOption(String name, dynamic value) {
|
|||
return '$name: <code>$value</code><br> ';
|
||||
}
|
||||
|
||||
// TODO(brianwilkerson) This page is disabled for production until we determine
|
||||
// whether we want to display some information to the user and if so what
|
||||
// information we want to display.
|
||||
//
|
||||
// class AnalyticsPage extends DiagnosticPageWithNav {
|
||||
// AnalyticsPage(DiagnosticsSite site)
|
||||
// : super(site, 'analytics', 'Analytics',
|
||||
// description: 'Analytics gathered by the analysis server.');
|
||||
//
|
||||
// @override
|
||||
// String? get navDetail => null;
|
||||
//
|
||||
// @override
|
||||
// Future generateContent(Map<String, String> params) async {
|
||||
// var manager = server.analyticsManager;
|
||||
// //
|
||||
// // Display the standard header.
|
||||
// //
|
||||
// if (!manager.analytics.telemetryEnabled) {
|
||||
// p('Analytics reporting disabled. In order to enable it, run:');
|
||||
// p(' <code>dart --enable-analytics</code>');
|
||||
// p('If analytics had been enabled, the information below would have been '
|
||||
// 'reported.');
|
||||
// } else {
|
||||
// p('The Dart tool uses Google Analytics to report feature usage '
|
||||
// 'statistics and to send basic crash reports. This data is used to '
|
||||
// 'help improve the Dart platform and tools over time.');
|
||||
// p('To disable reporting of analytics, run:');
|
||||
// p(' <code>dart --disable-analytics</code>');
|
||||
// p('The information below will be reported the next time analytics are '
|
||||
// 'sent.');
|
||||
// }
|
||||
// //
|
||||
// // Display the analytics data that has been gathered.
|
||||
// //
|
||||
// manager.toHtml(buf);
|
||||
// }
|
||||
// }
|
||||
class AnalyticsPage extends DiagnosticPageWithNav {
|
||||
AnalyticsPage(DiagnosticsSite site)
|
||||
: super(site, 'analytics', 'Analytics',
|
||||
description: 'Analytics gathered by the analysis server.');
|
||||
|
||||
@override
|
||||
String? get navDetail => null;
|
||||
|
||||
@override
|
||||
Future generateContent(Map<String, String> params) async {
|
||||
var manager = server.analyticsManager;
|
||||
//
|
||||
// Display the standard header.
|
||||
//
|
||||
if (manager.analytics is NoopAnalytics) {
|
||||
p('Analytics reporting disabled. In order to enable it, run:');
|
||||
p(' <code>dart --enable-analytics</code>');
|
||||
p('If analytics had been enabled, the information below would be '
|
||||
'reported on shutdown.');
|
||||
} else {
|
||||
p('The Dart tool uses Google Analytics to report feature usage '
|
||||
'statistics and to send basic crash reports. This data is used to '
|
||||
'help improve the Dart platform and tools over time.');
|
||||
p('To disable reporting of analytics, run:');
|
||||
p(' <code>dart --disable-analytics</code>');
|
||||
p('The information below will be reported on shutdown.');
|
||||
}
|
||||
//
|
||||
// Display the analytics data that has been gathered.
|
||||
//
|
||||
manager.toHtml(buf);
|
||||
}
|
||||
}
|
||||
|
||||
class AstPage extends DiagnosticPageWithNav {
|
||||
String? _description;
|
||||
|
|
|
@ -15,7 +15,6 @@ dependencies:
|
|||
convert: any
|
||||
crypto: any
|
||||
dart_style: any
|
||||
dash_analytics: any
|
||||
http: any
|
||||
linter: any
|
||||
meta: any
|
||||
|
|
|
@ -15,10 +15,8 @@ import 'package:analyzer/dart/analysis/context_root.dart' as analyzer;
|
|||
import 'package:analyzer/file_system/file_system.dart';
|
||||
import 'package:analyzer/src/test_utilities/mock_sdk.dart';
|
||||
import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
|
||||
import 'package:dash_analytics/dash_analytics.dart';
|
||||
import 'package:dash_analytics/src/config_handler.dart';
|
||||
import 'package:http/src/response.dart' as http;
|
||||
import 'package:linter/src/rules.dart';
|
||||
import 'package:telemetry/telemetry.dart';
|
||||
import 'package:test/test.dart';
|
||||
import 'package:test_reflective_loader/test_reflective_loader.dart';
|
||||
|
||||
|
@ -37,7 +35,7 @@ class AnalyticsManagerTest with ResourceProviderMixin {
|
|||
|
||||
String get testPackageRootPath => testPackageRoot.path;
|
||||
|
||||
Future<void> test_createAnalysisContexts_lints() async {
|
||||
void test_createAnalysisContexts_lints() {
|
||||
_createAnalysisOptionsFile(lints: [
|
||||
'avoid_dynamic_calls',
|
||||
'await_only_futures',
|
||||
|
@ -46,17 +44,17 @@ class AnalyticsManagerTest with ResourceProviderMixin {
|
|||
var collection = _createContexts();
|
||||
_defaultStartup();
|
||||
manager.createdAnalysisContexts(collection.contexts);
|
||||
await manager.shutdown();
|
||||
manager.shutdown();
|
||||
analytics.assertEvents([
|
||||
_ExpectedEvent.session(),
|
||||
_ExpectedEvent.lintUsageCounts(eventData: {
|
||||
_ExpectedEvent.lintUsageCounts(parameters: {
|
||||
'usageCounts':
|
||||
'{"avoid_dynamic_calls":1,"await_only_futures":1,"unawaited_futures":1}',
|
||||
}),
|
||||
]);
|
||||
}
|
||||
|
||||
Future<void> test_createAnalysisContexts_severityAdjustments() async {
|
||||
void test_createAnalysisContexts_severityAdjustments() {
|
||||
_createAnalysisOptionsFile(errors: {
|
||||
'avoid_dynamic_calls': 'error',
|
||||
'await_only_futures': 'ignore',
|
||||
|
@ -64,25 +62,25 @@ class AnalyticsManagerTest with ResourceProviderMixin {
|
|||
var collection = _createContexts();
|
||||
_defaultStartup();
|
||||
manager.createdAnalysisContexts(collection.contexts);
|
||||
await manager.shutdown();
|
||||
manager.shutdown();
|
||||
analytics.assertEvents([
|
||||
_ExpectedEvent.session(),
|
||||
_ExpectedEvent.severityAdjustments(eventData: {
|
||||
_ExpectedEvent.severityAdjustments(parameters: {
|
||||
'adjustmentCounts':
|
||||
'{"AVOID_DYNAMIC_CALLS":{"ERROR":1},"AWAIT_ONLY_FUTURES":{"ignore":1}}',
|
||||
}),
|
||||
]);
|
||||
}
|
||||
|
||||
Future<void> test_plugin_request() async {
|
||||
void test_plugin_request() {
|
||||
_defaultStartup();
|
||||
PluginManager.pluginResponseTimes[_MockPluginInfo('a')] = {
|
||||
'analysis.getNavigation': PercentileCalculator(),
|
||||
};
|
||||
await manager.shutdown();
|
||||
manager.shutdown();
|
||||
analytics.assertEvents([
|
||||
_ExpectedEvent.session(),
|
||||
_ExpectedEvent.pluginRequest(eventData: {
|
||||
_ExpectedEvent.pluginRequest(parameters: {
|
||||
'pluginId': 'a',
|
||||
'method': 'analysis.getNavigation',
|
||||
'duration': _IsPercentiles(),
|
||||
|
@ -91,7 +89,7 @@ class AnalyticsManagerTest with ResourceProviderMixin {
|
|||
PluginManager.pluginResponseTimes.clear();
|
||||
}
|
||||
|
||||
Future<void> test_server_notification() async {
|
||||
void test_server_notification() {
|
||||
_defaultStartup();
|
||||
manager.handledNotificationMessage(
|
||||
notification: NotificationMessage(
|
||||
|
@ -100,10 +98,10 @@ class AnalyticsManagerTest with ResourceProviderMixin {
|
|||
method: Method.workspace_didCreateFiles),
|
||||
startTime: _now(),
|
||||
endTime: _now());
|
||||
await manager.shutdown();
|
||||
manager.shutdown();
|
||||
analytics.assertEvents([
|
||||
_ExpectedEvent.session(),
|
||||
_ExpectedEvent.notification(eventData: {
|
||||
_ExpectedEvent.notification(parameters: {
|
||||
'latency': _IsPercentiles(),
|
||||
'method': Method.workspace_didCreateFiles.toString(),
|
||||
'duration': _IsPercentiles(),
|
||||
|
@ -111,7 +109,7 @@ class AnalyticsManagerTest with ResourceProviderMixin {
|
|||
]);
|
||||
}
|
||||
|
||||
Future<void> test_server_request_analysisDidChangeWorkspaceFolders() async {
|
||||
void test_server_request_analysisDidChangeWorkspaceFolders() {
|
||||
_defaultStartup();
|
||||
var params = DidChangeWorkspaceFoldersParams(
|
||||
event: WorkspaceFoldersChangeEvent(added: [], removed: []));
|
||||
|
@ -125,10 +123,10 @@ class AnalyticsManagerTest with ResourceProviderMixin {
|
|||
.changedWorkspaceFolders(added: ['a', 'b', 'c'], removed: ['d', 'e']);
|
||||
manager.sentResponseMessage(
|
||||
response: ResponseMessage(jsonrpc: '', id: Either2.t1(1)));
|
||||
await manager.shutdown();
|
||||
manager.shutdown();
|
||||
analytics.assertEvents([
|
||||
_ExpectedEvent.session(),
|
||||
_ExpectedEvent.request(eventData: {
|
||||
_ExpectedEvent.request(parameters: {
|
||||
'latency': _IsPercentiles(),
|
||||
'method': Method.workspace_didChangeWorkspaceFolders.toString(),
|
||||
'duration': _IsPercentiles(),
|
||||
|
@ -140,7 +138,7 @@ class AnalyticsManagerTest with ResourceProviderMixin {
|
|||
]);
|
||||
}
|
||||
|
||||
Future<void> test_server_request_analysisSetAnalysisRoots() async {
|
||||
void test_server_request_analysisSetAnalysisRoots() {
|
||||
_defaultStartup();
|
||||
var params = AnalysisSetAnalysisRootsParams(['a', 'b', 'c'], ['d', 'e']);
|
||||
var request =
|
||||
|
@ -148,10 +146,10 @@ class AnalyticsManagerTest with ResourceProviderMixin {
|
|||
manager.startedRequest(request: request, startTime: _now());
|
||||
manager.startedSetAnalysisRoots(params);
|
||||
manager.sentResponse(response: Response('1'));
|
||||
await manager.shutdown();
|
||||
manager.shutdown();
|
||||
analytics.assertEvents([
|
||||
_ExpectedEvent.session(),
|
||||
_ExpectedEvent.request(eventData: {
|
||||
_ExpectedEvent.request(parameters: {
|
||||
'latency': _IsPercentiles(),
|
||||
'method': ANALYSIS_REQUEST_SET_ANALYSIS_ROOTS,
|
||||
'duration': _IsPercentiles(),
|
||||
|
@ -163,7 +161,7 @@ class AnalyticsManagerTest with ResourceProviderMixin {
|
|||
]);
|
||||
}
|
||||
|
||||
Future<void> test_server_request_analysisSetPriorityFiles() async {
|
||||
void test_server_request_analysisSetPriorityFiles() {
|
||||
_defaultStartup();
|
||||
var params = AnalysisSetPriorityFilesParams(['a']);
|
||||
var request =
|
||||
|
@ -171,10 +169,10 @@ class AnalyticsManagerTest with ResourceProviderMixin {
|
|||
manager.startedRequest(request: request, startTime: _now());
|
||||
manager.startedSetPriorityFiles(params);
|
||||
manager.sentResponse(response: Response('1'));
|
||||
await manager.shutdown();
|
||||
manager.shutdown();
|
||||
analytics.assertEvents([
|
||||
_ExpectedEvent.session(),
|
||||
_ExpectedEvent.request(eventData: {
|
||||
_ExpectedEvent.request(parameters: {
|
||||
'latency': _IsPercentiles(),
|
||||
'method': ANALYSIS_REQUEST_SET_PRIORITY_FILES,
|
||||
'duration': _IsPercentiles(),
|
||||
|
@ -184,7 +182,7 @@ class AnalyticsManagerTest with ResourceProviderMixin {
|
|||
]);
|
||||
}
|
||||
|
||||
Future<void> test_server_request_editGetRefactoring() async {
|
||||
void test_server_request_editGetRefactoring() {
|
||||
_defaultStartup();
|
||||
var params =
|
||||
EditGetRefactoringParams(RefactoringKind.RENAME, '', 0, 0, true);
|
||||
|
@ -192,10 +190,10 @@ class AnalyticsManagerTest with ResourceProviderMixin {
|
|||
manager.startedRequest(request: request, startTime: _now());
|
||||
manager.startedGetRefactoring(params);
|
||||
manager.sentResponse(response: Response('1'));
|
||||
await manager.shutdown();
|
||||
manager.shutdown();
|
||||
analytics.assertEvents([
|
||||
_ExpectedEvent.session(),
|
||||
_ExpectedEvent.request(eventData: {
|
||||
_ExpectedEvent.request(parameters: {
|
||||
'latency': _IsPercentiles(),
|
||||
'method': EDIT_REQUEST_GET_REFACTORING,
|
||||
'duration': _IsPercentiles(),
|
||||
|
@ -204,7 +202,7 @@ class AnalyticsManagerTest with ResourceProviderMixin {
|
|||
]);
|
||||
}
|
||||
|
||||
Future<void> test_server_request_initialize() async {
|
||||
void test_server_request_initialize() {
|
||||
_defaultStartup();
|
||||
var params = InitializeParams(
|
||||
capabilities: ClientCapabilities(),
|
||||
|
@ -214,16 +212,16 @@ class AnalyticsManagerTest with ResourceProviderMixin {
|
|||
'onlyAnalyzeProjectsWithOpenFiles': true,
|
||||
});
|
||||
manager.initialize(params);
|
||||
await manager.shutdown();
|
||||
manager.shutdown();
|
||||
analytics.assertEvents([
|
||||
_ExpectedEvent.session(eventData: {
|
||||
_ExpectedEvent.session(parameters: {
|
||||
'parameters':
|
||||
'closingLabels,onlyAnalyzeProjectsWithOpenFiles,suggestFromUnimportedLibraries',
|
||||
}),
|
||||
]);
|
||||
}
|
||||
|
||||
Future<void> test_server_request_initialized() async {
|
||||
void test_server_request_initialized() {
|
||||
_defaultStartup();
|
||||
var params = InitializedParams();
|
||||
var request = RequestMessage(
|
||||
|
@ -235,10 +233,10 @@ class AnalyticsManagerTest with ResourceProviderMixin {
|
|||
manager.initialized(openWorkspacePaths: ['a', 'b', 'c']);
|
||||
manager.sentResponseMessage(
|
||||
response: ResponseMessage(jsonrpc: '', id: Either2.t1(1)));
|
||||
await manager.shutdown();
|
||||
manager.shutdown();
|
||||
analytics.assertEvents([
|
||||
_ExpectedEvent.session(),
|
||||
_ExpectedEvent.request(eventData: {
|
||||
_ExpectedEvent.request(parameters: {
|
||||
'latency': _IsPercentiles(),
|
||||
'method': Method.initialized.toString(),
|
||||
'duration': _IsPercentiles(),
|
||||
|
@ -248,15 +246,15 @@ class AnalyticsManagerTest with ResourceProviderMixin {
|
|||
]);
|
||||
}
|
||||
|
||||
Future<void> test_server_request_noAdditional() async {
|
||||
void test_server_request_noAdditional() {
|
||||
_defaultStartup();
|
||||
manager.startedRequest(
|
||||
request: Request('1', SERVER_REQUEST_SHUTDOWN), startTime: _now());
|
||||
manager.sentResponse(response: Response('1'));
|
||||
await manager.shutdown();
|
||||
manager.shutdown();
|
||||
analytics.assertEvents([
|
||||
_ExpectedEvent.session(),
|
||||
_ExpectedEvent.request(eventData: {
|
||||
_ExpectedEvent.request(parameters: {
|
||||
'latency': _IsPercentiles(),
|
||||
'method': SERVER_REQUEST_SHUTDOWN,
|
||||
'duration': _IsPercentiles(),
|
||||
|
@ -264,7 +262,7 @@ class AnalyticsManagerTest with ResourceProviderMixin {
|
|||
]);
|
||||
}
|
||||
|
||||
Future<void> test_server_request_workspaceExecuteCommand() async {
|
||||
void test_server_request_workspaceExecuteCommand() {
|
||||
_defaultStartup();
|
||||
var params = ExecuteCommandParams(command: 'doIt');
|
||||
var request = RequestMessage(
|
||||
|
@ -277,10 +275,10 @@ class AnalyticsManagerTest with ResourceProviderMixin {
|
|||
manager.executedCommand('doIt');
|
||||
manager.sentResponseMessage(
|
||||
response: ResponseMessage(jsonrpc: '', id: Either2.t1(1)));
|
||||
await manager.shutdown();
|
||||
manager.shutdown();
|
||||
analytics.assertEvents([
|
||||
_ExpectedEvent.session(),
|
||||
_ExpectedEvent.request(eventData: {
|
||||
_ExpectedEvent.request(parameters: {
|
||||
'latency': _IsPercentiles(),
|
||||
'method': Method.workspace_executeCommand.toString(),
|
||||
'duration': _IsPercentiles(),
|
||||
|
@ -289,62 +287,68 @@ class AnalyticsManagerTest with ResourceProviderMixin {
|
|||
]);
|
||||
}
|
||||
|
||||
Future<void> test_shutdownWithoutStartup() async {
|
||||
await manager.shutdown();
|
||||
void test_shutdownWithoutStartup() {
|
||||
manager.shutdown();
|
||||
analytics.assertNoEvents();
|
||||
}
|
||||
|
||||
Future<void> test_startup_withoutVersion() async {
|
||||
void test_startup_withoutVersion() {
|
||||
var arguments = ['a', 'b'];
|
||||
var clientId = 'clientId';
|
||||
var sdkVersion = 'sdkVersion';
|
||||
manager.startUp(
|
||||
time: DateTime.now(),
|
||||
arguments: arguments,
|
||||
clientId: clientId,
|
||||
clientVersion: null);
|
||||
await manager.shutdown();
|
||||
clientVersion: null,
|
||||
sdkVersion: sdkVersion);
|
||||
manager.shutdown();
|
||||
analytics.assertEvents([
|
||||
_ExpectedEvent.session(eventData: {
|
||||
_ExpectedEvent.session(parameters: {
|
||||
'flags': arguments.join(','),
|
||||
'clientId': clientId,
|
||||
'clientVersion': '',
|
||||
'sdkVersion': sdkVersion,
|
||||
'duration': _IsStringEncodedPositiveInt(),
|
||||
}),
|
||||
]);
|
||||
}
|
||||
|
||||
Future<void> test_startup_withPlugins() async {
|
||||
void test_startup_withPlugins() {
|
||||
_defaultStartup();
|
||||
manager.changedPlugins(_MockPluginManager(plugins: [
|
||||
_MockPluginInfo('a'),
|
||||
_MockPluginInfo('b'),
|
||||
]));
|
||||
await manager.shutdown();
|
||||
manager.shutdown();
|
||||
var counts =
|
||||
'{"count":1,"percentiles":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}';
|
||||
analytics.assertEvents([
|
||||
_ExpectedEvent.session(eventData: {
|
||||
_ExpectedEvent.session(parameters: {
|
||||
'plugins': '{"recordCount":1,"rootCounts":{"a":$counts,"b":$counts}}'
|
||||
}),
|
||||
]);
|
||||
}
|
||||
|
||||
Future<void> test_startup_withVersion() async {
|
||||
void test_startup_withVersion() {
|
||||
var arguments = ['a', 'b'];
|
||||
var clientId = 'clientId';
|
||||
var clientVersion = 'clientVersion';
|
||||
var sdkVersion = 'sdkVersion';
|
||||
manager.startUp(
|
||||
time: DateTime.now(),
|
||||
arguments: arguments,
|
||||
clientId: clientId,
|
||||
clientVersion: clientVersion);
|
||||
await manager.shutdown();
|
||||
clientVersion: clientVersion,
|
||||
sdkVersion: sdkVersion);
|
||||
manager.shutdown();
|
||||
analytics.assertEvents([
|
||||
_ExpectedEvent.session(eventData: {
|
||||
_ExpectedEvent.session(parameters: {
|
||||
'flags': arguments.join(','),
|
||||
'clientId': clientId,
|
||||
'clientVersion': clientVersion,
|
||||
'': isNull,
|
||||
'sdkVersion': sdkVersion,
|
||||
'duration': _IsStringEncodedPositiveInt(),
|
||||
}),
|
||||
]);
|
||||
|
@ -407,7 +411,11 @@ class AnalyticsManagerTest with ResourceProviderMixin {
|
|||
|
||||
void _defaultStartup() {
|
||||
manager.startUp(
|
||||
time: DateTime.now(), arguments: [], clientId: '', clientVersion: null);
|
||||
time: DateTime.now(),
|
||||
arguments: [],
|
||||
clientId: '',
|
||||
clientVersion: null,
|
||||
sdkVersion: '');
|
||||
}
|
||||
|
||||
DateTime _now() => DateTime.now();
|
||||
|
@ -415,47 +423,66 @@ class AnalyticsManagerTest with ResourceProviderMixin {
|
|||
|
||||
/// A record of an event that was reported to analytics.
|
||||
class _Event {
|
||||
final DashEvent eventName;
|
||||
final Map<String, Object?> eventData;
|
||||
final String category;
|
||||
final String action;
|
||||
final String? label;
|
||||
final int? value;
|
||||
final Map<String, String>? parameters;
|
||||
|
||||
_Event(this.eventName, this.eventData);
|
||||
_Event(this.category, this.action, this.label, this.value, this.parameters);
|
||||
}
|
||||
|
||||
/// A record of an event that was reported to analytics.
|
||||
class _ExpectedEvent {
|
||||
final DashEvent eventName;
|
||||
final Map<String, Object?>? eventData;
|
||||
final String category;
|
||||
final String action;
|
||||
final String? label;
|
||||
final int? value;
|
||||
final Map<String, Object>? parameters;
|
||||
|
||||
_ExpectedEvent(this.eventName, this.eventData);
|
||||
_ExpectedEvent(this.category, this.action,
|
||||
{this.label, // ignore: unused_element
|
||||
this.value, // ignore: unused_element
|
||||
this.parameters});
|
||||
|
||||
_ExpectedEvent.lintUsageCounts({Map<String, Object?>? eventData})
|
||||
: this(DashEvent.lintUsageCounts, eventData);
|
||||
_ExpectedEvent.lintUsageCounts({Map<String, Object>? parameters})
|
||||
: this('language_server', 'lintUsageCounts', parameters: parameters);
|
||||
|
||||
_ExpectedEvent.notification({Map<String, Object?>? eventData})
|
||||
: this(DashEvent.notification, eventData);
|
||||
_ExpectedEvent.notification({Map<String, Object>? parameters})
|
||||
: this('language_server', 'notification', parameters: parameters);
|
||||
|
||||
_ExpectedEvent.pluginRequest({Map<String, Object?>? eventData})
|
||||
: this(DashEvent.pluginRequest, eventData);
|
||||
_ExpectedEvent.pluginRequest({Map<String, Object>? parameters})
|
||||
: this('language_server', 'pluginRequest', parameters: parameters);
|
||||
|
||||
_ExpectedEvent.request({Map<String, Object?>? eventData})
|
||||
: this(DashEvent.request, eventData);
|
||||
_ExpectedEvent.request({Map<String, Object>? parameters})
|
||||
: this('language_server', 'request', parameters: parameters);
|
||||
|
||||
_ExpectedEvent.session({Map<String, Object?>? eventData})
|
||||
: this(DashEvent.session, eventData);
|
||||
_ExpectedEvent.session({Map<String, Object>? parameters})
|
||||
: this('language_server', 'session', parameters: parameters);
|
||||
|
||||
_ExpectedEvent.severityAdjustments({Map<String, Object?>? eventData})
|
||||
: this(DashEvent.severityAdjustments, eventData);
|
||||
_ExpectedEvent.severityAdjustments({Map<String, Object>? parameters})
|
||||
: this('language_server', 'severityAdjustments', parameters: parameters);
|
||||
|
||||
/// Compare the expected event with the [actual] event, failing if the actual
|
||||
/// doesn't match the expected.
|
||||
void matches(_Event actual) {
|
||||
expect(actual.eventName, eventName);
|
||||
final actualData = actual.eventData;
|
||||
final expectedData = eventData;
|
||||
if (expectedData != null) {
|
||||
for (var expectedKey in expectedData.keys) {
|
||||
var actualValue = actualData[expectedKey];
|
||||
var expectedValue = expectedData[expectedKey];
|
||||
expect(actual.category, category);
|
||||
expect(actual.action, action);
|
||||
if (label != null) {
|
||||
expect(actual.label, label);
|
||||
}
|
||||
if (value != null) {
|
||||
expect(actual.value, value);
|
||||
}
|
||||
final actualParameters = actual.parameters;
|
||||
final expectedParameters = parameters;
|
||||
if (expectedParameters != null) {
|
||||
if (actualParameters == null) {
|
||||
fail('Expected parameters but found none');
|
||||
}
|
||||
for (var expectedKey in expectedParameters.keys) {
|
||||
var actualValue = actualParameters[expectedKey];
|
||||
var expectedValue = expectedParameters[expectedKey];
|
||||
expect(actualValue, expectedValue, reason: 'For key $expectedKey');
|
||||
}
|
||||
}
|
||||
|
@ -464,11 +491,17 @@ class _ExpectedEvent {
|
|||
@override
|
||||
String toString() {
|
||||
var buffer = StringBuffer();
|
||||
buffer.write('eventData: ');
|
||||
buffer.writeln(eventData);
|
||||
var data = eventData;
|
||||
if (data != null) {
|
||||
for (var entry in data.entries) {
|
||||
buffer.write('category: ');
|
||||
buffer.writeln(category);
|
||||
buffer.write('action: ');
|
||||
buffer.writeln(action);
|
||||
buffer.write('label: ');
|
||||
buffer.writeln(label);
|
||||
buffer.write('value: ');
|
||||
buffer.writeln(value);
|
||||
var parameterMap = parameters;
|
||||
if (parameterMap != null) {
|
||||
for (var entry in parameterMap.entries) {
|
||||
buffer.write('value: ');
|
||||
buffer.writeln('${entry.key}: ${entry.value}');
|
||||
}
|
||||
|
@ -533,15 +566,6 @@ class _MockAnalytics implements Analytics {
|
|||
|
||||
_MockAnalytics();
|
||||
|
||||
@override
|
||||
Map<String, ToolInfo> get parsedTools => throw UnimplementedError();
|
||||
|
||||
@override
|
||||
bool get shouldShowMessage => false;
|
||||
|
||||
@override
|
||||
bool get telemetryEnabled => false;
|
||||
|
||||
void assertEvents(List<_ExpectedEvent> expectedEvents) {
|
||||
var expectedCount = expectedEvents.length;
|
||||
expect(events, hasLength(expectedCount));
|
||||
|
@ -556,23 +580,21 @@ class _MockAnalytics implements Analytics {
|
|||
|
||||
@override
|
||||
void close() {
|
||||
// Ignored
|
||||
}
|
||||
|
||||
@override
|
||||
LogFileStats? logFileStats() {
|
||||
throw UnimplementedError();
|
||||
// ignored
|
||||
}
|
||||
|
||||
@override
|
||||
dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
|
||||
|
||||
@override
|
||||
Future<http.Response>? sendEvent(
|
||||
{required DashEvent eventName,
|
||||
Map<String, Object?> eventData = const {}}) {
|
||||
events.add(_Event(eventName, eventData));
|
||||
return null;
|
||||
Future sendEvent(String category, String action,
|
||||
{String? label, int? value, Map<String, String>? parameters}) async {
|
||||
events.add(_Event(category, action, label, value, parameters));
|
||||
}
|
||||
|
||||
@override
|
||||
Future waitForLastPing({Duration? timeout}) async {
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue