Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion flutter-candidate.txt
Copy link
Member Author

@elliette elliette Oct 1, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the latest candidate in g3. It contains flutter/flutter#155846 which is required so that we can pull in the latest version of package:stack_trace

Original file line number Diff line number Diff line change
@@ -1 +1 @@
b05246d305ac94798ca5429754917c0afa92fd9b
5dff2b54f93ebbc5e711b5fc68d52cd275be9b07
87 changes: 80 additions & 7 deletions packages/devtools_app/lib/src/framework/app_error_handling.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,14 @@
// found in the LICENSE file.

import 'dart:async';
import 'dart:convert';

import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
import 'package:http/http.dart';
import 'package:logging/logging.dart';
import 'package:source_map_stack_trace/source_map_stack_trace.dart';
import 'package:source_maps/source_maps.dart';
import 'package:stack_trace/stack_trace.dart' as stack_trace;

import '../shared/analytics/analytics.dart' as ga;
Expand All @@ -26,10 +30,11 @@ void setupErrorHandling(Future Function() appStartCallback) {
// First, run all our code in a new zone.
unawaited(
runZonedGuarded<Future<void>>(
// ignore: avoid-passing-async-when-sync-expected this ignore should be fixed.
() {
() async {
WidgetsFlutterBinding.ensureInitialized();

await _initializeSourceMapping();

final FlutterExceptionHandler? oldHandler = FlutterError.onError;

FlutterError.onError = (FlutterErrorDetails details) {
Expand Down Expand Up @@ -70,13 +75,29 @@ void reportError(
bool notifyUser = false,
StackTrace? stack,
}) {
stack = stack ?? StackTrace.empty;

final terseStackTrace = stack_trace.Trace.from(stack).terse.toString();
unawaited(
_reportError(
error,
errorType: errorType,
notifyUser: notifyUser,
stack: stack,
).catchError((_) {
// Ignore errors.
}),
);
}

_log.severe('[$errorType]: ${error.toString()}', error, stack);
Future<void> _reportError(
Object error, {
String errorType = 'DevToolsError',
bool notifyUser = false,
StackTrace? stack,
}) async {
final terseStackTrace = await _mapAndTersify(stack);
final errorMessage = '$error\n$terseStackTrace';

ga.reportError('$error\n$terseStackTrace');
_log.severe('[$errorType]: $errorMessage', error, stack);
ga.reportError(errorMessage);

// Show error message in a notification pop-up:
if (notifyUser) {
Expand All @@ -86,3 +107,55 @@ void reportError(
);
}
}

SingleMapping? _cachedJsSourceMapping;
SingleMapping? _cachedWasmSourceMapping;

Future<SingleMapping?> _fetchSourceMapping() async {
final cachedSourceMapping = preferences.wasmEnabled.value
? _cachedWasmSourceMapping
: _cachedJsSourceMapping;

return cachedSourceMapping ?? (await _initializeSourceMapping());
}

Future<SingleMapping?> _initializeSourceMapping() async {
try {
final wasmEnabled = preferences.wasmEnabled.value;
final sourceMapUri = Uri.parse(
'main.dart.${wasmEnabled ? 'wasm' : 'js'}.map',
);
final sourceMapFile = await get(sourceMapUri);

return SingleMapping.fromJson(
jsonDecode(sourceMapFile.body),
mapUrl: sourceMapUri,
);
} catch (_) {
// Ignore any errors loading the source map.
return Future.value();
}
}

Future<String> _mapAndTersify(StackTrace? stack) async {
final originalStackTrace = stack;
if (originalStackTrace == null) return '';

final mappedStackTrace = await _maybeMapStackTrace(originalStackTrace);
// If mapping fails, revert back to the original source map:
final stackTrace = mappedStackTrace.toString().isEmpty
? originalStackTrace
: mappedStackTrace;
return stack_trace.Trace.from(stackTrace).terse.toString();
}

Future<StackTrace> _maybeMapStackTrace(StackTrace stack) async {
final sourceMapping = await _fetchSourceMapping();
return sourceMapping != null
? mapStackTrace(
sourceMapping,
stack,
minified: true,
)
: stack;
}
4 changes: 3 additions & 1 deletion packages/devtools_app/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,10 @@ dependencies:
provider: ^6.0.2
# Only used for debug mode logic.
shared_preferences: ^2.0.15
source_map_stack_trace: ^2.1.2
source_maps: ^0.10.12
sse: ^4.1.2
stack_trace: ^1.10.0
stack_trace: ^1.12.0
stream_channel: ^2.1.1
string_scanner: ^1.1.0
unified_analytics: ^6.1.3
Expand Down
3 changes: 3 additions & 0 deletions packages/devtools_app/release_notes/NEXT_RELEASE_NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ show. - [#8277](https://github.com/flutter/devtools/pull/8277)
* Added support for loading extensions in pub workspaces
[8347](https://github.com/flutter/devtools/pull/8347).

* Mapped error stacktraces to use the Dart sourcecode locations so that they are human-
readable. - [#8385](https://github.com/flutter/devtools/pull/8385)

## Inspector updates

- Added a setting to the Flutter Inspector controls that allows users to opt-in to the newly redesigned Flutter Inspector. - [#8342](https://github.com/flutter/devtools/pull/8342)
Expand Down
1 change: 1 addition & 0 deletions tool/build_release.sh
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ rm -rf build/web
flutter pub get

flutter build web \
--source-maps \
--wasm \
--pwa-strategy=offline-first \
--release \
Expand Down
1 change: 1 addition & 0 deletions tool/lib/commands/build.dart
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ class BuildCommand extends Command {
[
'build',
'web',
'--source-maps',
if (useWasm) ...[
BuildCommandArgs.wasm.asArg(),
if (noStripWasm) BuildCommandArgs.noStripWasm.asArg(),
Expand Down