Rename AppRunLogger, stop writing status messages that break JSON (#172591)

Closes https://github.com/flutter/flutter/issues/118907.

It looks like some of the work around splitting had already happened
(`DaemonLogger`), so this ... seems right?
This commit is contained in:
Matan Lurey 2025-07-25 12:14:01 -07:00 committed by GitHub
parent 465b21cee1
commit 3e86cb8773
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 25 additions and 44 deletions

View File

@ -323,7 +323,7 @@ class LoggerFactory {
return NotifyingLogger(verbose: verbose, parent: logger);
}
if (machine) {
return AppRunLogger(parent: logger);
return MachineOutputLogger(parent: logger);
}
return logger;
}

View File

@ -219,9 +219,6 @@ abstract class Logger {
});
/// Send an event to be emitted.
///
/// Only surfaces a value in machine modes, Loggers may ignore this message in
/// non-machine modes.
void sendEvent(String name, [Map<String, dynamic>? args]) {}
/// Clears all output.

View File

@ -378,7 +378,7 @@ known, it can be explicitly provided to attach via the command-line, e.g.
true,
_fileSystem.currentDirectory,
LaunchMode.attach,
_logger as AppRunLogger,
_logger as MachineOutputLogger,
);
} on Exception catch (error) {
throwToolExit(error.toString());

View File

@ -747,7 +747,7 @@ class AppDomain extends Domain {
enableHotReload,
cwd,
LaunchMode.run,
asLogger<AppRunLogger>(globals.logger),
asLogger<MachineOutputLogger>(globals.logger),
);
}
@ -759,7 +759,7 @@ class AppDomain extends Domain {
bool enableHotReload,
Directory cwd,
LaunchMode launchMode,
AppRunLogger logger,
MachineOutputLogger logger,
) async {
final app = AppInstance(
_getNewAppId(),
@ -771,8 +771,8 @@ class AppDomain extends Domain {
// Set the domain and app for the given AppRunLogger. This allows the logger
// to log messages containing the app ID to the host.
logger.domain = this;
logger.app = app;
logger._domain = this;
logger._app = app;
_sendAppEvent(app, 'start', <String, Object?>{
'deviceId': device.id,
@ -1549,13 +1549,13 @@ class AppInstance {
this.id, {
required this.runner,
this.logToStdout = false,
required AppRunLogger logger,
required MachineOutputLogger logger,
}) : _logger = logger;
final String id;
final ResidentRunner runner;
final bool logToStdout;
final AppRunLogger _logger;
final MachineOutputLogger _logger;
Future<OperationResult> restart({bool fullRestart = false, bool pause = false, String? reason}) {
return runner.restart(fullRestart: fullRestart, pause: pause, reason: reason);
@ -1773,21 +1773,13 @@ class ProxyDomain extends Domain {
..createSync();
}
/// A [Logger] which sends log messages to a listening daemon client.
///
/// This class can either:
/// 1) Send stdout messages and progress events to the client IDE
/// 1) Log messages to stdout and send progress events to the client IDE
//
// TODO(devoncarew): To simplify this code a bit, we could choose to specialize
// this class into two, one for each of the above use cases.
class AppRunLogger extends DelegatingLogger {
AppRunLogger({required Logger parent}) : super(parent);
/// A [Logger] which omits log messages to avoid breaking `--machine` formatting.
final class MachineOutputLogger extends DelegatingLogger {
MachineOutputLogger({required Logger parent}) : super(parent);
AppDomain? domain;
late AppInstance app;
AppDomain? _domain;
late final AppInstance _app;
var _nextProgressId = 0;
Status? _status;
@override
@ -1814,7 +1806,7 @@ class AppRunLogger extends DelegatingLogger {
}
void close() {
domain = null;
_domain = null;
}
void _sendProgressEvent({
@ -1823,13 +1815,7 @@ class AppRunLogger extends DelegatingLogger {
bool finished = false,
String? message,
}) {
if (domain == null) {
// If we're sending progress events before an app has started, send the
// progress messages as plain status messages.
if (message != null) {
printStatus(message);
}
} else {
if (_domain case final domain?) {
final event = <String, Object?>{
'id': eventId,
'progressId': eventType,
@ -1837,16 +1823,14 @@ class AppRunLogger extends DelegatingLogger {
'finished': finished,
};
domain!._sendAppEvent(app, 'progress', event);
domain._sendAppEvent(_app, 'progress', event);
}
}
@override
void sendEvent(String name, [Map<String, Object?>? args, List<int>? binary]) {
if (domain == null) {
printStatus('event sent after app closed: $name');
} else {
domain!.sendEvent(name, args, binary);
if (_domain case final domain?) {
domain.sendEvent(name, args, binary);
}
}

View File

@ -539,7 +539,7 @@ void main() {
FileSystem: () => fs,
ProcessManager: () => FakeProcessManager.any(),
Stdio: () => FakeStdio(),
Logger: () => AppRunLogger(parent: logger),
Logger: () => MachineOutputLogger(parent: logger),
},
);
@ -565,7 +565,7 @@ void main() {
FileSystem: () => fs,
ProcessManager: () => FakeProcessManager.any(),
Stdio: () => FakeStdio(),
Logger: () => AppRunLogger(parent: logger),
Logger: () => MachineOutputLogger(parent: logger),
},
);
});

View File

@ -99,7 +99,7 @@ void main() {
daemon: false,
windows: false,
),
isA<AppRunLogger>(),
isA<MachineOutputLogger>(),
);
});
@ -249,7 +249,7 @@ void main() {
expect(asLogger<VerboseLogger>(notifyingLogger), verboseLogger);
expect(asLogger<FakeLogger>(notifyingLogger), fakeLogger);
expect(() => asLogger<AppRunLogger>(notifyingLogger), throwsStateError);
expect(() => asLogger<MachineOutputLogger>(notifyingLogger), throwsStateError);
});
group('AppContext', () {
@ -796,13 +796,13 @@ void main() {
expect(lines[3], equals('0123456789' * 3));
});
testWithoutContext('AppRunLogger writes plain text statuses when no app is active', () async {
testWithoutContext('MachineFlagLogger does not output text statuses', () async {
final buffer = BufferLogger.test();
final logger = AppRunLogger(parent: buffer);
final logger = MachineOutputLogger(parent: buffer);
logger.startProgress('Test status...').stop();
expect(buffer.statusText.trim(), equals('Test status...'));
expect(buffer.statusText, isEmpty);
});
testWithoutContext('Error logs are wrapped and can be indented.', () async {