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
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,17 @@

## Unreleased


### Enhancements

- 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/163761).

### Fixes

- Pass missing `captureFailedRequests` param to `FailedRequestInterceptor` ([#2744](https://github.com/getsentry/sentry-dart/pull/2744))


## 8.14.0-beta.1

### Behavioral changes
Expand Down
76 changes: 76 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,76 @@
import '../../protocol/sentry_runtime.dart';

// The Flutter version information can be fetched via Dart defines,
// see
// - https://github.com/flutter/flutter/pull/140783
// - https://github.com/flutter/flutter/pull/163761
//
// 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.
// The const-ness of the properties below ensure that the code
// is tree shaken in a non-Flutter environment.

const _isFlutterRuntimeInformationAbsent = FlutterVersion.version == null ||
FlutterVersion.channel == null ||
FlutterVersion.frameworkRevision == null;

const SentryRuntime? flutterRuntime = _isFlutterRuntimeInformationAbsent
? null
: SentryRuntime(
name: 'Flutter',
version: '${FlutterVersion.version} (${FlutterVersion.channel})',
build: FlutterVersion.frameworkRevision,
rawDescription: '${FlutterVersion.version} (${FlutterVersion.channel}) '
'- Git hash ${FlutterVersion.frameworkRevision} '
'- Git URL ${FlutterVersion.gitUrl}',
);

const SentryRuntime? dartFlutterRuntime = FlutterVersion.dartVersion == null
? null
: 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
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
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
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 '../../../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 @@
version: _dartVersion,
rawDescription: Platform.version,
);
final flRuntime = flutterRuntime;

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

Check warning on line 70 in dart/lib/src/event_processor/enricher/io_enricher_event_processor.dart

View check run for this annotation

Codecov / codecov/patch

dart/lib/src/event_processor/enricher/io_enricher_event_processor.dart#L70

Added line #L70 was not covered by tests
}
return [
...runtimes,
dartRuntime,
if (flRuntime != null) flRuntime,

Check warning on line 75 in dart/lib/src/event_processor/enricher/io_enricher_event_processor.dart

View check run for this annotation

Codecov / codecov/patch

dart/lib/src/event_processor/enricher/io_enricher_event_processor.dart#L75

Added line #L75 was not covered by tests
];
}

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
41 changes: 41 additions & 0 deletions flutter/test/flutter_version_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:sentry/src/event_processor/enricher/flutter_runtime.dart';

void main() {
group(FlutterVersion, () {
test('FlutterVersion.version contains the current version', () {
expect(FlutterVersion.version,
const String.fromEnvironment('FLUTTER_VERSION'));
});

test('FlutterVersion.channel contains the current channel', () {
expect(FlutterVersion.channel,
const String.fromEnvironment('FLUTTER_CHANNEL'));
});

test('FlutterVersion.gitUrl contains the current git URL', () {
expect(FlutterVersion.gitUrl,
const String.fromEnvironment('FLUTTER_GIT_URL'));
});

test(
'FlutterVersion.frameworkRevision contains the current framework revision',
() {
expect(
FlutterVersion.frameworkRevision,
const String.fromEnvironment('FLUTTER_FRAMEWORK_REVISION'),
);
});

test('FlutterVersion.engineRevision contains the current engine revision',
() {
expect(FlutterVersion.engineRevision,
const String.fromEnvironment('FLUTTER_ENGINE_REVISION'));
});

test('FlutterVersion.dartVersion contains the current Dart version', () {
expect(FlutterVersion.dartVersion,
const String.fromEnvironment('FLUTTER_DART_VERSION'));
});
}, skip: !(const bool.hasEnvironment('FLUTTER_VERSION')));
}
Loading