| // 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.nullSafety, |
| @required this.fastReassemble, |
| this.reason, |
| this.finalLibraryCount, |
| this.syncedLibraryCount, |
| this.syncedClassesCount, |
| this.syncedProceduresCount, |
| this.syncedBytes, |
| this.invalidatedSourcesCount, |
| this.transferTimeInMs, |
| this.overallTimeInMs, |
| }) : super('hot', parameter, flutterUsage: globals.flutterUsage); |
| |
| final String reason; |
| final String targetPlatform; |
| final String sdkName; |
| final bool emulator; |
| final bool fullRestart; |
| final bool nullSafety; |
| 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; |
| |
| @override |
| void send() { |
| final Map<String, String> parameters = _useCdKeys(<CustomDimensions, String>{ |
| CustomDimensions.hotEventTargetPlatform: targetPlatform, |
| CustomDimensions.hotEventSdkName: sdkName, |
| CustomDimensions.hotEventEmulator: emulator.toString(), |
| CustomDimensions.hotEventFullRestart: fullRestart.toString(), |
| if (reason != null) |
| CustomDimensions.hotEventReason: reason, |
| if (finalLibraryCount != null) |
| CustomDimensions.hotEventFinalLibraryCount: finalLibraryCount.toString(), |
| if (syncedLibraryCount != null) |
| CustomDimensions.hotEventSyncedLibraryCount: syncedLibraryCount.toString(), |
| if (syncedClassesCount != null) |
| CustomDimensions.hotEventSyncedClassesCount: syncedClassesCount.toString(), |
| if (syncedProceduresCount != null) |
| CustomDimensions.hotEventSyncedProceduresCount: syncedProceduresCount.toString(), |
| if (syncedBytes != null) |
| CustomDimensions.hotEventSyncedBytes: syncedBytes.toString(), |
| if (invalidatedSourcesCount != null) |
| CustomDimensions.hotEventInvalidatedSourcesCount: invalidatedSourcesCount.toString(), |
| if (transferTimeInMs != null) |
| CustomDimensions.hotEventTransferTimeInMs: transferTimeInMs.toString(), |
| if (overallTimeInMs != null) |
| CustomDimensions.hotEventOverallTimeInMs: overallTimeInMs.toString(), |
| if (nullSafety != null) |
| CustomDimensions.nullSafety: nullSafety.toString(), |
| if (fastReassemble != null) |
| CustomDimensions.fastReassemble: fastReassemble.toString(), |
| }); |
| 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 == null) { |
| 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, |
| }) : _command = command, |
| _settings = settings, |
| _eventError = eventError, |
| super( |
| // category |
| 'build', |
| // parameter |
| FlutterCommand.current == null |
| ? 'unspecified' |
| : FlutterCommand.current.name, |
| label: label, |
| flutterUsage: flutterUsage, |
| ); |
| |
| final String _command; |
| final String _settings; |
| final String _eventError; |
| |
| @override |
| void send() { |
| final Map<String, String> parameters = _useCdKeys(<CustomDimensions, String>{ |
| if (_command != null) |
| CustomDimensions.buildEventCommand: _command, |
| if (_settings != null) |
| CustomDimensions.buildEventSettings: _settings, |
| if (_eventError != null) |
| CustomDimensions.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, FlutterCommandResult result) |
| : assert(commandPath != null), |
| assert(result != null), |
| super(commandPath, result.toString(), 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 = 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 ?? globals.flutterUsage, |
| ); |
| } |