Skip to content

Commit fecf459

Browse files
authored
Fix: missing event.origin and event.environment tags for non-native events on iOS (#369)
1 parent ae21d7e commit fecf459

File tree

4 files changed

+116
-40
lines changed

4 files changed

+116
-40
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
* Fix: Enable breadcrumb recording mechanism based on platform (#366)
66
* Feat: Send default PII options (#360)
77
* Bump: sentry-cocoa to v6.2.1 (#360)
8+
* Fix: missing event.origin and event.environment tags for non-native events on iOS (#369)
89

910
## Breaking Changes:
1011

flutter/ios/Classes/SwiftSentryFlutterPlugin.swift

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -202,8 +202,6 @@ public class SwiftSentryFlutterPlugin: NSObject, FlutterPlugin {
202202
if isValidSdk(sdk: sdk) {
203203

204204
switch sdk["name"] as? String {
205-
case "sentry.dart.flutter":
206-
setEventEnvironmentTag(event: event, origin: "flutter", environment: "dart")
207205
case "sentry.cocoa":
208206
setEventEnvironmentTag(event: event, origin: "ios", environment: "native")
209207
default:

flutter/lib/src/default_integrations.dart

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,15 @@ class LoadContextsIntegration extends Integration<SentryFlutterOptions> {
157157
sdk.addPackage(package['sdk_name']!, package['version']!);
158158
event = event.copyWith(sdk: sdk);
159159
}
160+
161+
// on iOS, captureEnvelope does not call the beforeSend callback,
162+
// hence we need to add these tags here.
163+
if (event.sdk?.name == 'sentry.dart.flutter') {
164+
final tags = event.tags ?? {};
165+
tags['event.origin'] = 'flutter';
166+
tags['event.environment'] = 'dart';
167+
event = event.copyWith(tags: tags);
168+
}
160169
} catch (error) {
161170
options.logger(
162171
SentryLevel.error,

flutter/test/load_contexts_integrations_test.dart

Lines changed: 106 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,19 @@ import 'package:flutter_test/flutter_test.dart';
55
import 'package:sentry_flutter/sentry_flutter.dart';
66
import 'package:sentry_flutter/src/sentry_flutter_options.dart';
77

8-
import 'mocks.dart';
8+
import 'mocks.mocks.dart';
99

1010
void main() {
11-
const _channel = MethodChannel('sentry_flutter');
12-
1311
TestWidgetsFlutterBinding.ensureInitialized();
1412

1513
var called = false;
1614

15+
late Fixture fixture;
16+
1717
setUp(() {
18-
_channel.setMockMethodCallHandler((MethodCall methodCall) async {
18+
fixture = Fixture();
19+
20+
fixture.channel.setMockMethodCallHandler((MethodCall methodCall) async {
1921
called = true;
2022
return {
2123
'integrations': ['NativeIntegration'],
@@ -34,20 +36,36 @@ void main() {
3436
});
3537

3638
tearDown(() {
37-
_channel.setMockMethodCallHandler(null);
39+
fixture.channel.setMockMethodCallHandler(null);
3840
});
3941

40-
test('should apply the loadContextsIntegration eventProcessor', () async {
41-
final options = SentryFlutterOptions()..dsn = fakeDsn;
42-
final hub = Hub(options);
42+
SdkVersion getSdkVersion({String name = 'sentry.dart'}) {
43+
return SdkVersion(
44+
name: name,
45+
version: '1.0',
46+
integrations: const ['EventIntegration'],
47+
packages: const [SentryPackage('event-package', '2.0')]);
48+
}
49+
50+
SentryEvent getEvent({
51+
SdkVersion? sdk,
52+
Map<String, String>? tags,
53+
}) {
54+
return SentryEvent(
55+
sdk: sdk ?? getSdkVersion(),
56+
tags: tags,
57+
);
58+
}
4359

44-
LoadContextsIntegration(_channel)(hub, options);
60+
test('should apply the loadContextsIntegration eventProcessor', () async {
61+
final integration = fixture.getSut();
62+
integration(fixture.hub, fixture.options);
4563

46-
expect(options.eventProcessors.length, 1);
64+
expect(fixture.options.eventProcessors.length, 1);
4765

4866
final e = SentryEvent();
49-
final event =
50-
await (options.eventProcessors.first(e) as FutureOr<SentryEvent>);
67+
final event = await (fixture.options.eventProcessors.first(e)
68+
as FutureOr<SentryEvent>);
5169

5270
expect(called, true);
5371
expect(event.contexts.device!.name, 'Device1');
@@ -68,12 +86,10 @@ void main() {
6886
test(
6987
'should not override event contexts with the loadContextsIntegration infos',
7088
() async {
71-
final options = SentryFlutterOptions()..dsn = fakeDsn;
72-
final hub = Hub(options);
89+
final integration = fixture.getSut();
90+
integration(fixture.hub, fixture.options);
7391

74-
LoadContextsIntegration(_channel)(hub, options);
75-
76-
expect(options.eventProcessors.length, 1);
92+
expect(fixture.options.eventProcessors.length, 1);
7793

7894
final eventContexts = Contexts(
7995
device: const SentryDevice(name: 'eDevice'),
@@ -84,8 +100,8 @@ void main() {
84100
runtimes: [const SentryRuntime(name: 'eRT')])
85101
..['theme'] = 'cuppertino';
86102
final e = SentryEvent(contexts: eventContexts);
87-
final event =
88-
await (options.eventProcessors.first(e) as FutureOr<SentryEvent>);
103+
final event = await (fixture.options.eventProcessors.first(e)
104+
as FutureOr<SentryEvent>);
89105

90106
expect(called, true);
91107
expect(event.contexts.device!.name, 'eDevice');
@@ -103,20 +119,12 @@ void main() {
103119
test(
104120
'should merge event and loadContextsIntegration sdk packages and integration',
105121
() async {
106-
final options = SentryFlutterOptions()..dsn = fakeDsn;
107-
final hub = Hub(options);
108-
109-
LoadContextsIntegration(_channel)(hub, options);
122+
final integration = fixture.getSut();
123+
integration(fixture.hub, fixture.options);
110124

111-
final eventSdk = SdkVersion(
112-
name: 'sdk1',
113-
version: '1.0',
114-
integrations: const ['EventIntegration'],
115-
packages: const [SentryPackage('event-package', '2.0')],
116-
);
117-
final e = SentryEvent(sdk: eventSdk);
118-
final event =
119-
await (options.eventProcessors.first(e) as FutureOr<SentryEvent>);
125+
final e = getEvent();
126+
final event = await (fixture.options.eventProcessors.first(e)
127+
as FutureOr<SentryEvent>);
120128

121129
expect(
122130
event.sdk!.packages.any((element) => element.name == 'native-package'),
@@ -132,17 +140,77 @@ void main() {
132140
);
133141

134142
test('should not throw on loadContextsIntegration exception', () async {
135-
_channel.setMockMethodCallHandler((MethodCall methodCall) async {
143+
fixture.channel.setMockMethodCallHandler((MethodCall methodCall) async {
136144
throw Exception();
137145
});
138-
final options = SentryFlutterOptions()..dsn = fakeDsn;
139-
final hub = Hub(options);
140-
141-
LoadContextsIntegration(_channel)(hub, options);
146+
final integration = fixture.getSut();
147+
integration(fixture.hub, fixture.options);
142148

143149
final e = SentryEvent();
144-
final event = await options.eventProcessors.first(e);
150+
final event = await fixture.options.eventProcessors.first(e);
145151

146152
expect(event, isNotNull);
147153
});
154+
155+
test(
156+
'should add origin and environment tags if tags is null',
157+
() async {
158+
final integration = fixture.getSut();
159+
integration(fixture.hub, fixture.options);
160+
161+
final eventSdk = getSdkVersion(name: 'sentry.dart.flutter');
162+
final e = getEvent(sdk: eventSdk);
163+
final event = await (fixture.options.eventProcessors.first(e)
164+
as FutureOr<SentryEvent>);
165+
166+
expect(event.tags!['event.origin'], 'flutter');
167+
expect(event.tags!['event.environment'], 'dart');
168+
},
169+
);
170+
171+
test(
172+
'should merge origin and environment tags',
173+
() async {
174+
final integration = fixture.getSut();
175+
integration(fixture.hub, fixture.options);
176+
177+
final eventSdk = getSdkVersion(name: 'sentry.dart.flutter');
178+
final e = getEvent(
179+
sdk: eventSdk,
180+
tags: {'a': 'b'},
181+
);
182+
final event = await (fixture.options.eventProcessors.first(e)
183+
as FutureOr<SentryEvent>);
184+
185+
expect(event.tags!['event.origin'], 'flutter');
186+
expect(event.tags!['event.environment'], 'dart');
187+
expect(event.tags!['a'], 'b');
188+
},
189+
);
190+
191+
test(
192+
'should not add origin and environment tags if not flutter sdk',
193+
() async {
194+
final integration = fixture.getSut();
195+
integration(fixture.hub, fixture.options);
196+
197+
final e = getEvent(tags: {});
198+
final event = await (fixture.options.eventProcessors.first(e)
199+
as FutureOr<SentryEvent>);
200+
201+
expect(event.tags!.containsKey('event.origin'), false);
202+
expect(event.tags!.containsKey('event.environment'), false);
203+
},
204+
);
205+
}
206+
207+
class Fixture {
208+
final channel = MethodChannel('sentry_flutter');
209+
210+
final hub = MockHub();
211+
final options = SentryFlutterOptions();
212+
213+
LoadContextsIntegration getSut() {
214+
return LoadContextsIntegration(channel);
215+
}
148216
}

0 commit comments

Comments
 (0)