Skip to content

Commit 95ebf3f

Browse files
uemandenrase
andauthored
Add Flutter runtime information (#2742)
* Add Flutter runtime * add explaining comment * add changelog * Update CHANGELOG.md * make things const * fix changelog * more doc comments * Fix formatting * add test and requested changes * move tests to flutter package * skip if environment is missing * add ignore --------- Co-authored-by: Denis Andrašec <[email protected]>
1 parent 3b5a71f commit 95ebf3f

File tree

5 files changed

+148
-1
lines changed

5 files changed

+148
-1
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,17 @@
22

33
## Unreleased
44

5+
6+
### Enhancements
7+
8+
- Add Flutter runtime information ([#2742](https://github.com/getsentry/sentry-dart/pull/2742))
9+
- This works if the version of Flutter you're using includes [this code](https://github.com/flutter/flutter/pull/163761).
10+
511
### Fixes
612

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

15+
916
## 8.14.0-beta.1
1017

1118
### Behavioral changes
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import '../../protocol/sentry_runtime.dart';
2+
3+
// The Flutter version information can be fetched via Dart defines,
4+
// see
5+
// - https://github.com/flutter/flutter/pull/140783
6+
// - https://github.com/flutter/flutter/pull/163761
7+
//
8+
// This code lives in the Dart only Sentry code, since the code
9+
// doesn't require any Flutter dependency.
10+
// Additionally, this makes it work on background isolates in
11+
// Flutter, where one may not initialize the whole Flutter Sentry
12+
// SDK.
13+
// The const-ness of the properties below ensure that the code
14+
// is tree shaken in a non-Flutter environment.
15+
16+
const _isFlutterRuntimeInformationAbsent = FlutterVersion.version == null ||
17+
FlutterVersion.channel == null ||
18+
FlutterVersion.frameworkRevision == null;
19+
20+
const SentryRuntime? flutterRuntime = _isFlutterRuntimeInformationAbsent
21+
? null
22+
: SentryRuntime(
23+
name: 'Flutter',
24+
version: '${FlutterVersion.version} (${FlutterVersion.channel})',
25+
build: FlutterVersion.frameworkRevision,
26+
rawDescription: '${FlutterVersion.version} (${FlutterVersion.channel}) '
27+
'- Git hash ${FlutterVersion.frameworkRevision} '
28+
'- Git URL ${FlutterVersion.gitUrl}',
29+
);
30+
31+
const SentryRuntime? dartFlutterRuntime = FlutterVersion.dartVersion == null
32+
? null
33+
: SentryRuntime(name: 'Dart', version: FlutterVersion.dartVersion);
34+
35+
/// Details about the Flutter version this app was compiled with,
36+
/// corresponding to the output of `flutter --version`.
37+
///
38+
/// When this Flutter version was build from a fork, or when Flutter runs in a
39+
/// custom embedder, these values might be unreliable.
40+
abstract class FlutterVersion {
41+
const FlutterVersion._();
42+
43+
/// The Flutter version used to compile the app.
44+
static const String? version = bool.hasEnvironment('FLUTTER_VERSION')
45+
? String.fromEnvironment('FLUTTER_VERSION')
46+
: null;
47+
48+
/// The Flutter channel used to compile the app.
49+
static const String? channel = bool.hasEnvironment('FLUTTER_CHANNEL')
50+
? String.fromEnvironment('FLUTTER_CHANNEL')
51+
: null;
52+
53+
/// The URL of the Git repository from which Flutter was obtained.
54+
static const String? gitUrl = bool.hasEnvironment('FLUTTER_GIT_URL')
55+
? String.fromEnvironment('FLUTTER_GIT_URL')
56+
: null;
57+
58+
/// The Flutter framework revision, as a (short) Git commit ID.
59+
static const String? frameworkRevision =
60+
bool.hasEnvironment('FLUTTER_FRAMEWORK_REVISION')
61+
? String.fromEnvironment('FLUTTER_FRAMEWORK_REVISION')
62+
: null;
63+
64+
/// The Flutter engine revision.
65+
static const String? engineRevision =
66+
bool.hasEnvironment('FLUTTER_ENGINE_REVISION')
67+
? String.fromEnvironment('FLUTTER_ENGINE_REVISION')
68+
: null;
69+
70+
// This is included since [Platform.version](https://api.dart.dev/stable/dart-io/Platform/version.html)
71+
// is not included on web platforms.
72+
/// The Dart version used to compile the app.
73+
static const String? dartVersion = bool.hasEnvironment('FLUTTER_DART_VERSION')
74+
? String.fromEnvironment('FLUTTER_DART_VERSION')
75+
: null;
76+
}

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import 'package:meta/meta.dart';
44

55
import '../../../sentry.dart';
66
import 'enricher_event_processor.dart';
7+
import 'flutter_runtime.dart';
78
import 'io_platform_memory.dart';
89

910
EnricherEventProcessor enricherEventProcessor(SentryOptions options) {
@@ -63,12 +64,15 @@ class IoEnricherEventProcessor implements EnricherEventProcessor {
6364
version: _dartVersion,
6465
rawDescription: Platform.version,
6566
);
67+
final flRuntime = flutterRuntime;
68+
6669
if (runtimes == null) {
67-
return [dartRuntime];
70+
return [dartRuntime, if (flRuntime != null) flRuntime];
6871
}
6972
return [
7073
...runtimes,
7174
dartRuntime,
75+
if (flRuntime != null) flRuntime,
7276
];
7377
}
7478

dart/lib/src/event_processor/enricher/web_enricher_event_processor.dart

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import 'package:web/web.dart' as web show window, Window, Navigator;
44

55
import '../../../sentry.dart';
66
import 'enricher_event_processor.dart';
7+
import 'flutter_runtime.dart';
78

89
EnricherEventProcessor enricherEventProcessor(SentryOptions options) {
910
return WebEnricherEventProcessor(
@@ -29,6 +30,7 @@ class WebEnricherEventProcessor implements EnricherEventProcessor {
2930
final contexts = event.contexts.copyWith(
3031
device: _getDevice(event.contexts.device),
3132
culture: _getSentryCulture(event.contexts.culture),
33+
runtimes: _getRuntimes(event.contexts.runtimes),
3234
);
3335

3436
contexts['dart_context'] = _getDartContext();
@@ -100,6 +102,23 @@ class WebEnricherEventProcessor implements EnricherEventProcessor {
100102
timezone: culture?.timezone ?? DateTime.now().timeZoneName,
101103
);
102104
}
105+
106+
List<SentryRuntime> _getRuntimes(List<SentryRuntime>? runtimes) {
107+
final flRuntime = flutterRuntime;
108+
final dartFlRuntime = dartFlutterRuntime;
109+
110+
if (runtimes == null) {
111+
return [
112+
if (flRuntime != null) flRuntime,
113+
if (dartFlRuntime != null) dartFlRuntime,
114+
];
115+
}
116+
return [
117+
...runtimes,
118+
if (flRuntime != null) flRuntime,
119+
if (dartFlRuntime != null) dartFlRuntime,
120+
];
121+
}
103122
}
104123

105124
extension on web.Navigator {
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import 'package:flutter_test/flutter_test.dart';
2+
import 'package:sentry/src/event_processor/enricher/flutter_runtime.dart';
3+
4+
void main() {
5+
group(FlutterVersion, () {
6+
test('FlutterVersion.version contains the current version', () {
7+
expect(FlutterVersion.version,
8+
const String.fromEnvironment('FLUTTER_VERSION'));
9+
});
10+
11+
test('FlutterVersion.channel contains the current channel', () {
12+
expect(FlutterVersion.channel,
13+
const String.fromEnvironment('FLUTTER_CHANNEL'));
14+
});
15+
16+
test('FlutterVersion.gitUrl contains the current git URL', () {
17+
expect(FlutterVersion.gitUrl,
18+
const String.fromEnvironment('FLUTTER_GIT_URL'));
19+
});
20+
21+
test(
22+
'FlutterVersion.frameworkRevision contains the current framework revision',
23+
() {
24+
expect(
25+
FlutterVersion.frameworkRevision,
26+
const String.fromEnvironment('FLUTTER_FRAMEWORK_REVISION'),
27+
);
28+
});
29+
30+
test('FlutterVersion.engineRevision contains the current engine revision',
31+
() {
32+
expect(FlutterVersion.engineRevision,
33+
const String.fromEnvironment('FLUTTER_ENGINE_REVISION'));
34+
});
35+
36+
test('FlutterVersion.dartVersion contains the current Dart version', () {
37+
expect(FlutterVersion.dartVersion,
38+
const String.fromEnvironment('FLUTTER_DART_VERSION'));
39+
});
40+
}, skip: !(const bool.hasEnvironment('FLUTTER_VERSION')));
41+
}

0 commit comments

Comments
 (0)