sentry-dart
sentry-dart copied to clipboard
Improve support for Flutter Web
- [X] Support tracingOrigins for performance feature - replaced by
tracePropagationTargets
- [X] Add Flutter web renderer information to event
- [x] Support allowUrls , denyUrls and ignoreErrors (InboundFilters)
- [ ] Breadcrumbs and spans for fetch/xmlhttprequest thru the JS SDK
- [ ] Support for tunnel parameter
- [ ] Native JS error handler thru the JS SDK
- [ ] Web vitals thru the JS SDK
- [ ] Sessions thru the JS SDK
- [ ] Support WASM with Dart 3, Article.
- [X] Improve stack trace symbolication, related issue.
- [ ] Read buildNumber and buildName (and use as release/dist)
- [ ] Migrate source maps to use the new debug id - https://github.com/dart-lang/sdk/issues/53027
- [ ] Demangle runtime types
- [ ] Support for apps loaded as Chrome extension
Likely more improvements can be made.
Breadcrumbs and spans for fetch/xmlhttprequest
This should not create duplicates when used together with the http
or dio
integrations.
https://trends.builtwith.com/websitelist/Flutter
https://trends.builtwith.com/websitelist/Dart
https://github.com/dart-lang/source_map_stack_trace/tree/master might be something to look at in case JS stack traces are not so user-friendly, we could do something similar on the Server, well, we already symbolicate it but not sure if this library does something different than us.
https://github.com/dart-lang/source_map_stack_trace/tree/master might be something to look at in case JS stack traces are not so user-friendly, we could do something similar on the Server, well, we already symbolicate it but not sure if this library does something different than us.
Demo App Code
import 'package:flutter/material.dart';
import 'package:sentry_flutter/sentry_flutter.dart';
void main() {
SentryFlutter.init(
(options) {
options.dsn =
'https://[email protected]/4504991898140672';
},
appRunner: () => runApp(const MainApp()),
);
}
class MainApp extends StatelessWidget {
const MainApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: ElevatedButton(
onPressed: () {
throw Exception('Test exception');
},
child: const Text('Hello World!'),
),
),
),
);
}
}
This is how Sentry deobfuscates the stack trace for the error thrown in the demo app:

