Skip to content

Commit 83081be

Browse files
committed
Merge branch 'main' into enha/rel-platfomr-cause
2 parents 9a23c4a + 6664bac commit 83081be

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+1273
-160
lines changed

CHANGELOG.md

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,48 @@
11
# Changelog
22

3-
## Unreleased
3+
## 9.0.0-alpha.2
4+
5+
### Features
6+
7+
- Add support for Flutter Web release health ([#2794](https://github.com/getsentry/sentry-dart/pull/2794))
8+
- Requires using `SentryNavigatorObserver`;
9+
10+
### Dependencies
11+
12+
- Bump Native SDK from v0.7.20 to v0.8.2 ([#2761](https://github.com/getsentry/sentry-dart/pull/2761), [#2807](https://github.com/getsentry/sentry-dart/pull/2807))
13+
- [changelog](https://github.com/getsentry/sentry-native/blob/master/CHANGELOG.md#082)
14+
- [diff](https://github.com/getsentry/sentry-native/compare/0.7.20...0.8.2)
15+
- Bump Javascript SDK from v8.42.0 to v9.5.0 ([#2784](https://github.com/getsentry/sentry-dart/pull/2784))
16+
- [changelog](https://github.com/getsentry/sentry-javascript/blob/main/CHANGELOG.md#950)
17+
- [diff](https://github.com/getsentry/sentry-javascript/compare/8.42.0...9.5.0)
18+
19+
### Behavioral changes
420

5-
- Bump Native SDK from v0.7.20 to v0.8.1 ([#2761](https://github.com/getsentry/sentry-dart/pull/2761))
6-
- [changelog](https://github.com/getsentry/sentry-native/blob/master/CHANGELOG.md#081)
7-
- [diff](https://github.com/getsentry/sentry-native/compare/0.7.20...0.8.1)
821
- Set sentry-native backend to `crashpad` by default and `breakpad` for Windows ARM64 ([#2791](https://github.com/getsentry/sentry-dart/pull/2791))
922
- Setting the `SENTRY_NATIVE_BACKEND` environment variable will override the defaults.
10-
- Move replay and privacy from experimental to options ([#2755](https://github.com/getsentry/sentry-dart/pull/2755))
1123
- Remove renderer from `flutter_context` ([#2751](https://github.com/getsentry/sentry-dart/pull/2751))
24+
25+
### API changes
26+
27+
- Move replay and privacy from experimental to options ([#2755](https://github.com/getsentry/sentry-dart/pull/2755))
1228
- Cleanup platform mocking ([#2730](https://github.com/getsentry/sentry-dart/pull/2730))
1329
- The `PlatformChecker` was renamed to `RuntimeChecker`
1430
- Moved `PlatformChecker.platform` to `options.platform`
15-
- Bump Javascript SDK from v8.42.0 to v9.5.0 ([#2784](https://github.com/getsentry/sentry-dart/pull/2784))
16-
- [changelog](https://github.com/getsentry/sentry-javascript/blob/main/CHANGELOG.md#950)
17-
- [diff](https://github.com/getsentry/sentry-javascript/compare/8.42.0...9.5.0)
31+
32+
## 8.14.1
33+
34+
### Fixes
35+
36+
- Improve platform memory collection on windows/linux ([#2798](https://github.com/getsentry/sentry-dart/pull/2798))
37+
- Fixes an issue where total memory on windows was not read.
38+
- Free memory collection was removed on windows/linux, due to performance issues.
39+
- Fix adding runtime to contexts ([#2813](https://github.com/getsentry/sentry-dart/pull/2813))
40+
41+
### Dependencies
42+
43+
- Bump Android SDK from v7.22.1 to v7.22.4 ([#2810](https://github.com/getsentry/sentry-dart/pull/2810))
44+
- [changelog](https://github.com/getsentry/sentry-java/blob/7.x.x/CHANGELOG.md#7224)
45+
- [diff](https://github.com/getsentry/sentry-java/compare/7.22.1...7.22.4)
1846

1947
## 8.14.0
2048

dart/lib/sentry.dart

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
/// A pure Dart client for Sentry.io crash reporting.
66
library;
77

8+
// ignore: invalid_export_of_internal_element
9+
export 'src/constants.dart';
810
export 'src/event_processor.dart';
911
export 'src/exception_cause.dart';
1012
export 'src/exception_cause_extractor.dart';
@@ -18,12 +20,14 @@ export 'src/hub_adapter.dart';
1820
export 'src/integration.dart';
1921
export 'src/noop_isolate_error_integration.dart'
2022
if (dart.library.io) 'src/isolate_error_integration.dart';
23+
// ignore: invalid_export_of_internal_element
24+
export 'src/observers.dart';
2125
export 'src/performance_collector.dart';
22-
export 'src/runtime_checker.dart';
2326
export 'src/protocol.dart';
2427
export 'src/protocol/sentry_feedback.dart';
2528
export 'src/protocol/sentry_proxy.dart';
2629
export 'src/run_zoned_guarded_integration.dart';
30+
export 'src/runtime_checker.dart';
2731
export 'src/scope.dart';
2832
export 'src/scope_observer.dart';
2933
export 'src/sentry.dart';
@@ -34,8 +38,6 @@ export 'src/sentry_envelope.dart';
3438
export 'src/sentry_envelope_item.dart';
3539
export 'src/sentry_options.dart';
3640
// ignore: invalid_export_of_internal_element
37-
export 'src/constants.dart';
38-
// ignore: invalid_export_of_internal_element
3941
export 'src/sentry_trace_origins.dart';
4042
export 'src/span_data_convention.dart';
4143
export 'src/spotlight.dart';

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

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,11 @@ class IoEnricherEventProcessor implements EnricherEventProcessor {
2020
final SentryOptions _options;
2121
late final String _dartVersion = _extractDartVersion(Platform.version);
2222
late final SentryOperatingSystem _os = extractOperatingSystem(
23-
Platform.operatingSystem, Platform.operatingSystemVersion);
23+
Platform.operatingSystem,
24+
Platform.operatingSystemVersion,
25+
);
26+
bool _fetchedTotalPhysicalMemory = false;
27+
int? _totalPhysicalMemory;
2428

2529
/// Extracts the semantic version and channel from the full version string.
2630
///
@@ -37,17 +41,15 @@ class IoEnricherEventProcessor implements EnricherEventProcessor {
3741
}
3842

3943
@override
40-
SentryEvent? apply(SentryEvent event, Hint hint) {
41-
// Amend app with current memory usage, as this is not available on native.
42-
final app = _getApp(event.contexts.app);
43-
44-
final contexts = event.contexts.copyWith(
45-
device: _getDevice(event.contexts.device),
46-
operatingSystem: _getOperatingSystem(event.contexts.operatingSystem),
47-
runtimes: _getRuntimes(event.contexts.runtimes),
48-
app: app,
49-
culture: _getSentryCulture(event.contexts.culture),
50-
);
44+
Future<SentryEvent?> apply(SentryEvent event, Hint hint) async {
45+
final contexts = event.contexts;
46+
47+
contexts.device = await _getDevice(event.contexts.device);
48+
contexts.operatingSystem =
49+
_getOperatingSystem(event.contexts.operatingSystem);
50+
contexts.runtimes = _getRuntimes(event.contexts.runtimes);
51+
contexts.app = _getApp(event.contexts.app);
52+
contexts.culture = _getSentryCulture(event.contexts.culture);
5153

5254
contexts['dart_context'] = _getDartContext();
5355

@@ -99,17 +101,25 @@ class IoEnricherEventProcessor implements EnricherEventProcessor {
99101
};
100102
}
101103

102-
SentryDevice _getDevice(SentryDevice? device) {
103-
final platformMemory = PlatformMemory(_options);
104+
Future<SentryDevice> _getDevice(SentryDevice? device) async {
104105
return (device ?? SentryDevice()).copyWith(
105106
name: device?.name ??
106107
(_options.sendDefaultPii ? Platform.localHostname : null),
107108
processorCount: device?.processorCount ?? Platform.numberOfProcessors,
108-
memorySize: device?.memorySize ?? platformMemory.getTotalPhysicalMemory(),
109-
freeMemory: device?.freeMemory ?? platformMemory.getFreePhysicalMemory(),
109+
memorySize: device?.memorySize ?? await _getTotalPhysicalMemory(),
110+
freeMemory: device?.freeMemory,
110111
);
111112
}
112113

114+
Future<int?> _getTotalPhysicalMemory() async {
115+
if (!_fetchedTotalPhysicalMemory) {
116+
_totalPhysicalMemory =
117+
await PlatformMemory(_options).getTotalPhysicalMemory();
118+
_fetchedTotalPhysicalMemory = true;
119+
}
120+
return _totalPhysicalMemory;
121+
}
122+
113123
SentryApp _getApp(SentryApp? app) {
114124
return (app ?? SentryApp()).copyWith(
115125
appMemory: app?.appMemory ?? ProcessInfo.currentRss,

dart/lib/src/event_processor/enricher/io_platform_memory.dart

Lines changed: 60 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -6,32 +6,47 @@ import '../../sentry_options.dart';
66
// Get total & free platform memory (in bytes) for linux and windows operating systems.
77
// Source: https://github.com/onepub-dev/system_info/blob/8a9bf6b8eb7c86a09b3c3df4bf6d7fa5a6b50732/lib/src/platform/memory.dart
88
class PlatformMemory {
9-
PlatformMemory(this.options);
10-
11-
final SentryOptions options;
12-
13-
int? getTotalPhysicalMemory() {
14-
if (options.platform.isLinux) {
15-
return _getLinuxMemInfoValue('MemTotal');
16-
} else if (options.platform.isWindows) {
17-
return _getWindowsWmicValue('ComputerSystem', 'TotalPhysicalMemory');
9+
PlatformMemory(this.options) {
10+
if (options.platform.isWindows) {
11+
// Check for WMIC (deprecated in newer Windows versions)
12+
// https://techcommunity.microsoft.com/blog/windows-itpro-blog/wmi-command-line-wmic-utility-deprecation-next-steps/4039242
13+
useWindowsWmci =
14+
File('C:\\Windows\\System32\\wbem\\wmic.exe').existsSync();
15+
if (!useWindowsWmci) {
16+
useWindowsPowerShell = File(
17+
'C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe')
18+
.existsSync();
19+
} else {
20+
useWindowsPowerShell = false;
21+
}
1822
} else {
19-
return null;
23+
useWindowsWmci = false;
24+
useWindowsPowerShell = false;
2025
}
2126
}
2227

23-
int? getFreePhysicalMemory() {
28+
final SentryOptions options;
29+
late final bool useWindowsWmci;
30+
late final bool useWindowsPowerShell;
31+
32+
Future<int?> getTotalPhysicalMemory() async {
2433
if (options.platform.isLinux) {
25-
return _getLinuxMemInfoValue('MemFree');
34+
return _getLinuxMemInfoValue('MemTotal');
2635
} else if (options.platform.isWindows) {
27-
return _getWindowsWmicValue('OS', 'FreePhysicalMemory');
36+
if (useWindowsWmci) {
37+
return _getWindowsWmicValue('ComputerSystem', 'TotalPhysicalMemory');
38+
} else if (useWindowsPowerShell) {
39+
return _getWindowsPowershellTotalMemoryValue();
40+
} else {
41+
return null;
42+
}
2843
} else {
2944
return null;
3045
}
3146
}
3247

33-
int? _getWindowsWmicValue(String section, String key) {
34-
final os = _wmicGetValueAsMap(section, [key]);
48+
Future<int?> _getWindowsWmicValue(String section, String key) async {
49+
final os = await _wmicGetValueAsMap(section, [key]);
3550
final totalPhysicalMemoryValue = os?[key];
3651
if (totalPhysicalMemoryValue == null) {
3752
return null;
@@ -43,12 +58,10 @@ class PlatformMemory {
4358
return size;
4459
}
4560

46-
int? _getLinuxMemInfoValue(String key) {
47-
final meminfoList = _exec('cat', ['/proc/meminfo'])
48-
?.trim()
49-
.replaceAll('\r\n', '\n')
50-
.split('\n') ??
51-
[];
61+
Future<int?> _getLinuxMemInfoValue(String key) async {
62+
final result = await _exec('cat', ['/proc/meminfo']);
63+
final meminfoList =
64+
result?.trim().replaceAll('\r\n', '\n').split('\n') ?? [];
5265

5366
final meminfoMap = _listToMap(meminfoList, ':');
5467
final memsizeResults = meminfoMap[key]?.split(' ') ?? [];
@@ -65,11 +78,11 @@ class PlatformMemory {
6578
return memsize;
6679
}
6780

68-
String? _exec(String executable, List<String> arguments,
69-
{bool runInShell = false}) {
81+
Future<String?> _exec(String executable, List<String> arguments,
82+
{bool runInShell = false}) async {
7083
try {
7184
final result =
72-
Process.runSync(executable, arguments, runInShell: runInShell);
85+
await Process.run(executable, arguments, runInShell: runInShell);
7386
if (result.exitCode == 0) {
7487
return result.stdout.toString();
7588
}
@@ -82,16 +95,16 @@ class PlatformMemory {
8295
return null;
8396
}
8497

85-
Map<String, String>? _wmicGetValueAsMap(String section, List<String> fields) {
98+
Future<Map<String, String>?> _wmicGetValueAsMap(
99+
String section, List<String> fields) async {
86100
final arguments = <String>[section];
87101
arguments
88102
..add('get')
89103
..addAll(fields.join(', ').split(' '))
90104
..add('/VALUE');
91105

92-
final list =
93-
_exec('wmic', arguments)?.trim().replaceAll('\r\n', '\n').split('\n') ??
94-
[];
106+
final result = await _exec('wmic', arguments);
107+
final list = result?.trim().replaceAll('\r\n', '\n').split('\n') ?? [];
95108

96109
return _listToMap(list, '=');
97110
}
@@ -108,4 +121,23 @@ class PlatformMemory {
108121
}
109122
return map;
110123
}
124+
125+
Future<int?> _getWindowsPowershellTotalMemoryValue() async {
126+
final command =
127+
'Get-CimInstance Win32_ComputerSystem | Select-Object -ExpandProperty TotalPhysicalMemory';
128+
129+
final result = await _exec('powershell.exe',
130+
['-NoProfile', '-NonInteractive', '-Command', command]);
131+
if (result == null) {
132+
return null;
133+
}
134+
135+
final value = result.trim();
136+
final size = int.tryParse(value);
137+
if (size == null) {
138+
return null;
139+
}
140+
141+
return size;
142+
}
111143
}

dart/lib/src/observers.dart

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import 'dart:async';
2+
3+
import 'package:meta/meta.dart';
4+
5+
import '../sentry.dart';
6+
7+
// This file will contain observer definitions that are executed during
8+
// specific points in the SDK such as as right before an event is sent.
9+
// Only for internal use, e.g updating sessions only when an event is fully processed.
10+
// Not to be confused with the public callbacks such as beforeSend.
11+
// These should not mutate the data that is passed through the observer.
12+
13+
/// Called right before an event is sent, after all processing is complete.
14+
/// Should not modify the event at this point.
15+
@internal
16+
abstract class BeforeSendEventObserver {
17+
FutureOr<void> onBeforeSendEvent(SentryEvent event, Hint hint);
18+
}

dart/lib/src/protocol/contexts.dart

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ class Contexts extends MapView<String, dynamic> {
2424
}) : super({
2525
SentryDevice.type: device,
2626
SentryOperatingSystem.type: operatingSystem,
27-
SentryRuntime.listType: runtimes ?? [],
27+
SentryRuntime.listType: List<SentryRuntime>.from(runtimes ?? []),
2828
SentryApp.type: app,
2929
SentryBrowser.type: browser,
3030
SentryGpu.type: gpu,
@@ -98,6 +98,9 @@ class Contexts extends MapView<String, dynamic> {
9898
List<SentryRuntime> get runtimes =>
9999
List.unmodifiable(this[SentryRuntime.listType] ?? []);
100100

101+
set runtimes(List<SentryRuntime> runtimes) =>
102+
this[SentryRuntime.listType] = List<SentryRuntime>.from(runtimes);
103+
101104
void addRuntime(SentryRuntime runtime) =>
102105
this[SentryRuntime.listType].add(runtime);
103106

@@ -291,7 +294,8 @@ class Contexts extends MapView<String, dynamic> {
291294
Contexts(
292295
device: device ?? this.device,
293296
operatingSystem: operatingSystem ?? this.operatingSystem,
294-
runtimes: runtimes ?? this.runtimes,
297+
runtimes: runtimes ??
298+
List<SentryRuntime>.from(this[SentryRuntime.listType] ?? []),
295299
app: app ?? this.app,
296300
browser: browser ?? this.browser,
297301
gpu: gpu ?? this.gpu,

dart/lib/src/scope.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,7 @@ class Scope {
317317
level: level ?? event.level);
318318
}
319319

320-
_contexts.clone().forEach((key, value) {
320+
_contexts.forEach((key, value) {
321321
// add the contexts runtime list to the event.contexts.runtimes
322322
if (key == SentryRuntime.listType &&
323323
value is List<SentryRuntime> &&

dart/lib/src/sentry_client.dart

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,9 @@ class SentryClient {
160160
return _emptySentryId;
161161
}
162162

163+
// Event is fully processed and ready to be sent, emit beforeSendEvent observer
164+
await _emitBeforeSendEventObserver(preparedEvent, hint);
165+
163166
var attachments = List<SentryAttachment>.from(scope?.attachments ?? []);
164167
attachments.addAll(hint.attachments);
165168
var screenshot = hint.screenshot;
@@ -563,4 +566,26 @@ class SentryClient {
563566
}
564567
return DataCategory.error;
565568
}
569+
570+
FutureOr<void> _emitBeforeSendEventObserver(
571+
SentryEvent event, Hint hint) async {
572+
for (final observer in _options.beforeSendEventObservers) {
573+
try {
574+
final result = observer.onBeforeSendEvent(event, hint);
575+
if (result is Future) {
576+
await result;
577+
}
578+
} catch (exception, stackTrace) {
579+
_options.logger(
580+
SentryLevel.error,
581+
'Error while running beforeSendEvent observer',
582+
exception: exception,
583+
stackTrace: stackTrace,
584+
);
585+
if (_options.automatedTestMode) {
586+
rethrow;
587+
}
588+
}
589+
}
590+
}
566591
}

0 commit comments

Comments
 (0)