Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
@@ -1 +1 @@
b05246d305ac94798ca5429754917c0afa92fd9b
5dff2b54f93ebbc5e711b5fc68d52cd275be9b07
85 changes: 78 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,53 @@ void reportError(
);
}
}

SingleMapping? _cachedJsSourceMapping;
SingleMapping? _cachedWasmSourceMapping;

Future<SingleMapping?> _fetchSourceMapping() async {
final cachedSourceMapping =
kIsWasm ? _cachedWasmSourceMapping : _cachedJsSourceMapping;

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

Future<SingleMapping?> _initializeSourceMapping() async {
try {
final sourceMapUri = Uri.parse(
'main.dart.${kIsWasm ? '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 null;
}
}

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 stack trace:
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 source code 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