317 lines
9.5 KiB
Dart
317 lines
9.5 KiB
Dart
// Copyright 2014 The Flutter Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
part of reporting;
|
|
|
|
/// A generic usage even that does not involve custom dimensions.
|
|
///
|
|
/// If sending values for custom dimensions is required, extend this class as
|
|
/// below.
|
|
class UsageEvent {
|
|
UsageEvent(this.category, this.parameter, {
|
|
this.label,
|
|
this.value,
|
|
required this.flutterUsage,
|
|
});
|
|
|
|
final String category;
|
|
final String parameter;
|
|
final String? label;
|
|
final int? value;
|
|
final Usage flutterUsage;
|
|
|
|
void send() {
|
|
flutterUsage.sendEvent(category, parameter, label: label, value: value);
|
|
}
|
|
}
|
|
|
|
/// A usage event related to hot reload/restart.
|
|
///
|
|
/// On a successful hot reload, we collect stats that help understand scale of
|
|
/// the update. For example, [syncedLibraryCount]/[finalLibraryCount] indicates
|
|
/// how many libraries were affected by the hot reload request. Relation of
|
|
/// [invalidatedSourcesCount] to [syncedLibraryCount] should help understand
|
|
/// sync/transfer "overhead" of updating this number of source files.
|
|
class HotEvent extends UsageEvent {
|
|
HotEvent(String parameter, {
|
|
required this.targetPlatform,
|
|
required this.sdkName,
|
|
required this.emulator,
|
|
required this.fullRestart,
|
|
required this.fastReassemble,
|
|
this.reason,
|
|
this.finalLibraryCount,
|
|
this.syncedLibraryCount,
|
|
this.syncedClassesCount,
|
|
this.syncedProceduresCount,
|
|
this.syncedBytes,
|
|
this.invalidatedSourcesCount,
|
|
this.transferTimeInMs,
|
|
this.overallTimeInMs,
|
|
this.compileTimeInMs,
|
|
this.findInvalidatedTimeInMs,
|
|
this.scannedSourcesCount,
|
|
this.reassembleTimeInMs,
|
|
this.reloadVMTimeInMs,
|
|
}) : super('hot', parameter, flutterUsage: globals.flutterUsage);
|
|
|
|
final String? reason;
|
|
final String targetPlatform;
|
|
final String sdkName;
|
|
final bool emulator;
|
|
final bool fullRestart;
|
|
final bool fastReassemble;
|
|
final int? finalLibraryCount;
|
|
final int? syncedLibraryCount;
|
|
final int? syncedClassesCount;
|
|
final int? syncedProceduresCount;
|
|
final int? syncedBytes;
|
|
final int? invalidatedSourcesCount;
|
|
final int? transferTimeInMs;
|
|
final int? overallTimeInMs;
|
|
final int? compileTimeInMs;
|
|
final int? findInvalidatedTimeInMs;
|
|
final int? scannedSourcesCount;
|
|
final int? reassembleTimeInMs;
|
|
final int? reloadVMTimeInMs;
|
|
|
|
@override
|
|
void send() {
|
|
final CustomDimensions parameters = CustomDimensions(
|
|
hotEventTargetPlatform: targetPlatform,
|
|
hotEventSdkName: sdkName,
|
|
hotEventEmulator: emulator,
|
|
hotEventFullRestart: fullRestart,
|
|
hotEventReason: reason,
|
|
hotEventFinalLibraryCount: finalLibraryCount,
|
|
hotEventSyncedLibraryCount: syncedLibraryCount,
|
|
hotEventSyncedClassesCount: syncedClassesCount,
|
|
hotEventSyncedProceduresCount: syncedProceduresCount,
|
|
hotEventSyncedBytes: syncedBytes,
|
|
hotEventInvalidatedSourcesCount: invalidatedSourcesCount,
|
|
hotEventTransferTimeInMs: transferTimeInMs,
|
|
hotEventOverallTimeInMs: overallTimeInMs,
|
|
fastReassemble: fastReassemble,
|
|
hotEventCompileTimeInMs: compileTimeInMs,
|
|
hotEventFindInvalidatedTimeInMs: findInvalidatedTimeInMs,
|
|
hotEventScannedSourcesCount: scannedSourcesCount,
|
|
hotEventReassembleTimeInMs: reassembleTimeInMs,
|
|
hotEventReloadVMTimeInMs: reloadVMTimeInMs,
|
|
);
|
|
flutterUsage.sendEvent(category, parameter, parameters: parameters);
|
|
}
|
|
}
|
|
|
|
/// An event that reports the result of a [DoctorValidator]
|
|
class DoctorResultEvent extends UsageEvent {
|
|
DoctorResultEvent({
|
|
required this.validator,
|
|
required this.result,
|
|
Usage? flutterUsage,
|
|
}) : super(
|
|
'doctor-result',
|
|
'${validator.runtimeType}',
|
|
label: result.typeStr,
|
|
flutterUsage: flutterUsage ?? globals.flutterUsage,
|
|
);
|
|
|
|
final DoctorValidator validator;
|
|
final ValidationResult result;
|
|
|
|
@override
|
|
void send() {
|
|
if (validator is! GroupedValidator) {
|
|
flutterUsage.sendEvent(category, parameter, label: label);
|
|
return;
|
|
}
|
|
final GroupedValidator group = validator as GroupedValidator;
|
|
// The validator crashed.
|
|
if (group.subResults.isEmpty) {
|
|
flutterUsage.sendEvent(category, parameter, label: label);
|
|
return;
|
|
}
|
|
for (int i = 0; i < group.subValidators.length; i++) {
|
|
final DoctorValidator v = group.subValidators[i];
|
|
final ValidationResult r = group.subResults[i];
|
|
DoctorResultEvent(validator: v, result: r, flutterUsage: flutterUsage).send();
|
|
}
|
|
}
|
|
}
|
|
|
|
/// An event that reports on the result of a pub invocation.
|
|
class PubResultEvent extends UsageEvent {
|
|
PubResultEvent({
|
|
required String context,
|
|
required String result,
|
|
required Usage usage,
|
|
}) : super('pub-result', context, label: result, flutterUsage: usage);
|
|
}
|
|
|
|
/// An event that reports something about a build.
|
|
class BuildEvent extends UsageEvent {
|
|
BuildEvent(String label, {
|
|
String? command,
|
|
String? settings,
|
|
String? eventError,
|
|
required Usage flutterUsage,
|
|
required String type,
|
|
}) : _command = command,
|
|
_settings = settings,
|
|
_eventError = eventError,
|
|
super(
|
|
// category
|
|
'build',
|
|
// parameter
|
|
type,
|
|
label: label,
|
|
flutterUsage: flutterUsage,
|
|
);
|
|
|
|
final String? _command;
|
|
final String? _settings;
|
|
final String? _eventError;
|
|
|
|
@override
|
|
void send() {
|
|
final CustomDimensions parameters = CustomDimensions(
|
|
buildEventCommand: _command,
|
|
buildEventSettings: _settings,
|
|
buildEventError: _eventError,
|
|
);
|
|
flutterUsage.sendEvent(
|
|
category,
|
|
parameter,
|
|
label: label,
|
|
parameters: parameters,
|
|
);
|
|
}
|
|
}
|
|
|
|
/// An event that reports the result of a top-level command.
|
|
class CommandResultEvent extends UsageEvent {
|
|
CommandResultEvent(String commandPath, String result)
|
|
: assert(commandPath != null),
|
|
assert(result != null),
|
|
super(commandPath, result, flutterUsage: globals.flutterUsage);
|
|
|
|
@override
|
|
void send() {
|
|
// An event for the command result.
|
|
flutterUsage.sendEvent(
|
|
'tool-command-result',
|
|
category,
|
|
label: parameter,
|
|
);
|
|
|
|
// A separate event for the memory highwater mark. This is a separate event
|
|
// so that we can get the command result even if trying to grab maxRss
|
|
// throws an exception.
|
|
try {
|
|
final int maxRss = globals.processInfo.maxRss;
|
|
flutterUsage.sendEvent(
|
|
'tool-command-max-rss',
|
|
category,
|
|
label: parameter,
|
|
value: maxRss,
|
|
);
|
|
} on Exception catch (error) {
|
|
// If grabbing the maxRss fails for some reason, just don't send an event.
|
|
globals.printTrace('Querying maxRss failed with error: $error');
|
|
}
|
|
}
|
|
}
|
|
|
|
/// An event that reports on changes in the configuration of analytics.
|
|
class AnalyticsConfigEvent extends UsageEvent {
|
|
AnalyticsConfigEvent({
|
|
/// Whether analytics reporting is being enabled (true) or disabled (false).
|
|
required bool enabled,
|
|
}) : super(
|
|
'analytics',
|
|
'enabled',
|
|
label: enabled ? 'true' : 'false',
|
|
flutterUsage: globals.flutterUsage,
|
|
);
|
|
}
|
|
|
|
/// An event that reports when the code size measurement is run via `--analyze-size`.
|
|
class CodeSizeEvent extends UsageEvent {
|
|
CodeSizeEvent(String platform, {
|
|
required Usage flutterUsage,
|
|
}) : super(
|
|
'code-size-analysis',
|
|
platform,
|
|
flutterUsage: flutterUsage
|
|
);
|
|
}
|
|
|
|
/// An event for tracking the usage of specific error handling fallbacks.
|
|
class ErrorHandlingEvent extends UsageEvent {
|
|
ErrorHandlingEvent(String parameter) : super('error-handling', parameter, flutterUsage: globals.flutterUsage);
|
|
}
|
|
|
|
/// Emit various null safety analytic events.
|
|
///
|
|
/// 1. The current null safety runtime mode.
|
|
/// 2. The number of packages that are migrated, along with the total number of packages
|
|
/// 3. The main packages language version.
|
|
class NullSafetyAnalysisEvent implements UsageEvent {
|
|
NullSafetyAnalysisEvent(
|
|
this.packageConfig,
|
|
this.nullSafetyMode,
|
|
this.currentPackage,
|
|
this.flutterUsage,
|
|
);
|
|
|
|
/// The category for analytics events related to null safety.
|
|
static const String kNullSafetyCategory = 'null-safety';
|
|
|
|
final PackageConfig packageConfig;
|
|
final NullSafetyMode nullSafetyMode;
|
|
final String currentPackage;
|
|
@override
|
|
final Usage flutterUsage;
|
|
|
|
@override
|
|
void send() {
|
|
if (packageConfig.packages.isEmpty) {
|
|
return;
|
|
}
|
|
int migrated = 0;
|
|
LanguageVersion? languageVersion;
|
|
for (final Package package in packageConfig.packages) {
|
|
final LanguageVersion? packageLanguageVersion = package.languageVersion;
|
|
if (package.name == currentPackage) {
|
|
languageVersion = packageLanguageVersion;
|
|
}
|
|
if (packageLanguageVersion != null &&
|
|
packageLanguageVersion.major >= nullSafeVersion.major &&
|
|
packageLanguageVersion.minor >= nullSafeVersion.minor) {
|
|
migrated += 1;
|
|
}
|
|
}
|
|
flutterUsage.sendEvent(kNullSafetyCategory, 'runtime-mode', label: nullSafetyMode.toString());
|
|
flutterUsage.sendEvent(kNullSafetyCategory, 'stats', parameters: CustomDimensions(
|
|
nullSafeMigratedLibraries: migrated,
|
|
nullSafeTotalLibraries: packageConfig.packages.length,
|
|
));
|
|
if (languageVersion != null) {
|
|
final String formattedVersion = '${languageVersion.major}.${languageVersion.minor}';
|
|
flutterUsage.sendEvent(kNullSafetyCategory, 'language-version', label: formattedVersion);
|
|
}
|
|
}
|
|
|
|
@override
|
|
String get category => kNullSafetyCategory;
|
|
|
|
@override
|
|
String get label => throw UnsupportedError('');
|
|
|
|
@override
|
|
String get parameter => throw UnsupportedError('');
|
|
|
|
@override
|
|
int get value => throw UnsupportedError('');
|
|
}
|