Apply basic log filtering and formatting to fuchsia logs. (#24143)
diff --git a/packages/flutter_tools/lib/src/base/time.dart b/packages/flutter_tools/lib/src/base/time.dart
new file mode 100644
index 0000000..5ba7e02
--- /dev/null
+++ b/packages/flutter_tools/lib/src/base/time.dart
@@ -0,0 +1,34 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'context.dart';
+
+/// The current system clock instance.
+SystemClock get systemClock => context[SystemClock];
+
+/// A class for making time based operations testable.
+class SystemClock {
+ /// A const constructor to allow subclasses to be const.
+ const SystemClock();
+
+ /// Create a clock with a fixed current time.
+ const factory SystemClock.fixed(DateTime time) = _FixedTimeClock;
+
+ /// Retrieve the current time.
+ DateTime now() => DateTime.now();
+
+ /// Compute the time a given duration ago.
+ DateTime ago(Duration duration) {
+ return now().subtract(duration);
+ }
+}
+
+class _FixedTimeClock extends SystemClock {
+ const _FixedTimeClock(this._fixedTime);
+
+ final DateTime _fixedTime;
+
+ @override
+ DateTime now() => _fixedTime;
+}
diff --git a/packages/flutter_tools/lib/src/base/utils.dart b/packages/flutter_tools/lib/src/base/utils.dart
index b0e5049..4bdb587 100644
--- a/packages/flutter_tools/lib/src/base/utils.dart
+++ b/packages/flutter_tools/lib/src/base/utils.dart
@@ -8,7 +8,6 @@
import 'package:crypto/crypto.dart';
import 'package:intl/intl.dart';
-import 'package:quiver/time.dart';
import '../globals.dart';
import 'context.dart';
@@ -251,8 +250,6 @@
return map.cast<String, dynamic>();
}
-Clock get clock => context[Clock];
-
typedef AsyncCallback = Future<void> Function();
/// A [Timer] inspired class that:
diff --git a/packages/flutter_tools/lib/src/commands/run.dart b/packages/flutter_tools/lib/src/commands/run.dart
index cb0e66e..145e668 100644
--- a/packages/flutter_tools/lib/src/commands/run.dart
+++ b/packages/flutter_tools/lib/src/commands/run.dart
@@ -6,6 +6,7 @@
import '../base/common.dart';
import '../base/file_system.dart';
+import '../base/time.dart';
import '../base/utils.dart';
import '../build_info.dart';
import '../cache.dart';
@@ -300,7 +301,7 @@
} catch (error) {
throwToolExit(error.toString());
}
- final DateTime appStartedTime = clock.now();
+ final DateTime appStartedTime = systemClock.now();
final int result = await app.runner.waitForAppToFinish();
if (result != 0)
throwToolExit(null, exitCode: result);
@@ -391,7 +392,7 @@
final Completer<void> appStartedTimeRecorder = Completer<void>.sync();
// This callback can't throw.
appStartedTimeRecorder.future.then<void>( // ignore: unawaited_futures
- (_) { appStartedTime = clock.now(); }
+ (_) { appStartedTime = systemClock.now(); }
);
final int result = await runner.run(
diff --git a/packages/flutter_tools/lib/src/context_runner.dart b/packages/flutter_tools/lib/src/context_runner.dart
index f973516..d9dff8a 100644
--- a/packages/flutter_tools/lib/src/context_runner.dart
+++ b/packages/flutter_tools/lib/src/context_runner.dart
@@ -4,8 +4,6 @@
import 'dart:async';
-import 'package:quiver/time.dart';
-
import 'android/android_sdk.dart';
import 'android/android_studio.dart';
import 'android/android_workflow.dart';
@@ -19,6 +17,7 @@
import 'base/logger.dart';
import 'base/os.dart';
import 'base/platform.dart';
+import 'base/time.dart';
import 'base/utils.dart';
import 'cache.dart';
import 'compile.dart';
@@ -55,7 +54,6 @@
AssetBundleFactory: () => AssetBundleFactory.defaultInstance,
BotDetector: () => const BotDetector(),
Cache: () => Cache(),
- Clock: () => const Clock(),
CocoaPods: () => CocoaPods(),
CocoaPodsValidator: () => const CocoaPodsValidator(),
Config: () => Config(),
@@ -68,7 +66,7 @@
FuchsiaArtifacts: () => FuchsiaArtifacts(),
FuchsiaWorkflow: () => FuchsiaWorkflow(),
Flags: () => const EmptyFlags(),
- FlutterVersion: () => FlutterVersion(const Clock()),
+ FlutterVersion: () => FlutterVersion(const SystemClock()),
GenSnapshot: () => const GenSnapshot(),
HotRunnerConfig: () => HotRunnerConfig(),
IMobileDevice: () => const IMobileDevice(),
@@ -80,6 +78,7 @@
OperatingSystemUtils: () => OperatingSystemUtils(),
PlistBuddy: () => const PlistBuddy(),
SimControl: () => SimControl(),
+ SystemClock: () => const SystemClock(),
Stdio: () => const Stdio(),
Usage: () => Usage(),
Xcode: () => Xcode(),
diff --git a/packages/flutter_tools/lib/src/fuchsia/fuchsia_device.dart b/packages/flutter_tools/lib/src/fuchsia/fuchsia_device.dart
index dba2a3a..c1ada88 100644
--- a/packages/flutter_tools/lib/src/fuchsia/fuchsia_device.dart
+++ b/packages/flutter_tools/lib/src/fuchsia/fuchsia_device.dart
@@ -12,6 +12,7 @@
import '../base/platform.dart';
import '../base/process.dart';
import '../base/process_manager.dart';
+import '../base/time.dart';
import '../build_info.dart';
import '../device.dart';
import '../globals.dart';
@@ -25,23 +26,48 @@
/// Read the log for a particular device.
class _FuchsiaLogReader extends DeviceLogReader {
- _FuchsiaLogReader(this._device);
+ _FuchsiaLogReader(this._device, [this._app]);
- // TODO(jonahwilliams): handle filtering log output from different modules.
- static final Pattern flutterLogOutput = RegExp(r'\[\d+\.\d+\]\[\d+\]\[\d+\]\[klog\] INFO: \w+\(flutter\): ');
+ static final RegExp _flutterLogOutput = RegExp(r'INFO: \w+\(flutter\): ');
+ static final RegExp _utcDateOutput = RegExp(r'\d+\-\d+\-\d+ \d+:\d+:\d+');
FuchsiaDevice _device;
+ ApplicationPackage _app;
@override String get name => _device.name;
Stream<String> _logLines;
@override
Stream<String> get logLines {
- _logLines ??= fuchsiaSdk.syslogs()
- .where((String line) => flutterLogOutput.matchAsPrefix(line) != null);
+ _logLines ??= _processLogs(fuchsiaSdk.syslogs());
return _logLines;
}
+ Stream<String> _processLogs(Stream<String> lines) async* {
+ // Get the starting time of the log processor to filter logs from before
+ // the process attached.
+ final DateTime startTime = systemClock.now();
+ // Determine if line comes from flutter, and optionally whether it matches
+ // the correct fuchsia module.
+ final RegExp matchRegExp = _app == null
+ ? _flutterLogOutput
+ : RegExp('INFO: ${_app.name}\\(flutter\\): ');
+ await for (String line in lines.where(matchRegExp.hasMatch)) {
+ // Read out the date string from the log and compare it to the current time:
+ // Example: 2018-11-09 01:27:45
+ final String rawDate = _utcDateOutput.firstMatch(line)?.group(0);
+ if (rawDate == null) {
+ continue;
+ }
+ final DateTime logTime = DateTime.parse(rawDate);
+ if (logTime.millisecondsSinceEpoch < startTime.millisecondsSinceEpoch) {
+ continue;
+ }
+ // Format log into a useful string:
+ yield '[${logTime.toLocal()}] Flutter: ${line.split(matchRegExp).last}';
+ }
+ }
+
@override
String toString() => name;
}
@@ -152,7 +178,7 @@
Future<String> get sdkNameAndVersion async => 'Fuchsia';
@override
- DeviceLogReader getLogReader({ApplicationPackage app}) => _logReader ??= _FuchsiaLogReader(this);
+ DeviceLogReader getLogReader({ApplicationPackage app}) => _logReader ??= _FuchsiaLogReader(this, app);
_FuchsiaLogReader _logReader;
@override
@@ -279,6 +305,13 @@
}
}
+class FuchsiaModulePackage extends ApplicationPackage {
+ FuchsiaModulePackage({@required this.name}) : super(id: name);
+
+ @override
+ final String name;
+}
+
/// Parses output from `dart.services` output on a fuchsia device.
///
/// Example output:
diff --git a/packages/flutter_tools/lib/src/fuchsia/fuchsia_sdk.dart b/packages/flutter_tools/lib/src/fuchsia/fuchsia_sdk.dart
index a67ea94..201fefe 100644
--- a/packages/flutter_tools/lib/src/fuchsia/fuchsia_sdk.dart
+++ b/packages/flutter_tools/lib/src/fuchsia/fuchsia_sdk.dart
@@ -12,7 +12,6 @@
import '../base/platform.dart';
import '../base/process.dart';
import '../base/process_manager.dart';
-import '../globals.dart';
/// The [FuchsiaSdk] instance.
FuchsiaSdk get fuchsiaSdk => context[FuchsiaSdk];
@@ -27,7 +26,7 @@
class FuchsiaSdk {
static const List<String> _netaddrCommand = <String>['fx', 'netaddr', '--fuchsia', '--nowait'];
static const List<String> _netlsCommand = <String>['fx', 'netls', '--nowait'];
- static const List<String> _syslogCommand = <String>['fx', 'syslog'];
+ static const List<String> _syslogCommand = <String>['fx', 'syslog', '--clock', 'Local'];
/// Invokes the `netaddr` command.
///
@@ -57,12 +56,11 @@
process.kill();
});
processManager.start(_syslogCommand).then((Process newProcess) {
- printTrace('Running logs');
if (controller.isClosed) {
return;
}
process = newProcess;
- process.exitCode.then((_) => controller.close);
+ process.exitCode.whenComplete(controller.close);
controller.addStream(process.stdout.transform(utf8.decoder).transform(const LineSplitter()));
});
return controller.stream;
diff --git a/packages/flutter_tools/lib/src/runner/flutter_command.dart b/packages/flutter_tools/lib/src/runner/flutter_command.dart
index 95ae66f..83ea0b4 100644
--- a/packages/flutter_tools/lib/src/runner/flutter_command.dart
+++ b/packages/flutter_tools/lib/src/runner/flutter_command.dart
@@ -13,6 +13,7 @@
import '../base/common.dart';
import '../base/context.dart';
import '../base/file_system.dart';
+import '../base/time.dart';
import '../base/utils.dart';
import '../build_info.dart';
import '../bundle.dart' as bundle;
@@ -320,7 +321,7 @@
/// so that this method can record and report the overall time to analytics.
@override
Future<void> run() {
- final DateTime startTime = clock.now();
+ final DateTime startTime = systemClock.now();
return context.run<void>(
name: 'command',
@@ -336,7 +337,7 @@
commandResult = const FlutterCommandResult(ExitStatus.fail);
rethrow;
} finally {
- final DateTime endTime = clock.now();
+ final DateTime endTime = systemClock.now();
printTrace('"flutter $name" took ${getElapsedAsMilliseconds(endTime.difference(startTime))}.');
// This is checking the result of the call to 'usagePath'
// (a Future<String>), and not the result of evaluating the Future.
diff --git a/packages/flutter_tools/lib/src/version.dart b/packages/flutter_tools/lib/src/version.dart
index 444acc2..5f09e68 100644
--- a/packages/flutter_tools/lib/src/version.dart
+++ b/packages/flutter_tools/lib/src/version.dart
@@ -6,7 +6,6 @@
import 'dart:convert';
import 'package:meta/meta.dart';
-import 'package:quiver/time.dart';
import 'base/common.dart';
import 'base/context.dart';
@@ -14,12 +13,13 @@
import 'base/io.dart';
import 'base/process.dart';
import 'base/process_manager.dart';
+import 'base/time.dart';
import 'cache.dart';
import 'globals.dart';
class FlutterVersion {
@visibleForTesting
- FlutterVersion([this._clock = const Clock()]) {
+ FlutterVersion([this._clock = const SystemClock()]) {
_channel = _runGit('git rev-parse --abbrev-ref --symbolic @{u}');
final String branch = _runGit('git rev-parse --abbrev-ref HEAD');
_branch = branch == 'HEAD' ? _channel : branch;
@@ -38,7 +38,7 @@
_frameworkVersion = GitTagVersion.determine().frameworkVersionFor(_frameworkRevision);
}
- final Clock _clock;
+ final SystemClock _clock;
String _repositoryUrl;
String get repositoryUrl => _repositoryUrl;
@@ -273,7 +273,7 @@
// Do not load the stamp before the above server check as it may modify the stamp file.
final VersionCheckStamp stamp = await VersionCheckStamp.load();
- final DateTime lastTimeWarningWasPrinted = stamp.lastTimeWarningWasPrinted ?? _clock.agoBy(kMaxTimeSinceLastWarning * 2);
+ final DateTime lastTimeWarningWasPrinted = stamp.lastTimeWarningWasPrinted ?? _clock.ago(kMaxTimeSinceLastWarning * 2);
final bool beenAWhileSinceWarningWasPrinted = _clock.now().difference(lastTimeWarningWasPrinted) > kMaxTimeSinceLastWarning;
// We show a warning if either we know there is a new remote version, or we couldn't tell but the local