mirror of
https://github.com/flutter/flutter
synced 2024-10-13 03:32:55 +00:00
[flutter_tool] Report rss high watermark in command analytics events (#40988)
This commit is contained in:
parent
9c6f11d5d1
commit
5142238c85
|
@ -26,7 +26,7 @@
|
|||
/// increase the API surface that we have to test in Flutter tools, and the APIs
|
||||
/// in `dart:io` can sometimes be hard to use in tests.
|
||||
import 'dart:async';
|
||||
import 'dart:io' as io show exit, IOSink, Process, ProcessSignal, stderr, stdin, Stdout, stdout;
|
||||
import 'dart:io' as io show exit, IOSink, Process, ProcessInfo, ProcessSignal, stderr, stdin, Stdout, stdout;
|
||||
|
||||
import 'package:meta/meta.dart';
|
||||
|
||||
|
@ -62,6 +62,7 @@ export 'dart:io'
|
|||
// Platform NO! use `platform.dart`
|
||||
Process,
|
||||
ProcessException,
|
||||
// ProcessInfo, NO! use `io.dart`
|
||||
ProcessResult,
|
||||
// ProcessSignal NO! Use [ProcessSignal] below.
|
||||
ProcessStartMode,
|
||||
|
@ -188,3 +189,25 @@ Stdio get stdio => context.get<Stdio>() ?? const Stdio();
|
|||
io.Stdout get stdout => stdio.stdout;
|
||||
Stream<List<int>> get stdin => stdio.stdin;
|
||||
io.IOSink get stderr => stdio.stderr;
|
||||
|
||||
/// An overridable version of io.ProcessInfo.
|
||||
abstract class ProcessInfo {
|
||||
factory ProcessInfo() => _DefaultProcessInfo();
|
||||
|
||||
static ProcessInfo get instance => context.get<ProcessInfo>();
|
||||
|
||||
int get currentRss;
|
||||
|
||||
int get maxRss;
|
||||
}
|
||||
|
||||
ProcessInfo get processInfo => ProcessInfo.instance;
|
||||
|
||||
/// The default implementation of [ProcessInfo], which uses [io.ProcessInfo].
|
||||
class _DefaultProcessInfo implements ProcessInfo {
|
||||
@override
|
||||
int get currentRss => io.ProcessInfo.currentRss;
|
||||
|
||||
@override
|
||||
int get maxRss => io.ProcessInfo.maxRss;
|
||||
}
|
||||
|
|
|
@ -104,6 +104,7 @@ Future<T> runInContext<T>(
|
|||
MacOSWorkflow: () => const MacOSWorkflow(),
|
||||
MDnsObservatoryDiscovery: () => MDnsObservatoryDiscovery(),
|
||||
OperatingSystemUtils: () => OperatingSystemUtils(),
|
||||
ProcessInfo: () => ProcessInfo(),
|
||||
ProcessUtils: () => ProcessUtils(),
|
||||
SimControl: () => SimControl(),
|
||||
Stdio: () => const Stdio(),
|
||||
|
|
|
@ -153,4 +153,20 @@ class BuildEvent extends UsageEvent {
|
|||
class CommandResultEvent extends UsageEvent {
|
||||
CommandResultEvent(String commandPath, FlutterCommandResult result)
|
||||
: super(commandPath, result?.toString() ?? 'unspecified');
|
||||
|
||||
@override
|
||||
void send() {
|
||||
int maxRss;
|
||||
try {
|
||||
maxRss = processInfo.maxRss;
|
||||
} catch (e) {
|
||||
// If grabbing the maxRss fails for some reason, just leave it off the
|
||||
// event.
|
||||
}
|
||||
final Map<String, String> parameters = _useCdKeys(<CustomDimensions, String>{
|
||||
if (maxRss != null)
|
||||
CustomDimensions.commandResultEventMaxRss: maxRss.toString(),
|
||||
});
|
||||
flutterUsage.sendEvent(category, parameter, parameters: parameters);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,6 +54,7 @@ enum CustomDimensions {
|
|||
commandBuildAppBundleTargetPlatform, // cd41
|
||||
commandBuildAppBundleBuildMode, // cd42
|
||||
buildEventError, // cd43
|
||||
commandResultEventMaxRss, // cd44
|
||||
}
|
||||
|
||||
String cdKey(CustomDimensions cd) => 'cd${cd.index + 1}';
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
// found in the LICENSE file.
|
||||
|
||||
import 'package:flutter_tools/src/base/common.dart';
|
||||
import 'package:flutter_tools/src/base/io.dart';
|
||||
import 'package:flutter_tools/src/base/time.dart';
|
||||
import 'package:flutter_tools/src/cache.dart';
|
||||
import 'package:flutter_tools/src/reporting/reporting.dart';
|
||||
|
@ -19,16 +20,20 @@ void main() {
|
|||
MockitoCache cache;
|
||||
MockitoUsage usage;
|
||||
MockClock clock;
|
||||
MockProcessInfo mockProcessInfo;
|
||||
List<int> mockTimes;
|
||||
|
||||
setUp(() {
|
||||
cache = MockitoCache();
|
||||
usage = MockitoUsage();
|
||||
clock = MockClock();
|
||||
mockProcessInfo = MockProcessInfo();
|
||||
|
||||
when(usage.isFirstRun).thenReturn(false);
|
||||
when(clock.now()).thenAnswer(
|
||||
(Invocation _) => DateTime.fromMillisecondsSinceEpoch(mockTimes.removeAt(0))
|
||||
);
|
||||
when(mockProcessInfo.maxRss).thenReturn(10);
|
||||
});
|
||||
|
||||
testUsingContext('honors shouldUpdateCache false', () async {
|
||||
|
@ -49,7 +54,15 @@ void main() {
|
|||
Cache: () => cache,
|
||||
});
|
||||
|
||||
testUsingContext('reports command that results in success', () async {
|
||||
void testUsingCommandContext(String testName, Function testBody) {
|
||||
testUsingContext(testName, testBody, overrides: <Type, Generator>{
|
||||
ProcessInfo: () => mockProcessInfo,
|
||||
SystemClock: () => clock,
|
||||
Usage: () => usage,
|
||||
});
|
||||
}
|
||||
|
||||
testUsingCommandContext('reports command that results in success', () async {
|
||||
// Crash if called a third time which is unexpected.
|
||||
mockTimes = <int>[1000, 2000];
|
||||
|
||||
|
@ -61,14 +74,10 @@ void main() {
|
|||
await flutterCommand.run();
|
||||
|
||||
verify(usage.sendCommand(captureAny, parameters: captureAnyNamed('parameters')));
|
||||
verify(usage.sendEvent(captureAny, 'success'));
|
||||
},
|
||||
overrides: <Type, Generator>{
|
||||
SystemClock: () => clock,
|
||||
Usage: () => usage,
|
||||
verify(usage.sendEvent(captureAny, 'success', parameters: captureAnyNamed('parameters')));
|
||||
});
|
||||
|
||||
testUsingContext('reports command that results in warning', () async {
|
||||
testUsingCommandContext('reports command that results in warning', () async {
|
||||
// Crash if called a third time which is unexpected.
|
||||
mockTimes = <int>[1000, 2000];
|
||||
|
||||
|
@ -80,14 +89,10 @@ void main() {
|
|||
await flutterCommand.run();
|
||||
|
||||
verify(usage.sendCommand(captureAny, parameters: captureAnyNamed('parameters')));
|
||||
verify(usage.sendEvent(captureAny, 'warning'));
|
||||
},
|
||||
overrides: <Type, Generator>{
|
||||
SystemClock: () => clock,
|
||||
Usage: () => usage,
|
||||
verify(usage.sendEvent(captureAny, 'warning', parameters: captureAnyNamed('parameters')));
|
||||
});
|
||||
|
||||
testUsingContext('reports command that results in failure', () async {
|
||||
testUsingCommandContext('reports command that results in failure', () async {
|
||||
// Crash if called a third time which is unexpected.
|
||||
mockTimes = <int>[1000, 2000];
|
||||
|
||||
|
@ -101,15 +106,11 @@ void main() {
|
|||
await flutterCommand.run();
|
||||
} on ToolExit {
|
||||
verify(usage.sendCommand(captureAny, parameters: captureAnyNamed('parameters')));
|
||||
verify(usage.sendEvent(captureAny, 'fail'));
|
||||
verify(usage.sendEvent(captureAny, 'fail', parameters: captureAnyNamed('parameters')));
|
||||
}
|
||||
},
|
||||
overrides: <Type, Generator>{
|
||||
SystemClock: () => clock,
|
||||
Usage: () => usage,
|
||||
});
|
||||
|
||||
testUsingContext('reports command that results in error', () async {
|
||||
testUsingCommandContext('reports command that results in error', () async {
|
||||
// Crash if called a third time which is unexpected.
|
||||
mockTimes = <int>[1000, 2000];
|
||||
|
||||
|
@ -125,15 +126,32 @@ void main() {
|
|||
fail('Mock should make this fail');
|
||||
} on ToolExit {
|
||||
verify(usage.sendCommand(captureAny, parameters: captureAnyNamed('parameters')));
|
||||
verify(usage.sendEvent(captureAny, 'fail'));
|
||||
verify(usage.sendEvent(captureAny, 'fail', parameters: captureAnyNamed('parameters')));
|
||||
}
|
||||
},
|
||||
overrides: <Type, Generator>{
|
||||
SystemClock: () => clock,
|
||||
Usage: () => usage,
|
||||
});
|
||||
|
||||
testUsingContext('report execution timing by default', () async {
|
||||
testUsingCommandContext('reports maxRss', () async {
|
||||
// Crash if called a third time which is unexpected.
|
||||
mockTimes = <int>[1000, 2000];
|
||||
|
||||
final DummyFlutterCommand flutterCommand = DummyFlutterCommand(
|
||||
commandFunction: () async {
|
||||
return const FlutterCommandResult(ExitStatus.success);
|
||||
}
|
||||
);
|
||||
await flutterCommand.run();
|
||||
|
||||
verify(usage.sendCommand(captureAny, parameters: captureAnyNamed('parameters')));
|
||||
expect(verify(usage.sendEvent(
|
||||
any,
|
||||
'success',
|
||||
parameters: captureAnyNamed('parameters'),
|
||||
)).captured[0],
|
||||
containsPair(cdKey(CustomDimensions.commandResultEventMaxRss),
|
||||
mockProcessInfo.maxRss.toString()));
|
||||
});
|
||||
|
||||
testUsingCommandContext('report execution timing by default', () async {
|
||||
// Crash if called a third time which is unexpected.
|
||||
mockTimes = <int>[1000, 2000];
|
||||
|
||||
|
@ -152,13 +170,9 @@ void main() {
|
|||
null,
|
||||
],
|
||||
);
|
||||
},
|
||||
overrides: <Type, Generator>{
|
||||
SystemClock: () => clock,
|
||||
Usage: () => usage,
|
||||
});
|
||||
|
||||
testUsingContext('no timing report without usagePath', () async {
|
||||
testUsingCommandContext('no timing report without usagePath', () async {
|
||||
// Crash if called a third time which is unexpected.
|
||||
mockTimes = <int>[1000, 2000];
|
||||
|
||||
|
@ -169,13 +183,9 @@ void main() {
|
|||
verifyNever(usage.sendTiming(
|
||||
any, any, any,
|
||||
label: anyNamed('label')));
|
||||
},
|
||||
overrides: <Type, Generator>{
|
||||
SystemClock: () => clock,
|
||||
Usage: () => usage,
|
||||
});
|
||||
|
||||
testUsingContext('report additional FlutterCommandResult data', () async {
|
||||
testUsingCommandContext('report additional FlutterCommandResult data', () async {
|
||||
// Crash if called a third time which is unexpected.
|
||||
mockTimes = <int>[1000, 2000];
|
||||
|
||||
|
@ -202,13 +212,9 @@ void main() {
|
|||
'success-blah1-blah2-blah3',
|
||||
],
|
||||
);
|
||||
},
|
||||
overrides: <Type, Generator>{
|
||||
SystemClock: () => clock,
|
||||
Usage: () => usage,
|
||||
});
|
||||
|
||||
testUsingContext('report failed execution timing too', () async {
|
||||
testUsingCommandContext('report failed execution timing too', () async {
|
||||
// Crash if called a third time which is unexpected.
|
||||
mockTimes = <int>[1000, 2000];
|
||||
|
||||
|
@ -238,10 +244,6 @@ void main() {
|
|||
],
|
||||
);
|
||||
}
|
||||
},
|
||||
overrides: <Type, Generator>{
|
||||
SystemClock: () => clock,
|
||||
Usage: () => usage,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -261,3 +263,4 @@ class FakeCommand extends FlutterCommand {
|
|||
}
|
||||
|
||||
class MockVersion extends Mock implements FlutterVersion {}
|
||||
class MockProcessInfo extends Mock implements ProcessInfo {}
|
||||
|
|
Loading…
Reference in a new issue