Skip to content

Commit cdc6e60

Browse files
authored
feat(symbolication): upload dart symbol mapping file (#347)
* Initial impl * Initial impl * Initial impl * Update * Update * Fix * Update * Update * Update * Update * Update * Update * Update * Update * Optimize * Update * Update * Remove unnecessary file check * Review * Add missing test * Update tests * Update tests * Update tests * Update * Update * Update * Update * Updaet * Update * Update * Update * Update * Update * Update * Update * Update * Update cli_params.dart * Update dart_symbol_map.dart * Update tests * Fix * Update * Update * Update * Run tests * Add marker * Update * Update * Update * Update * Update * Update * Update * Update * Update * Update * Update * Update * Update * Update * Update * Update * Update * Update CHANGELOG * Update CHANGELOG * Update * Update * Update * Update * Update * Update * Update * Update * Update * Update docs * Fix tests * Update CHANGELOG * Update * Update test * Remove duplicate * Cursor review * Update marker * Update comment * Review * Update CI * Update * Update * Update * Update
1 parent fb06747 commit cdc6e60

19 files changed

Lines changed: 1090 additions & 85 deletions

.github/workflows/integration-test.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ jobs:
5858
path: temp/testapp-${{ matrix.target }}
5959
key: integration-test-${{ matrix.host }}-${{ matrix.target }}-${{ hashFiles('flutter.version') }}
6060

61+
- run: sudo xcode-select --switch /Applications/Xcode_16.4.app
62+
if: ${{ matrix.target == 'ios' || matrix.target == 'ios-framework' || matrix.target == 'ipa' }}
63+
6164
- run: dart test --tags integration
6265

6366
- uses: actions/upload-artifact@v4

CHANGELOG.md

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,15 @@
22

33
## Unreleased
44

5-
### Dependencies
5+
### Features
66

7-
- Bump CLI from v2.41.1 to v2.52.0 ([#327](https://github.com/getsentry/sentry-dart-plugin/pull/327))
8-
- [changelog](https://github.com/getsentry/sentry-cli/blob/master/CHANGELOG.md#2520)
9-
- [diff](https://github.com/getsentry/sentry-cli/compare/2.41.1...2.52.0)
7+
- Upload Dart symbol mapping file ([#347](https://github.com/getsentry/sentry-dart-plugin/pull/347))
8+
- Enables symbolication of Flutter issue titles for obfuscated builds.
9+
- Supported: Android and iOS
10+
- Not supported (yet): macOS, Linux and Windows.
11+
- Generate the mapping file: Add `--extra-gen-snapshot-options=--save-obfuscation-map=<path>` when building. Example: `flutter build apk --obfuscate --split-debug-info=build/symbols --extra-gen-snapshot-options=--save-obfuscation-map=build/mapping.json`
12+
- Configure the plugin: Set `dart_symbol_map_path: build/mapping.json`
13+
- Important: `dart_symbol_map_path` must point directly to the mapping file (absolute or relative path), not a directory.
1014

1115
## 3.1.1
1216

README.md

Lines changed: 33 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,12 @@ sentry:
5757
build_path: ...
5858
web_build_path: ...
5959
symbols_path: ...
60+
# Path to the Dart obfuscation map (opt-in)
61+
# Example generation flags:
62+
# flutter build apk --obfuscate --split-debug-info=symbols \\
63+
# --extra-gen-snapshot-options=--save-obfuscation-map=build/app/obfuscation.map.json
64+
# Then set the path below to the generated obfuscation map file
65+
dart_symbol_map_path: build/app/obfuscation.map.json
6066
commits: auto
6167
ignore_missing: true
6268
```
@@ -95,30 +101,31 @@ ignore_missing=true
95101

96102
### Available Configuration Fields
97103

98-
| Configuration Name | Description | Default Value And Type | Required | Alternative Environment variable |
99-
| - | - | - | - | - |
100-
| upload_debug_symbols | Enables or disables the automatic upload of debug symbols | true (boolean) | no | - |
101-
| upload_source_maps | Enables or disables the automatic upload of source maps | false (boolean) | no | - |
102-
| upload_sources | Does or doesn't include the source code of native code | false (boolean) | no | - |
103-
| legacy_web_symbolication | Uses legacy symbolication method for Flutter Web instead of Debug IDs | false (boolean) | no | - |
104-
| project | Project's name | e.g. sentry-flutter (string) | yes | SENTRY_PROJECT |
105-
| org | Organization's slug | e.g. sentry-sdks (string) | yes | SENTRY_ORG |
106-
| auth_token | Auth Token | e.g. 64 random characteres (string) | yes | SENTRY_AUTH_TOKEN |
107-
| url | URL | e.g. https<area>://mysentry.invalid/ (string) | no | SENTRY_URL |
108-
| url_prefix | URL prefix for JS source maps | e.g. ~/app/ (string) | no | - |
109-
| wait_for_processing | Wait for server-side processing of uploaded files | false (boolean) | no | - |
110-
| log_level | Configures the log level for sentry-cli | warn (string) | no | SENTRY_LOG_LEVEL |
111-
| release | The release version for source maps, it should match the release set by the SDK | name@version from pubspec (string) | no | SENTRY_RELEASE |
112-
| dist | The dist/build number for source maps, it should match the dist set by the SDK | the number after the '+' char from 'version' pubspec (string) | no | SENTRY_DIST |
113-
| build_path | The build folder of debug files for upload | `build` (string) | no | - |
114-
| web_build_path | The web build folder of debug files for upload relative to build_path | `web` (string) | no | - |
115-
| symbols_path | The directory containing debug symbols (i.e. the `--split-debug-info=` parameter value you pass to `flutter build`) | `.` (string) | no | - |
116-
| commits | Release commits integration | auto (string) | no | - |
117-
| ignore_missing | Ignore missing commits previously used in the release | false (boolean) | no | - |
118-
| bin_dir | The folder where the plugin downloads the sentry-cli binary | .dart_tool/pub/bin/sentry_dart_plugin (string) | no | - |
119-
| bin_path | Path to the sentry-cli binary to use instead of downloading. Make sure to use the correct version. | null (string) | no | - |
120-
| sentry_cli_cdn_url | Alternative place to download sentry-cli | https://downloads.sentry-cdn.com/sentry-cli (string) | no | SENTRYCLI_CDNURL |
121-
| sentry_cli_version | Override the sentry-cli version that should be downloaded. | (string) | no | - |
104+
| Configuration Name | Description | Default Value And Type | Required | Alternative Environment variable |
105+
| ------------------------ |-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| ------------------------------------------------------------- | -------- | -------------------------------- |
106+
| upload_debug_symbols | Enables or disables the automatic upload of debug symbols | true (boolean) | no | - |
107+
| upload_source_maps | Enables or disables the automatic upload of source maps | false (boolean) | no | - |
108+
| upload_sources | Does or doesn't include the source code of native code | false (boolean) | no | - |
109+
| legacy_web_symbolication | Uses legacy symbolication method for Flutter Web instead of Debug IDs | false (boolean) | no | - |
110+
| project | Project's name | e.g. sentry-flutter (string) | yes | SENTRY_PROJECT |
111+
| org | Organization's slug | e.g. sentry-sdks (string) | yes | SENTRY_ORG |
112+
| auth_token | Auth Token | e.g. 64 random characteres (string) | yes | SENTRY_AUTH_TOKEN |
113+
| url | URL | e.g. https<area>://mysentry.invalid/ (string) | no | SENTRY_URL |
114+
| url_prefix | URL prefix for JS source maps | e.g. ~/app/ (string) | no | - |
115+
| wait_for_processing | Wait for server-side processing of uploaded files | false (boolean) | no | - |
116+
| log_level | Configures the log level for sentry-cli | warn (string) | no | SENTRY_LOG_LEVEL |
117+
| release | The release version for source maps, it should match the release set by the SDK | name@version from pubspec (string) | no | SENTRY_RELEASE |
118+
| dist | The dist/build number for source maps, it should match the dist set by the SDK | the number after the '+' char from 'version' pubspec (string) | no | SENTRY_DIST |
119+
| build_path | The build folder of debug files for upload | `build` (string) | no | - |
120+
| web_build_path | The web build folder of debug files for upload relative to build_path | `web` (string) | no | - |
121+
| symbols_path | The directory containing debug symbols (i.e. the `--split-debug-info=` parameter value you pass to `flutter build`) | `.` (string) | no | - |
122+
| dart_symbol_map_path | Absolute or relative path to a Dart obfuscation map file to upload. This allows symbolication of Flutter issue titles for Android and iOS. The map file is generated by adding the following arguments to your Flutter build command: `--extra-gen-snapshot-options=--save-obfuscation-map=<path>`. | null (string) | no | - |
123+
| commits | Release commits integration | auto (string) | no | - |
124+
| ignore_missing | Ignore missing commits previously used in the release | false (boolean) | no | - |
125+
| bin_dir | The folder where the plugin downloads the sentry-cli binary | .dart_tool/pub/bin/sentry_dart_plugin (string) | no | - |
126+
| bin_path | Path to the sentry-cli binary to use instead of downloading. Make sure to use the correct version. | null (string) | no | - |
127+
| sentry_cli_cdn_url | Alternative place to download sentry-cli | https://downloads.sentry-cdn.com/sentry-cli (string) | no | SENTRYCLI_CDNURL |
128+
| sentry_cli_version | Override the sentry-cli version that should be downloaded. | (string) | no | - |
122129

123130
## Breaking Changes in v3.0.0
124131

@@ -200,4 +207,6 @@ The `--split-debug-info` option requires setting a output directory, the directo
200207

201208
Flutter's `build web` command requires setting the `--source-maps` parameter to generate source maps, See [Issue](https://github.com/flutter/flutter/issues/72150#issuecomment-755541599)
202209

210+
If you opt into uploading a Dart obfuscation map (`dart_symbol_map_path`), ensure you build with both `--obfuscate` and `--extra-gen-snapshot-options=--save-obfuscation-map=<path>`. The map path you configure must point to the generated file.
211+
203212
If a previous release could not be found in the git history, please make sure you set `ignore_missing: true` in the configuration if you want to ignore such errors, See [Issue](https://github.com/getsentry/sentry-dart-plugin/issues/153)

lib/sentry_dart_plugin.dart

Lines changed: 23 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@ import 'dart:convert';
22

33
import 'package:file/file.dart';
44
import 'package:process/process.dart';
5-
import 'package:sentry_dart_plugin/src/utils/extensions.dart';
65

76
import 'src/configuration.dart';
7+
import 'src/utils/flutter_debug_files.dart';
8+
import 'src/symbol_maps/dart_symbol_map.dart';
89
import 'src/utils/injector.dart';
910
import 'src/utils/log.dart';
11+
import 'src/utils/extensions.dart';
1012

1113
/// Class responsible to load the configurations and upload the
1214
/// debug symbols and source maps
@@ -86,7 +88,8 @@ class SentryDartPlugin {
8688
_addWait(params);
8789

8890
final fs = injector.get<FileSystem>();
89-
final debugSymbolPaths = _enumerateDebugSymbolPaths(fs);
91+
final debugSymbolPaths =
92+
enumerateDebugSearchRoots(fs: fs, config: _configuration);
9093
await for (final path in debugSymbolPaths) {
9194
if (await fs.directory(path).exists() || await fs.file(path).exists()) {
9295
await _executeAndLog('Failed to upload symbols', [...params, path]);
@@ -97,59 +100,9 @@ class SentryDartPlugin {
97100
await _executeAndLog('Failed to upload symbols', [...params, path]);
98101
}
99102

100-
Log.taskCompleted(taskName);
101-
}
102-
103-
Stream<String> _enumerateDebugSymbolPaths(FileSystem fs) async* {
104-
final buildDir = _configuration.buildFilesFolder;
105-
final projectRoot = fs.currentDirectory.path;
106-
107-
// Android (apk, appbundle)
108-
yield '$buildDir/app/outputs';
109-
yield '$buildDir/app/intermediates';
110-
111-
// Windows
112-
for (final subdir in ['', '/x64', '/arm64']) {
113-
yield '$buildDir/windows$subdir/runner/Release';
114-
}
115-
// TODO we should delete this once we have windows symbols collected automatically.
116-
// Related to https://github.com/getsentry/sentry-dart-plugin/issues/173
117-
yield 'windows/flutter/ephemeral/flutter_windows.dll.pdb';
118-
119-
// Linux
120-
for (final subdir in ['/x64', '/arm64']) {
121-
yield '$buildDir/linux$subdir/release/bundle';
122-
}
123-
124-
// macOS
125-
yield '$buildDir/macos/Build/Products/Release';
126-
127-
// macOS (macOS-framework)
128-
yield '$buildDir/macos/framework/Release';
129-
130-
// iOS
131-
yield '$buildDir/ios/iphoneos/Runner.app';
132-
if (await fs.directory('$buildDir/ios').exists()) {
133-
final regexp = RegExp(r'^Release(-.*)?-iphoneos$');
134-
yield* fs
135-
.directory('$buildDir/ios')
136-
.list()
137-
.where((v) => regexp.hasMatch(v.basename))
138-
.map((e) => e.path);
139-
}
103+
await _tryUploadDartSymbolMap();
140104

141-
// iOS (ipa)
142-
yield '$buildDir/ios/archive';
143-
144-
// iOS (ios-framework)
145-
yield '$buildDir/ios/framework/Release';
146-
147-
// iOS in Fastlane
148-
if (projectRoot == '/') {
149-
yield 'ios/build';
150-
} else {
151-
yield '$projectRoot/ios/build';
152-
}
105+
Log.taskCompleted(taskName);
153106
}
154107

155108
Future<Set<String>> _enumerateSymbolFiles() async {
@@ -194,6 +147,22 @@ class SentryDartPlugin {
194147
return params;
195148
}
196149

150+
/// Upload Dart symbol map(s) if configured.
151+
/// This is needed to symbolicate Flutter issue titles for obfuscated builds.
152+
Future<void> _tryUploadDartSymbolMap() async {
153+
const taskName = 'uploading Dart symbol map(s)';
154+
Log.startingTask(taskName);
155+
156+
try {
157+
final fs = injector.get<FileSystem>();
158+
await uploadDartSymbolMap(fs: fs, config: _configuration);
159+
} catch (e) {
160+
Log.error('Dart symbol map upload failed: $e');
161+
} finally {
162+
Log.taskCompleted(taskName);
163+
}
164+
}
165+
197166
Future<void> _executeNewRelease(String release) async {
198167
await _executeAndLog('Failed to create a new release',
199168
[..._releasesCliParams(), 'new', release]);

0 commit comments

Comments
 (0)