diff --git a/CHANGELOG.md b/CHANGELOG.md index 99e5b323fc..c540316f1e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## Unreleased + +### Fixes + +- Fix `event.origin` and `event.environment` on unhandled exception ([#3041](https://github.com/getsentry/sentry-react-native/pull/3041)) + ## 5.4.1 ### Fixes diff --git a/RNSentryTester/RNSentryTesterTests/RNSentry+initNativeSdk.mm b/RNSentryTester/RNSentryTesterTests/RNSentry+initNativeSdk.mm index a75b14f704..db570468d0 100644 --- a/RNSentryTester/RNSentryTesterTests/RNSentry+initNativeSdk.mm +++ b/RNSentryTester/RNSentryTesterTests/RNSentry+initNativeSdk.mm @@ -1,6 +1,7 @@ #import #import #import +#import #import "RNSentry.h" @interface RNSentryInitNativeSdkTests : XCTestCase @@ -134,4 +135,36 @@ - (void)testPassesErrorOnWrongDsn XCTAssertNotNil(error, @"Did not created error on invalid dsn"); } +- (void)testEventFromSentryCocoaReactNativeHasOriginAndEnvironmentTags +{ + RNSentry* rnSentry = [[RNSentry alloc] init]; + SentryEvent* testEvent = [[SentryEvent alloc] init]; + testEvent.sdk = @{ + @"name": @"sentry.cocoa.react-native" + }; + + [rnSentry setEventOriginTag: testEvent]; + + XCTAssertEqual(testEvent.tags[@"event.origin"], @"ios"); + XCTAssertEqual(testEvent.tags[@"event.environment"], @"native"); +} + +- (void)testEventFromSentryReactNativeOriginAndEnvironmentTagsAreOverwritten +{ + RNSentry* rnSentry = [[RNSentry alloc] init]; + SentryEvent* testEvent = [[SentryEvent alloc] init]; + testEvent.sdk = @{ + @"name": @"sentry.cocoa.react-native" + }; + testEvent.tags = @{ + @"event.origin": @"testEventOriginTag", + @"event.environment": @"testEventEnvironmentTag" + }; + + [rnSentry setEventOriginTag: testEvent]; + + XCTAssertEqual(testEvent.tags[@"event.origin"], @"ios"); + XCTAssertEqual(testEvent.tags[@"event.environment"], @"native"); +} + @end diff --git a/android/src/main/java/io/sentry/react/RNSentryModuleImpl.java b/android/src/main/java/io/sentry/react/RNSentryModuleImpl.java index daa1b94b0a..236d0b1279 100644 --- a/android/src/main/java/io/sentry/react/RNSentryModuleImpl.java +++ b/android/src/main/java/io/sentry/react/RNSentryModuleImpl.java @@ -10,7 +10,6 @@ import android.util.SparseIntArray; import androidx.annotation.Nullable; -import androidx.annotation.NonNull; import androidx.core.app.FrameMetricsAggregator; import com.facebook.react.bridge.Arguments; @@ -69,6 +68,8 @@ public class RNSentryModuleImpl { public static final String NAME = "RNSentry"; + private static final String NATIVE_SDK_NAME = "sentry.native.android"; + private static final String ANDROID_SDK_NAME = "sentry.java.android.react-native"; private static final ILogger logger = new AndroidLogger(NAME); private static final BuildInfoProvider buildInfo = new BuildInfoProvider(logger); private static final String modulesPath = "modules.json"; @@ -104,12 +105,11 @@ Activity getCurrentActivity() { public void initNativeSdk(final ReadableMap rnOptions, Promise promise) { SentryAndroid.init(this.getReactApplicationContext(), options -> { - @NonNull final String sdkName = "sentry.java.android.react-native"; @Nullable SdkVersion sdkVersion = options.getSdkVersion(); if (sdkVersion == null) { - sdkVersion = new SdkVersion(sdkName, BuildConfig.VERSION_NAME); + sdkVersion = new SdkVersion(ANDROID_SDK_NAME, BuildConfig.VERSION_NAME); } else { - sdkVersion.setName(sdkName); + sdkVersion.setName(ANDROID_SDK_NAME); } options.setSentryClientName(sdkVersion.getName() + "/" + sdkVersion.getVersion()); @@ -621,10 +621,10 @@ private void setEventOriginTag(SentryEvent event) { switch (sdk.getName()) { // If the event is from capacitor js, it gets set there and we do not handle it // here. - case "sentry.native": + case NATIVE_SDK_NAME: setEventEnvironmentTag(event, "native"); break; - case "sentry.java.android": + case ANDROID_SDK_NAME: setEventEnvironmentTag(event, "java"); break; default: diff --git a/ios/RNSentry.h b/ios/RNSentry.h index 0deb43541e..df9be92933 100644 --- a/ios/RNSentry.h +++ b/ios/RNSentry.h @@ -11,4 +11,6 @@ - (SentryOptions *_Nullable)createOptionsWithDictionary:(NSDictionary *_Nonnull)options error:(NSError *_Nullable*_Nonnull)errorPointer; +- (void)setEventOriginTag:(SentryEvent *)event; + @end diff --git a/ios/RNSentry.mm b/ios/RNSentry.mm index e03b1f444c..35aa601cab 100644 --- a/ios/RNSentry.mm +++ b/ios/RNSentry.mm @@ -30,6 +30,8 @@ + (void)storeEnvelope:(SentryEnvelope *)envelope; static bool didFetchAppStart; +static NSString* const nativeSdkName = @"sentry.cocoa.react-native"; + @implementation RNSentry { bool sentHybridSdkDidBecomeActive; } @@ -56,9 +58,8 @@ + (BOOL)requiresMainQueueSetup { return; } - NSString *sdkName = @"sentry.cocoa.react-native"; NSString *sdkVersion = [PrivateSentrySDKOnly getSdkVersionString]; - [PrivateSentrySDKOnly setSdkName: sdkName andVersionString: sdkVersion]; + [PrivateSentrySDKOnly setSdkName: nativeSdkName andVersionString: sdkVersion]; [SentrySDK startWithOptions:sentryOptions]; @@ -137,9 +138,9 @@ - (void)setEventOriginTag:(SentryEvent *)event { if (event.sdk != nil) { NSString *sdkName = event.sdk[@"name"]; - // If the event is from react native, it gets set there and we do not handle - // it here. - if ([sdkName isEqualToString:@"sentry.cocoa"]) { + // If the event is from react native, it gets set + // there and we do not handle it here. + if ([sdkName isEqual:nativeSdkName]) { [self setEventEnvironmentTag:event origin:@"ios" environment:@"native"]; } } diff --git a/package.json b/package.json index e8a01d0df9..4931e16f2c 100644 --- a/package.json +++ b/package.json @@ -80,7 +80,7 @@ "jest-environment-jsdom": "^29.4.1", "prettier": "^2.0.5", "react": "18.2.0", - "react-native": "0.71.0", + "react-native": "0.71.7", "replace-in-file": "^6.0.0", "rimraf": "^4.1.1", "ts-jest": "^29.0.5", diff --git a/sample-new-architecture/android/app/src/main/java/com/samplenewarchitecture/SamplePackage.java b/sample-new-architecture/android/app/src/main/java/com/samplenewarchitecture/SamplePackage.java index 40a3751d6c..fbbdc103b2 100644 --- a/sample-new-architecture/android/app/src/main/java/com/samplenewarchitecture/SamplePackage.java +++ b/sample-new-architecture/android/app/src/main/java/com/samplenewarchitecture/SamplePackage.java @@ -2,14 +2,30 @@ import com.facebook.react.ReactPackage; import com.facebook.react.bridge.NativeModule; import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReactContextBaseJavaModule; +import com.facebook.react.bridge.ReactMethod; import com.facebook.react.uimanager.ViewManager; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import io.sentry.ILogger; +import io.sentry.SentryLevel; +import io.sentry.android.core.AndroidLogger; + public class SamplePackage implements ReactPackage { + private static final ILogger logger = new AndroidLogger("SamplePackage"); + + static { + if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) { + System.loadLibrary("appmodules"); + } + } + + public native void crash(); + @Override public List createViewManagers(ReactApplicationContext reactContext) { return Collections.emptyList(); @@ -22,6 +38,20 @@ public List createNativeModules( modules.add(new AssetsModule(reactContext)); + modules.add(new ReactContextBaseJavaModule() { + @Override public String getName() { + return "CppModule"; + } + + @ReactMethod public void crashCpp() { + if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) { + crash(); + } else { + logger.log(SentryLevel.WARNING, "Enable RNNA to try this."); + } + } + }); + return modules; } diff --git a/sample-new-architecture/android/app/src/main/jni/OnLoad.cpp b/sample-new-architecture/android/app/src/main/jni/OnLoad.cpp index 6e1d156699..45f4a9c291 100644 --- a/sample-new-architecture/android/app/src/main/jni/OnLoad.cpp +++ b/sample-new-architecture/android/app/src/main/jni/OnLoad.cpp @@ -91,3 +91,10 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) { &facebook::react::registerComponents; }); } + +extern "C" +JNIEXPORT void JNICALL +Java_com_samplenewarchitecture_SamplePackage_crash(JNIEnv *env, jobject thiz) { + char *ptr = 0; + *ptr += 1; +} diff --git a/sample-new-architecture/src/Screens/HomeScreen.tsx b/sample-new-architecture/src/Screens/HomeScreen.tsx index 7a576e7e6e..31c5f72cd1 100644 --- a/sample-new-architecture/src/Screens/HomeScreen.tsx +++ b/sample-new-architecture/src/Screens/HomeScreen.tsx @@ -8,6 +8,7 @@ import { ButtonProps, StyleSheet, NativeModules, + Platform, } from 'react-native'; import * as Sentry from '@sentry/react-native'; @@ -19,7 +20,7 @@ import { UserFeedbackModal } from '../components/UserFeedbackModal'; import { FallbackRender } from '@sentry/react'; import NativeSampleModule from '../../tm/NativeSampleModule'; -const { AssetsModule } = NativeModules; +const { AssetsModule, CppModule } = NativeModules; interface Props { navigation: StackNavigationProp; @@ -118,7 +119,14 @@ const HomeScreen = (props: Props) => { NativeSampleModule?.crash(); }} /> - + {Platform.OS === 'android' && ( +