[flutter_tools] Fix encoded stderr in "dart.log" from debug adapter to client (#155249)
To aid debugging, debug adapter (DAP) clients can ask the debug adapters to send verbose logs back to the client (so they can capture them in a client-side log along with other things happening on the client). Included in this log is the `stderr` output of the `flutter run` process spawned by the debug adapter. This output was not decoded correctly for these logs, so showed up like: ``` [Flutter] [stderr] [91, 32, 32, 43, 49, 52, 32, 109, 115, 93, 32, 67, 111, 117, 108, 100, 32, 110, 111, 116, 32, 102, 105, 110, 100, 32, 97, 110, 32, 111, 112, 116, 105, 111, 110, 32, 110, 97, 109, 101, 100, 32, 34, 105, 110, 118, 97, 108, 105, 100, 34, 46, 10, 10, 91, 32, 32, 32, 32, 32, 32, 32, 32, 93, 32, 82, 117, 110, 32, 39, 102, 108, 117, 116, 116, 101, 114, 32, 45, 104, 39, 32, 40, 111, 114, 32, 39, 102, 108, 117, 116, 116, 101, 114, 32, 60, 99, 111, 109, 109, 97, 110, 100, 62, 32, 45, 104, 39, 41, 32, 102, 111, 114, 32, 97, 118, 97, 105, 108, 97, 98, 108, 101, 32, 102, 108, 117, 116, 116, 101, 114, 32, 99, 111, 109, 109, 97, 110, 100, 115, 32, 97, 110, 100, 32, 111, 112, 116, 105, 111, 110, 115, 46, 10] ``` This change decodes the output before processing. Fixes https://github.com/Dart-Code/Dart-Code/issues/5268 ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
This commit is contained in:
@@ -603,9 +603,9 @@ class FlutterDebugAdapter extends FlutterBaseDebugAdapter with VmServiceInfoFile
|
||||
}
|
||||
|
||||
@override
|
||||
void handleStderr(List<int> data) {
|
||||
void handleStderr(String data) {
|
||||
_logTraffic('<== [Flutter] [stderr] $data');
|
||||
sendOutput('stderr', utf8.decode(data));
|
||||
sendOutput('stderr', data);
|
||||
}
|
||||
|
||||
/// Handles stdout from the `flutter run --machine` process, decoding the JSON and calling the appropriate handlers.
|
||||
|
||||
@@ -11,6 +11,7 @@ import '../base/file_system.dart';
|
||||
import '../base/io.dart';
|
||||
import '../base/platform.dart';
|
||||
import '../cache.dart';
|
||||
import '../convert.dart';
|
||||
import 'flutter_adapter_args.dart';
|
||||
import 'mixins.dart';
|
||||
|
||||
@@ -150,11 +151,11 @@ abstract class FlutterBaseDebugAdapter extends DartDebugAdapter<FlutterLaunchReq
|
||||
this.process = process;
|
||||
|
||||
process.stdout.transform(ByteToLineTransformer()).listen(handleStdout);
|
||||
process.stderr.listen(handleStderr);
|
||||
process.stderr.transform(utf8.decoder).listen(handleStderr);
|
||||
unawaited(process.exitCode.then(handleExitCode));
|
||||
}
|
||||
|
||||
void handleExitCode(int code);
|
||||
void handleStderr(List<int> data);
|
||||
void handleStderr(String data);
|
||||
void handleStdout(String data);
|
||||
}
|
||||
|
||||
@@ -105,9 +105,9 @@ class FlutterTestDebugAdapter extends FlutterBaseDebugAdapter with TestAdapter {
|
||||
}
|
||||
|
||||
@override
|
||||
void handleStderr(List<int> data) {
|
||||
void handleStderr(String data) {
|
||||
logger?.call('stderr: $data');
|
||||
sendOutput('stderr', utf8.decode(data));
|
||||
sendOutput('stderr', data);
|
||||
}
|
||||
|
||||
/// Handles stdout from the `flutter test --machine` process, decoding the JSON and calling the appropriate handlers.
|
||||
|
||||
@@ -74,7 +74,7 @@ void main() {
|
||||
);
|
||||
});
|
||||
|
||||
testWithoutContext('logs to client when sendLogsToClient=true', () async {
|
||||
testWithoutContext('logs stdout to client when sendLogsToClient=true', () async {
|
||||
final BasicProject project = BasicProject();
|
||||
await project.setUpIn(tempDir);
|
||||
|
||||
@@ -107,6 +107,35 @@ void main() {
|
||||
);
|
||||
});
|
||||
|
||||
testWithoutContext('logs stderr to client when sendLogsToClient=true', () async {
|
||||
final BasicProject project = BasicProject();
|
||||
await project.setUpIn(tempDir);
|
||||
|
||||
// Capture all log events.
|
||||
final Future<List<Event>> logEventsFuture = dap.client.events('dart.log').toList();
|
||||
|
||||
// Launch the app and wait for it to terminate (because of the error).
|
||||
await Future.wait(<Future<void>>[
|
||||
dap.client.event('terminated'),
|
||||
dap.client.start(
|
||||
launch: () => dap.client.launch(
|
||||
cwd: project.dir.path,
|
||||
noDebug: true,
|
||||
toolArgs: <String>['--not-a-valid-flag'],
|
||||
sendLogsToClient: true,
|
||||
),
|
||||
),
|
||||
], eagerError: true);
|
||||
|
||||
// Ensure logs contain the expected error message.
|
||||
final List<Event> logEvents = await logEventsFuture;
|
||||
final List<String> logMessages = logEvents.map((Event l) => (l.body! as Map<String, Object?>)['message']! as String).toList();
|
||||
expect(
|
||||
logMessages,
|
||||
contains(startsWith('<== [Flutter] [stderr] Could not find an option named "not-a-valid-flag"')),
|
||||
);
|
||||
});
|
||||
|
||||
testWithoutContext('can run and terminate a Flutter app in noDebug mode', () async {
|
||||
final BasicProject project = BasicProject();
|
||||
await project.setUpIn(tempDir);
|
||||
|
||||
Reference in New Issue
Block a user