Skip to content

Commit 168e871

Browse files
authored
Merge fb0057d into 1faf8e3
2 parents 1faf8e3 + fb0057d commit 168e871

File tree

11 files changed

+104
-6
lines changed

11 files changed

+104
-6
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
### Fixes
1212

13+
- Adds breadcrumb origin field to prevent exception capture context from being overwritten by native scope sync ([#4124](https://github.com/getsentry/sentry-react-native/pull/4124))
1314
- Skips ignoring require cycle logs for RN 0.70 or newer ([#4214](https://github.com/getsentry/sentry-react-native/pull/4214))
1415
- Enhanced accuracy of time-to-display spans. ([#4189](https://github.com/getsentry/sentry-react-native/pull/4189))
1516

packages/core/RNSentryAndroidTester/app/src/test/java/io/sentry/rnsentryandroidtester/RNSentryBreadcrumbTest.kt

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package io.sentry.rnsentryandroidtester
22

33
import com.facebook.react.bridge.JavaOnlyMap
4+
import io.sentry.SentryLevel
45
import io.sentry.react.RNSentryBreadcrumb
56
import junit.framework.TestCase.assertEquals
67
import org.junit.Test
@@ -10,6 +11,38 @@ import org.junit.runners.JUnit4
1011
@RunWith(JUnit4::class)
1112
class RNSentryBreadcrumbTest {
1213

14+
@Test
15+
fun generatesSentryBreadcrumbFromMap() {
16+
val testData = JavaOnlyMap.of(
17+
"test", "data",
18+
)
19+
val map = JavaOnlyMap.of(
20+
"level", "error",
21+
"category", "testCategory",
22+
"origin", "testOrigin",
23+
"type", "testType",
24+
"message", "testMessage",
25+
"data", testData,
26+
)
27+
val actual = RNSentryBreadcrumb.fromMap(map)
28+
assertEquals(SentryLevel.ERROR, actual.level)
29+
assertEquals("testCategory", actual.category)
30+
assertEquals("testOrigin", actual.origin)
31+
assertEquals("testType", actual.type)
32+
assertEquals("testMessage", actual.message)
33+
assertEquals(testData.toHashMap(), actual.data)
34+
}
35+
36+
@Test
37+
fun reactNativeForMissingOrigin() {
38+
val map = JavaOnlyMap.of(
39+
"message", "testMessage",
40+
)
41+
val actual = RNSentryBreadcrumb.fromMap(map)
42+
assertEquals("testMessage", actual.message)
43+
assertEquals("react-native", actual.origin)
44+
}
45+
1346
@Test
1447
fun nullForMissingCategory() {
1548
val map = JavaOnlyMap.of()

packages/core/RNSentryCocoaTester/RNSentryCocoaTester.xcodeproj/project.pbxproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
33AFDFED2B8D14B300AAB120 /* RNSentryFramesTrackerListenerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 33AFDFEC2B8D14B300AAB120 /* RNSentryFramesTrackerListenerTests.m */; };
1313
33AFDFF12B8D15E500AAB120 /* RNSentryDependencyContainerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 33AFDFF02B8D15E500AAB120 /* RNSentryDependencyContainerTests.m */; };
1414
33F58AD02977037D008F60EA /* RNSentryTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 33F58ACF2977037D008F60EA /* RNSentryTests.mm */; };
15+
AEFB00422CC90C4B00EC8A9A /* RNSentryBreadcrumbTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3360843C2C340C76008CC412 /* RNSentryBreadcrumbTests.swift */; };
1516
B5859A50A3E865EF5E61465A /* libPods-RNSentryCocoaTesterTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 650CB718ACFBD05609BF2126 /* libPods-RNSentryCocoaTesterTests.a */; };
1617
/* End PBXBuildFile section */
1718

@@ -212,6 +213,7 @@
212213
isa = PBXSourcesBuildPhase;
213214
buildActionMask = 2147483647;
214215
files = (
216+
AEFB00422CC90C4B00EC8A9A /* RNSentryBreadcrumbTests.swift in Sources */,
215217
33AFDFF12B8D15E500AAB120 /* RNSentryDependencyContainerTests.m in Sources */,
216218
336084392C32E382008CC412 /* RNSentryReplayBreadcrumbConverterTests.swift in Sources */,
217219
33F58AD02977037D008F60EA /* RNSentryTests.mm in Sources */,

packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryBreadcrumbTests.swift

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import XCTest
22
import Sentry
33

4-
class RNSentryBreadcrumbTests: XCTestCase {
4+
final class RNSentryBreadcrumbTests: XCTestCase {
55

66
func testGeneratesSentryBreadcrumbFromNSDictionary() {
77
let actualCrumb = RNSentryBreadcrumb.from([
88
"level": "error",
99
"category": "testCategory",
10+
"origin": "testOrigin",
1011
"type": "testType",
1112
"message": "testMessage",
1213
"data": [
@@ -16,11 +17,29 @@ class RNSentryBreadcrumbTests: XCTestCase {
1617

1718
XCTAssertEqual(actualCrumb!.level, SentryLevel.error)
1819
XCTAssertEqual(actualCrumb!.category, "testCategory")
20+
XCTAssertEqual(actualCrumb!.origin, "testOrigin")
1921
XCTAssertEqual(actualCrumb!.type, "testType")
2022
XCTAssertEqual(actualCrumb!.message, "testMessage")
2123
XCTAssertEqual((actualCrumb!.data)!["test"] as! String, "data")
2224
}
2325

26+
func testUsesReactNativeAsDefaultOrigin() {
27+
let actualCrumb = RNSentryBreadcrumb.from([
28+
"message": "testMessage"
29+
])
30+
31+
XCTAssertEqual(actualCrumb!.origin, "react-native")
32+
}
33+
34+
func testKeepsOriginIfSet() {
35+
let actualCrumb = RNSentryBreadcrumb.from([
36+
"message": "testMessage",
37+
"origin": "someOrigin"
38+
])
39+
40+
XCTAssertEqual(actualCrumb!.origin, "someOrigin")
41+
}
42+
2443
func testUsesInfoAsDefaultSentryLevel() {
2544
let actualCrumb = RNSentryBreadcrumb.from([
2645
"message": "testMessage"

packages/core/android/src/main/java/io/sentry/react/RNSentryBreadcrumb.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,12 @@ public static Breadcrumb fromMap(ReadableMap from) {
5151
breadcrumb.setCategory(from.getString("category"));
5252
}
5353

54+
if (from.hasKey("origin")) {
55+
breadcrumb.setOrigin(from.getString("origin"));
56+
} else {
57+
breadcrumb.setOrigin("react-native");
58+
}
59+
5460
if (from.hasKey("level")) {
5561
switch (from.getString("level")) {
5662
case "fatal":

packages/core/android/src/main/java/io/sentry/react/RNSentryModuleImpl.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import com.facebook.react.bridge.WritableNativeArray;
2727
import com.facebook.react.bridge.WritableNativeMap;
2828
import com.facebook.react.modules.core.DeviceEventManagerModule;
29+
import io.sentry.Breadcrumb;
2930
import io.sentry.HubAdapter;
3031
import io.sentry.ILogger;
3132
import io.sentry.IScope;
@@ -75,6 +76,7 @@
7576
import java.io.InputStream;
7677
import java.nio.charset.Charset;
7778
import java.util.HashMap;
79+
import java.util.Iterator;
7880
import java.util.List;
7981
import java.util.Map;
8082
import java.util.Properties;
@@ -896,6 +898,17 @@ public void fetchNativeDeviceContexts(Promise promise) {
896898
}
897899

898900
final @Nullable IScope currentScope = InternalSentrySdk.getCurrentScope();
901+
if (currentScope != null) {
902+
// Remove react-native breadcrumbs
903+
Iterator<Breadcrumb> breadcrumbsIterator = currentScope.getBreadcrumbs().iterator();
904+
while (breadcrumbsIterator.hasNext()) {
905+
Breadcrumb breadcrumb = breadcrumbsIterator.next();
906+
if ("react-native".equals(breadcrumb.getOrigin())) {
907+
breadcrumbsIterator.remove();
908+
}
909+
}
910+
}
911+
899912
final @NotNull Map<String, Object> serialized =
900913
InternalSentrySdk.serializeScope(context, (SentryAndroidOptions) options, currentScope);
901914
final @Nullable Object deviceContext = RNSentryMapConverter.convertToWritable(serialized);

packages/core/ios/RNSentry.mm

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,17 @@ - (NSDictionary*) fetchNativeStackFramesBy: (NSArray<NSNumber*>*)instructionsAdd
386386

387387
[serializedScope setValue:contexts forKey:@"contexts"];
388388
[serializedScope removeObjectForKey:@"context"];
389+
390+
// Remove react-native breadcrumbs
391+
NSMutableArray<NSDictionary<NSString *, id> *> *breadcrumbs = [serializedScope[@"breadcrumbs"] mutableCopy];
392+
for (NSInteger i = breadcrumbs.count - 1; i >= 0; i--) {
393+
NSDictionary<NSString *, id> *breadcrumb = breadcrumbs[i];
394+
if ([breadcrumb[@"origin"] isEqualToString:@"react-native"]) {
395+
[breadcrumbs removeObjectAtIndex:i];
396+
}
397+
}
398+
[serializedScope setValue:breadcrumbs forKey:@"breadcrumbs"];
399+
389400
resolve(serializedScope);
390401
}
391402

packages/core/ios/RNSentryBreadcrumb.m

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@ +(SentryBreadcrumb*) from: (NSDictionary *) dict
2323

2424
[crumb setLevel:sentryLevel];
2525
[crumb setCategory:dict[@"category"]];
26+
id origin = dict[@"origin"];
27+
if (origin != nil) {
28+
[crumb setOrigin:origin];
29+
} else {
30+
[crumb setOrigin:@"react-native"];
31+
}
2632
[crumb setType:dict[@"type"]];
2733
[crumb setMessage:dict[@"message"]];
2834
[crumb setData:dict[@"data"]];

packages/core/src/js/integrations/devicecontext.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ async function processEvent(event: Event): Promise<Event> {
8383
? native['breadcrumbs'].map(breadcrumbFromObject)
8484
: undefined;
8585
if (nativeBreadcrumbs) {
86-
event.breadcrumbs = nativeBreadcrumbs;
86+
event.breadcrumbs = (event.breadcrumbs || []).concat(nativeBreadcrumbs);
8787
}
8888

8989
return event;

packages/core/test/integrations/devicecontext.test.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -158,13 +158,13 @@ describe('Device Context Integration', () => {
158158
).expectEvent.toStrictEqualMockEvent();
159159
});
160160

161-
it('use only native breadcrumbs', async () => {
161+
it('merge native and event breadcrumbs', async () => {
162162
const { processedEvent } = await processEventWith({
163-
nativeContexts: { breadcrumbs: [{ message: 'duplicate-breadcrumb' }, { message: 'native-breadcrumb' }] },
164-
mockEvent: { breadcrumbs: [{ message: 'duplicate-breadcrumb' }, { message: 'event-breadcrumb' }] },
163+
nativeContexts: { breadcrumbs: [{ message: 'native-breadcrumb' }] },
164+
mockEvent: { breadcrumbs: [{ message: 'event-breadcrumb' }] },
165165
});
166166
expect(processedEvent).toStrictEqual({
167-
breadcrumbs: [{ message: 'duplicate-breadcrumb' }, { message: 'native-breadcrumb' }],
167+
breadcrumbs: [{ message: 'event-breadcrumb' }, { message: 'native-breadcrumb' }],
168168
});
169169
});
170170

0 commit comments

Comments
 (0)