Skip to content

Commit

Permalink
Merge fb0057d into 1faf8e3
Browse files Browse the repository at this point in the history
  • Loading branch information
antonis authored Oct 31, 2024
2 parents 1faf8e3 + fb0057d commit 168e871
Show file tree
Hide file tree
Showing 11 changed files with 104 additions and 6 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

### Fixes

- 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))
- Skips ignoring require cycle logs for RN 0.70 or newer ([#4214](https://github.com/getsentry/sentry-react-native/pull/4214))
- Enhanced accuracy of time-to-display spans. ([#4189](https://github.com/getsentry/sentry-react-native/pull/4189))

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.sentry.rnsentryandroidtester

import com.facebook.react.bridge.JavaOnlyMap
import io.sentry.SentryLevel
import io.sentry.react.RNSentryBreadcrumb
import junit.framework.TestCase.assertEquals
import org.junit.Test
Expand All @@ -10,6 +11,38 @@ import org.junit.runners.JUnit4
@RunWith(JUnit4::class)
class RNSentryBreadcrumbTest {

@Test
fun generatesSentryBreadcrumbFromMap() {
val testData = JavaOnlyMap.of(
"test", "data",
)
val map = JavaOnlyMap.of(
"level", "error",
"category", "testCategory",
"origin", "testOrigin",
"type", "testType",
"message", "testMessage",
"data", testData,
)
val actual = RNSentryBreadcrumb.fromMap(map)
assertEquals(SentryLevel.ERROR, actual.level)
assertEquals("testCategory", actual.category)
assertEquals("testOrigin", actual.origin)
assertEquals("testType", actual.type)
assertEquals("testMessage", actual.message)
assertEquals(testData.toHashMap(), actual.data)
}

@Test
fun reactNativeForMissingOrigin() {
val map = JavaOnlyMap.of(
"message", "testMessage",
)
val actual = RNSentryBreadcrumb.fromMap(map)
assertEquals("testMessage", actual.message)
assertEquals("react-native", actual.origin)
}

@Test
fun nullForMissingCategory() {
val map = JavaOnlyMap.of()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
33AFDFED2B8D14B300AAB120 /* RNSentryFramesTrackerListenerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 33AFDFEC2B8D14B300AAB120 /* RNSentryFramesTrackerListenerTests.m */; };
33AFDFF12B8D15E500AAB120 /* RNSentryDependencyContainerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 33AFDFF02B8D15E500AAB120 /* RNSentryDependencyContainerTests.m */; };
33F58AD02977037D008F60EA /* RNSentryTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 33F58ACF2977037D008F60EA /* RNSentryTests.mm */; };
AEFB00422CC90C4B00EC8A9A /* RNSentryBreadcrumbTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3360843C2C340C76008CC412 /* RNSentryBreadcrumbTests.swift */; };
B5859A50A3E865EF5E61465A /* libPods-RNSentryCocoaTesterTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 650CB718ACFBD05609BF2126 /* libPods-RNSentryCocoaTesterTests.a */; };
/* End PBXBuildFile section */

Expand Down Expand Up @@ -212,6 +213,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
AEFB00422CC90C4B00EC8A9A /* RNSentryBreadcrumbTests.swift in Sources */,
33AFDFF12B8D15E500AAB120 /* RNSentryDependencyContainerTests.m in Sources */,
336084392C32E382008CC412 /* RNSentryReplayBreadcrumbConverterTests.swift in Sources */,
33F58AD02977037D008F60EA /* RNSentryTests.mm in Sources */,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import XCTest
import Sentry

class RNSentryBreadcrumbTests: XCTestCase {
final class RNSentryBreadcrumbTests: XCTestCase {

func testGeneratesSentryBreadcrumbFromNSDictionary() {
let actualCrumb = RNSentryBreadcrumb.from([
"level": "error",
"category": "testCategory",
"origin": "testOrigin",
"type": "testType",
"message": "testMessage",
"data": [
Expand All @@ -16,11 +17,29 @@ class RNSentryBreadcrumbTests: XCTestCase {

XCTAssertEqual(actualCrumb!.level, SentryLevel.error)
XCTAssertEqual(actualCrumb!.category, "testCategory")
XCTAssertEqual(actualCrumb!.origin, "testOrigin")
XCTAssertEqual(actualCrumb!.type, "testType")
XCTAssertEqual(actualCrumb!.message, "testMessage")
XCTAssertEqual((actualCrumb!.data)!["test"] as! String, "data")
}

func testUsesReactNativeAsDefaultOrigin() {
let actualCrumb = RNSentryBreadcrumb.from([
"message": "testMessage"
])

XCTAssertEqual(actualCrumb!.origin, "react-native")
}

func testKeepsOriginIfSet() {
let actualCrumb = RNSentryBreadcrumb.from([
"message": "testMessage",
"origin": "someOrigin"
])

XCTAssertEqual(actualCrumb!.origin, "someOrigin")
}

func testUsesInfoAsDefaultSentryLevel() {
let actualCrumb = RNSentryBreadcrumb.from([
"message": "testMessage"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,12 @@ public static Breadcrumb fromMap(ReadableMap from) {
breadcrumb.setCategory(from.getString("category"));
}

if (from.hasKey("origin")) {
breadcrumb.setOrigin(from.getString("origin"));
} else {
breadcrumb.setOrigin("react-native");
}

if (from.hasKey("level")) {
switch (from.getString("level")) {
case "fatal":
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import com.facebook.react.bridge.WritableNativeArray;
import com.facebook.react.bridge.WritableNativeMap;
import com.facebook.react.modules.core.DeviceEventManagerModule;
import io.sentry.Breadcrumb;
import io.sentry.HubAdapter;
import io.sentry.ILogger;
import io.sentry.IScope;
Expand Down Expand Up @@ -75,6 +76,7 @@
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
Expand Down Expand Up @@ -896,6 +898,17 @@ public void fetchNativeDeviceContexts(Promise promise) {
}

final @Nullable IScope currentScope = InternalSentrySdk.getCurrentScope();
if (currentScope != null) {
// Remove react-native breadcrumbs
Iterator<Breadcrumb> breadcrumbsIterator = currentScope.getBreadcrumbs().iterator();
while (breadcrumbsIterator.hasNext()) {
Breadcrumb breadcrumb = breadcrumbsIterator.next();
if ("react-native".equals(breadcrumb.getOrigin())) {
breadcrumbsIterator.remove();
}
}
}

final @NotNull Map<String, Object> serialized =
InternalSentrySdk.serializeScope(context, (SentryAndroidOptions) options, currentScope);
final @Nullable Object deviceContext = RNSentryMapConverter.convertToWritable(serialized);
Expand Down
11 changes: 11 additions & 0 deletions packages/core/ios/RNSentry.mm
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,17 @@ - (NSDictionary*) fetchNativeStackFramesBy: (NSArray<NSNumber*>*)instructionsAdd

[serializedScope setValue:contexts forKey:@"contexts"];
[serializedScope removeObjectForKey:@"context"];

// Remove react-native breadcrumbs
NSMutableArray<NSDictionary<NSString *, id> *> *breadcrumbs = [serializedScope[@"breadcrumbs"] mutableCopy];
for (NSInteger i = breadcrumbs.count - 1; i >= 0; i--) {
NSDictionary<NSString *, id> *breadcrumb = breadcrumbs[i];
if ([breadcrumb[@"origin"] isEqualToString:@"react-native"]) {
[breadcrumbs removeObjectAtIndex:i];
}
}
[serializedScope setValue:breadcrumbs forKey:@"breadcrumbs"];

resolve(serializedScope);
}

Expand Down
6 changes: 6 additions & 0 deletions packages/core/ios/RNSentryBreadcrumb.m
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ +(SentryBreadcrumb*) from: (NSDictionary *) dict

[crumb setLevel:sentryLevel];
[crumb setCategory:dict[@"category"]];
id origin = dict[@"origin"];
if (origin != nil) {
[crumb setOrigin:origin];
} else {
[crumb setOrigin:@"react-native"];
}
[crumb setType:dict[@"type"]];
[crumb setMessage:dict[@"message"]];
[crumb setData:dict[@"data"]];
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/js/integrations/devicecontext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ async function processEvent(event: Event): Promise<Event> {
? native['breadcrumbs'].map(breadcrumbFromObject)
: undefined;
if (nativeBreadcrumbs) {
event.breadcrumbs = nativeBreadcrumbs;
event.breadcrumbs = (event.breadcrumbs || []).concat(nativeBreadcrumbs);
}

return event;
Expand Down
8 changes: 4 additions & 4 deletions packages/core/test/integrations/devicecontext.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,13 +158,13 @@ describe('Device Context Integration', () => {
).expectEvent.toStrictEqualMockEvent();
});

it('use only native breadcrumbs', async () => {
it('merge native and event breadcrumbs', async () => {
const { processedEvent } = await processEventWith({
nativeContexts: { breadcrumbs: [{ message: 'duplicate-breadcrumb' }, { message: 'native-breadcrumb' }] },
mockEvent: { breadcrumbs: [{ message: 'duplicate-breadcrumb' }, { message: 'event-breadcrumb' }] },
nativeContexts: { breadcrumbs: [{ message: 'native-breadcrumb' }] },
mockEvent: { breadcrumbs: [{ message: 'event-breadcrumb' }] },
});
expect(processedEvent).toStrictEqual({
breadcrumbs: [{ message: 'duplicate-breadcrumb' }, { message: 'native-breadcrumb' }],
breadcrumbs: [{ message: 'event-breadcrumb' }, { message: 'native-breadcrumb' }],
});
});

Expand Down
7 changes: 7 additions & 0 deletions samples/react-native/src/Screens/ErrorsScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,13 @@ const ErrorsScreen = (_props: Props) => {
Sentry.captureException(error);
}}
/>
<Button
title="Capture exception with breadcrumb"
onPress={() => {
Sentry.captureException(new Error('Captured exception with breadcrumb'),
context => context.addBreadcrumb({ message: 'error with breadcrumb' }));
}}
/>
<Button
title="Uncaught Thrown Error"
onPress={() => {
Expand Down

0 comments on commit 168e871

Please sign in to comment.