Using source_map_stack_trace
to deobfuscate the stack trace yields the following:
../../../lib/main.dart 24:15 MainApp.build.<anonymous function>
../../../../../../fvm/versions/stable/packages/flutter/lib/src/widgets/framework.dart 921:26 _InkResponseState.handleTap
org-dartlang-sdk:///lib/_internal/js_runtime/lib/js_helper.dart 2105:9 Closure.cspForwardCall
../../../../../../fvm/versions/stable/packages/flutter/lib/src/gestures/recognizer.dart 253:16 GestureRecognizer.invokeCallback
../../../../../../fvm/versions/stable/packages/flutter/lib/src/gestures/recognizer.dart 239:6 GestureRecognizer.invokeCallback[function-entry$2]
../../../../../../fvm/versions/stable/packages/flutter/lib/src/gestures/tap.dart 627:11 TapGestureRecognizer.handleTapUp
../../../../../../fvm/versions/stable/packages/flutter/lib/src/gestures/tap.dart 306:5 BaseTapGestureRecognizer._checkUp
../../../../../../fvm/versions/stable/packages/flutter/lib/src/gestures/tap.dart 239:7 BaseTapGestureRecognizer.handlePrimaryPointer
../../../../../../fvm/versions/stable/packages/flutter/lib/src/gestures/recognizer.dart 615:9 PrimaryPointerGestureRecognizer.handleEvent
source_map_stack_trace
seems to be able to fully restore function names for each frame, whereas Sentry currently is not. I would love to see support for that and be happy to help with a pointer to where to start.
@blaugold can you provide a minimal reproducible example? (with build commands, upload source maps command, etc). Every time I test a sample app (Flutter web), symbolication works just fine. If that's indeed the case, I'd consider it a bug, and raise a new issue, I can do that if that's the case.
Flutter version:
Flutter 3.7.12 • channel stable • https://github.com/flutter/flutter.git
Framework • revision 4d9e56e694 (3 weeks ago) • 2023-04-17 21:47:46 -0400
Engine • revision 1a65d409c7
Tools • Dart 2.19.6 • DevTools 2.20.1
-
flutter create sentry_flutter_web_stacktraces_repro
-
cd sentry_flutter_web_stacktraces_repro
-
flutter pub add sentry_flutter
-
Replace
lib/main.dart
with the following:void main() { SentryFlutter.init( (options) { options.dsn = '...'; }, appRunner: () => runApp(const MainApp()), ); } class MainApp extends StatelessWidget { const MainApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( body: Center( child: ElevatedButton( onPressed: () { throw Exception('Test exception'); }, child: const Text('Throw exception'), ), ), ), ); } }
-
Configure DSN in
main.dart
-
flutter build web --source-maps
-
sentry-cli sourcemaps upload -o ... -p ... -r [email protected]+1 -d 1 build/web
-
cd build/web
-
caddy file-server
: Start a web server to serve the files. -
Open
http://localhost:80
: Open the web app in a browser, wherever it is served. -
Click on the "Throw exception" button
-
This is what the raw but deobfuscated stack trace looks like in Sentry:
minified:Gi: Exception: Test exception at A.c(org-dartlang-sdk:///lib/_internal/js_runtime/lib/js_helper.dart:1128:37) at A.Tt.prototype.$0(../../../lib/main.dart:24:15) at A.v6.prototype.Em(../../../../../../fvm/versions/stable/packages/flutter/lib/src/widgets/framework.dart:921:26) at A.akv(org-dartlang-sdk:///lib/_internal/js_runtime/lib/js_helper.dart:2105:9) at A.cN.prototype.EC(../../../../../../fvm/versions/stable/packages/flutter/lib/src/gestures/recognizer.dart:253:16) at A.cN.prototype.fG(../../../../../../fvm/versions/stable/packages/flutter/lib/src/gestures/recognizer.dart:239:6) at A.fA.prototype.Eo(../../../../../../fvm/versions/stable/packages/flutter/lib/src/gestures/tap.dart:627:11) at A.xl.prototype.zd(../../../../../../fvm/versions/stable/packages/flutter/lib/src/gestures/tap.dart:306:5) at A.xl.prototype.El(../../../../../../fvm/versions/stable/packages/flutter/lib/src/gestures/tap.dart:239:7) at A.nF.prototype.i4(../../../../../../fvm/versions/stable/packages/flutter/lib/src/gestures/recognizer.dart:615:9)
@blaugold can you try using the https://github.com/getsentry/sentry-dart-plugin plugin instead of calling sentry-cli manually? Just wanna be sure that all the configuration is correct. The plugin uses different commands than yours, maybe it's related to that. Also, link me to a sentry.io event so I can check myself as well. Btw feel free to raise a new issue about that, so we can avoid the back and forth there, which is a slightly different topic, it'd be a bug if there's something broken.
Flutter web has this option in the build cmd:
--build-number An identifier used as an internal version number. Each build must have a unique identifier to differentiate it from previous builds. It is used to determine whether one build is more recent than another, with higher numbers indicating more recent build. On Android it is used as "versionCode". On Xcode builds it is used as "CFBundleVersion". On Windows it is used as the build suffix for the product and file versions. --build-name=<x.y.z> A "x.y.z" string used as the version number shown to users. For each new version of your app, you will provide a version number to differentiate it from previous versions. On Android it is used as "versionName". On Xcode builds it is used as "CFBundleShortVersionString". On Windows it is used as the major, minor, and patch parts of the product and file versions.
If its set, we could use it as release/dist, instead of the pubspec file?
Duplicate of this with some context/rationale: https://github.com/getsentry/sentry-dart/issues/1661
What's the status of this item so far?
@alestiago hi, anything specific you are looking for in the list?
I'm also interested in updates here. My biggest issue is that the error information is minified, even if I upload debug symbols from Flutter using sentry_dart_plugin. I am uploading the symbols using sentry_dart_plugin and I see that the symbols are accepted and connected to my release when I check in sentry.io web portal.
When I run Flutter Web in release mode it presents alot of minified names, like this:
minified:am
ReferenceError: Can't find variable: a9
However, I can see relevant dart code in the stack trace even though the file paths are messy too.
If I switch to profile mode I get much nicer exceptions, the errors looks like this (with corret types, variable names etc)
_Exception
Exception: simulated locally (async)
Issue #1661 also describes this problem in a good way, but it's closed as a duplicate of this.
I guess that my main problem is the last checkbox, "demangle runtime types": https://github.com/getsentry/symbolic/issues/807 I'm not sure but I think that the second to last checkbox is relevant too: https://github.com/getsentry/team-mobile/issues/133 + https://github.com/dart-lang/sdk/issues/53027
thanks for the details. we'll discuss this and see if we can have some bandwidth soon to work on this.
I'm experiencing the same issue as @mikeesouth . Despite uploading source maps with the Sentry Dart plugin, my web stack traces remain minified. Is there a configuration step I'm missing, or is web source map support not yet implemented?
@Fraa-124 source maps are supported for Flutter Web, but with some limitations as discussed above
I also have same issue https://stackoverflow.com/questions/78290786/flutter-web-sentry-did-not-translate-correctly-issues/78291321#78291321
Is there a solution yet? @buenaflor. I keep getting this instead of dart source codes.
This ticket is 2 years old and it doesn't look promising in the thread. IMO it should be the top priority if you are to support Flutter web, I am surprised this takes so long. Right now we have around 50% of 'minified' issues and I am doubting my choice to use Sentry for our flutter product.
At least include some warning in the documentation about this limitation!
Hey, we totally understand the frustration and are sorry about the delay of this issue.
What should work:
- seeing the not minified stacktrace
What doesn't work:
- issue titles are still minified (that's one of the task in improving flutter web)
So (in theory) the stacktrace should not be minified in the issues. We'll take a look at that @denrase
At least include some warning in the documentation about this limitation!
You're right, thanks for pointing that out, we will add more visibility on current flutter web limitations to our docs
@buenaflor Please just in case I am wrong. Could you give the steps required to get the "What should work:" to work?
We are trying to use sentry on Crx(Flutter Web) to record exceptions, It does that but returns minified stacktraces. To solve this, we uploaded sourcemaps after making build (with the --sourcemaps in the build command) using the sentry_dart_plugin.
It shows on sentry that sourcemaps were uploaded successfully but we still don't see dart code in exception stacktraces.
After this exceptions show minified:kP (minified:a_P at times) instead of the exception types but the stacktraces are still not readable.
Is there any work around to get dart code or are we missing any step?
PS: We also tried to use sentry cli and manually upload the source code after injecting debug-ids but got similar results
Minimal Setup
Below is a minimal setup + steps that show working stack traces + inline dart code for minified code from a flutter web application, build with the release flag.
The app only has one button, which throws an exception. This is then captured using Sentry.
We use the sentry dart plugin to upload all files needed. It will create a release from the name and version in pubspec.yaml. Since we also have a build number, it will take it as dist
. The release name will be name@version
, with dist
parameter taken from the build 4
from the version:
pubspec.yaml
name: calculator
version: 1.0.3+4
dependencies:
sentry_flutter: ^7.18.0
dev_dependencies:
sentry_dart_plugin: ^1.7.1
sentry:
upload_debug_symbols: true
upload_source_maps: true
project: ... # In this sample the project name is also `calculator`
org: ...
auth_token: ...
wait_for_processing: true
log_level: info
commits: false
ignore_missing: true
Setup & Throwing Code
I added another class in a separate file to see if source mapping works in this case.
main.js
:
Future<void> main() async {
await SentryFlutter.init(
(options) {
options.dsn = '... your dsn ...';
options.tracesSampleRate = 1.0;
},
appRunner: () => runApp(const MyApp()),
);
}
void _throwAnException() {
try {
Helper().aThrowingFunction("paramA", true);
} catch (e, s) {
Sentry.captureException(e, stackTrace: s);
}
}
helper.js
:
class Helper {
void aThrowingFunction(String paramA, bool paramB) {
throw Exception('Only throwing this to test Sentry with paramA $paramA and paramB $paramB.');
}
}
Build & Upload
flutter build web --release --source-maps
dart run sentry_dart_plugin
This will then uplaod your source maps, and you see something like this output:
> Found 8 files
> Analyzing 8 sources
> Rewriting sources
> Adding source map references
> Bundled 8 files for upload
> Bundle ID: ec34b239-c576-57b3-a52a-c77151208c35
> Uploaded files to Sentry
> File processing complete
> Organization: denrase
> Project: calculator
> Release: [email protected]+4
> Dist: 4
> Upload type: artifact bundle
Source Map Upload Report
Scripts
~/flutter_service_worker.js
Minified Scripts
~/canvaskit/canvaskit.js (sourcemap at ../main.dart.js.map)
~/canvaskit/chromium/canvaskit.js (sourcemap at ../../main.dart.js.map)
~/canvaskit/skwasm.js (sourcemap at ../main.dart.js.map)
~/canvaskit/skwasm.worker.js (sourcemap at ../main.dart.js.map)
~/flutter.js (sourcemap at flutter.js.map)
~/main.dart.js (sourcemap at main.dart.js.map)
Source Maps
~/main.dart.js.map
Run Web Server
I used python http.server
webserver to run the flutter application.
cd build/web
python3 -m http.server
Click the UI element that throws/captures the exception.
Results
Exception
It should the stack trace and also the dart code.
Source Maps
We should see that the js files, minifier main.js
& source map main.js.map
are uploaded in the projects settings.
List | Artifacts | Artifacts 2 |
---|---|---|
Is this expected to behave differently if the flutter web app is loaded as a chrome extension? Because with the same steps you outlined I am getting this with a lot of missing source issues @denrase @buenaflor
Is this expected to behave differently if the flutter web app is loaded as a chrome extension? Because with the same steps you outlined I am getting this with a lot of missing source issues @denrase @buenaflor
![]()
![]()
I have same issue https://stackoverflow.com/questions/78290786/flutter-web-sentry-did-not-translate-correctly-issues/78291321#78291321
@EmmanuelAdeiza yes, it's expected to work differently when loaded as Chrome extension, and we didn't specifically add support for this - I added an item to the tasklist on top.