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: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
- Use `loadDebugImagesForAddresses` API for Android ([#2706](https://github.com/getsentry/sentry-dart/pull/2706))
- This reduces the envelope size and data transferred across method channels
- If debug images received by `loadDebugImagesForAddresses` are empty, the SDK loads all debug images as fallback
- Add Flutter runtime information ([#2742](https://github.com/getsentry/sentry-dart/pull/2742))
- This works if the version of Flutter you're using includes [this code](https://github.com/flutter/flutter/pull/140783).

### Fixes

Expand Down
77 changes: 77 additions & 0 deletions dart/lib/src/event_processor/enricher/flutter_runtime.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import '../../protocol/sentry_runtime.dart';

// The Flutter version information can be fetched via Dart defines,
// see https://github.com/flutter/flutter/pull/140783.
// This code lives in the Dart only Sentry code, since the code
// doesn't require any Flutter dependency.
// Additionally, this makes it work on background isolates in
// Flutter, where one may not initialize the whole Flutter Sentry
// SDK.

SentryRuntime? get flutterRuntime {
if (FlutterVersion.version == null ||
FlutterVersion.channel == null ||
FlutterVersion.frameworkRevision == null) {
return null;
}

return SentryRuntime(
name: 'Flutter',
version: '${FlutterVersion.version} (${FlutterVersion.channel})',
build: FlutterVersion.frameworkRevision,
);
}

SentryRuntime? get dartFlutterRuntime {
if (FlutterVersion.dartVersion == null) {
return null;
}

return SentryRuntime(
name: 'Dart',
version: FlutterVersion.dartVersion,
);
}

/// Details about the Flutter version this app was compiled with,
/// corresponding to the output of `flutter --version`.
///
/// When this Flutter version was build from a fork, or when Flutter runs in a
/// custom embedder, these values might be unreliable.
abstract class FlutterVersion {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Since this is code from your Flutter PR, would it also make sense to bring the corresponding tests over?

const FlutterVersion._();

/// The Flutter version used to compile the app.
static const String? version = bool.hasEnvironment('FLUTTER_VERSION')
? String.fromEnvironment('FLUTTER_VERSION')
: null;

/// The Flutter channel used to compile the app.
static const String? channel = bool.hasEnvironment('FLUTTER_CHANNEL')
? String.fromEnvironment('FLUTTER_CHANNEL')
: null;

/// The URL of the Git repository from which Flutter was obtained.
static const String? gitUrl = bool.hasEnvironment('FLUTTER_GIT_URL')
? String.fromEnvironment('FLUTTER_GIT_URL')
: null;
Comment on lines +53 to +56
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Should this be included in a context somewhere?


/// The Flutter framework revision, as a (short) Git commit ID.
static const String? frameworkRevision =
bool.hasEnvironment('FLUTTER_FRAMEWORK_REVISION')
? String.fromEnvironment('FLUTTER_FRAMEWORK_REVISION')
: null;

/// The Flutter engine revision.
static const String? engineRevision =
bool.hasEnvironment('FLUTTER_ENGINE_REVISION')
? String.fromEnvironment('FLUTTER_ENGINE_REVISION')
: null;

// This is included since [Platform.version](https://api.dart.dev/stable/dart-io/Platform/version.html)
// is not included on web platforms.
/// The Dart version used to compile the app.
static const String? dartVersion = bool.hasEnvironment('FLUTTER_DART_VERSION')
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

It's slightly different than Platform.version:

  • Platform.version: 3.8.0-133.0.dev (dev) (Sun Feb 23 12:02:50 2025 -0800) on "macos_x64"
  • FlutterVersion.dartVersion: 3.8.0 (build 3.8.0-133.0.dev)

? String.fromEnvironment('FLUTTER_DART_VERSION')
: null;
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import 'package:meta/meta.dart';

import '../../../sentry.dart';
import 'enricher_event_processor.dart';
import 'flutter_runtime.dart';
import 'io_platform_memory.dart';

EnricherEventProcessor enricherEventProcessor(SentryOptions options) {
Expand Down Expand Up @@ -63,12 +64,15 @@ class IoEnricherEventProcessor implements EnricherEventProcessor {
version: _dartVersion,
rawDescription: Platform.version,
);
final flRuntime = flutterRuntime;

if (runtimes == null) {
return [dartRuntime];
return [dartRuntime, if (flRuntime != null) flRuntime];
}
return [
...runtimes,
dartRuntime,
if (flRuntime != null) flRuntime,
];
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import 'package:web/web.dart' as web show window, Window, Navigator;

import '../../../sentry.dart';
import 'enricher_event_processor.dart';
import 'flutter_runtime.dart';

EnricherEventProcessor enricherEventProcessor(SentryOptions options) {
return WebEnricherEventProcessor(
Expand All @@ -29,6 +30,7 @@ class WebEnricherEventProcessor implements EnricherEventProcessor {
final contexts = event.contexts.copyWith(
device: _getDevice(event.contexts.device),
culture: _getSentryCulture(event.contexts.culture),
runtimes: _getRuntimes(event.contexts.runtimes),
);

contexts['dart_context'] = _getDartContext();
Expand Down Expand Up @@ -100,6 +102,23 @@ class WebEnricherEventProcessor implements EnricherEventProcessor {
timezone: culture?.timezone ?? DateTime.now().timeZoneName,
);
}

List<SentryRuntime> _getRuntimes(List<SentryRuntime>? runtimes) {
final flRuntime = flutterRuntime;
final dartFlRuntime = dartFlutterRuntime;

if (runtimes == null) {
return [
if (flRuntime != null) flRuntime,
if (dartFlRuntime != null) dartFlRuntime,
];
}
return [
...runtimes,
if (flRuntime != null) flRuntime,
if (dartFlRuntime != null) dartFlRuntime,
];
}
}

extension on web.Navigator {
Expand Down