Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
33F58ACF2977037D008F60EA /* RNSentryTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNSentryTests.m; sourceTree = "<group>"; };
650CB718ACFBD05609BF2126 /* libPods-RNSentryCocoaTesterTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-RNSentryCocoaTesterTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
E2321E7CFA55AB617247098E /* Pods-RNSentryCocoaTesterTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RNSentryCocoaTesterTests.debug.xcconfig"; path = "Target Support Files/Pods-RNSentryCocoaTesterTests/Pods-RNSentryCocoaTesterTests.debug.xcconfig"; sourceTree = "<group>"; };
FADF868E2EBD053E00D6652D /* SentrySDKWrapper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SentrySDKWrapper.h; path = ../ios/SentrySDKWrapper.h; sourceTree = SOURCE_ROOT; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -136,6 +137,7 @@
3360843A2C32E3A8008CC412 /* RNSentryReplayBreadcrumbConverter.h */,
330F308D2C0F385A002A0D4E /* RNSentryBreadcrumb.h */,
33958C672BFCEF5A00AD1FB6 /* RNSentryOnDrawReporter.h */,
FADF868E2EBD053E00D6652D /* SentrySDKWrapper.h */,
33AFE0132B8F31AF00AAB120 /* RNSentryDependencyContainer.h */,
338739072A7D7D2800950DDD /* RNSentryReplay.h */,
);
Expand Down

Large diffs are not rendered by default.

8 changes: 0 additions & 8 deletions packages/core/ios/RNSentry+fetchNativeStack.m
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,6 @@
#import "RNSentryBreadcrumb.h"
#import "RNSentryId.h"
#import <Sentry/PrivateSentrySDKOnly.h>
#import <Sentry/SentryAppStartMeasurement.h>
#import <Sentry/SentryBreadcrumb.h>
#import <Sentry/SentryDebugMeta.h>
#import <Sentry/SentryEvent.h>
#import <Sentry/SentryException.h>
#import <Sentry/SentryFormatter.h>
#import <Sentry/SentryOptions.h>
#import <Sentry/SentryUser.h>
@import Sentry;

// This method was moved to a new category so we can use `@import Sentry` to use Sentry's Swift
Expand Down
3 changes: 1 addition & 2 deletions packages/core/ios/RNSentry.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@ typedef int (*SymbolicateCallbackType)(const void *, Dl_info *);

@interface RNSentry : RCTEventEmitter <RCTBridgeModule>

- (SentryOptions *_Nullable)createOptionsWithDictionary:(NSDictionary *_Nonnull)options
error:(NSError *_Nullable *_Nonnull)errorPointer;
- (NSMutableDictionary *)prepareOptions:(NSDictionary *)options;

- (void)setEventOriginTag:(SentryEvent *)event;

Expand Down
212 changes: 58 additions & 154 deletions packages/core/ios/RNSentry.mm
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@
#import <Sentry/SentryException.h>
#import <Sentry/SentryFormatter.h>
#import <Sentry/SentryGeo.h>
#import <Sentry/SentryOptions.h>
#import <Sentry/SentryOptionsInternal.h>
#import <Sentry/SentryScreenFrames.h>
#import <Sentry/SentryUser.h>

Expand Down Expand Up @@ -85,24 +83,68 @@ - (instancetype)init
return self;
}

- (NSMutableDictionary *)prepareOptions:(NSDictionary *)options
{
SentryBeforeSendEventCallback beforeSend = ^SentryEvent *(SentryEvent *event) {
// We don't want to send an event after startup that came from a Unhandled JS Exception of
// React Native because we sent it already before the app crashed.
if (nil != event.exceptions.firstObject.type &&
[event.exceptions.firstObject.type rangeOfString:@"Unhandled JS Exception"].location
!= NSNotFound) {
return nil;
}

// Regex and Str are set when one of them has value so we only need to check one of them.
if (self->_ignoreErrorPatternsStr || self->_ignoreErrorPatternsRegex) {
for (SentryException *exception in event.exceptions) {
if ([self shouldIgnoreError:exception.value]) {
return nil;
}
}
if ([self shouldIgnoreError:event.message.message]) {
return nil;
}
}

[self setEventOriginTag:event];
return event;
};

NSMutableDictionary *mutableOptions = [options mutableCopy];
[mutableOptions setValue:beforeSend forKey:@"beforeSend"];

// remove performance traces sample rate and traces sampler since we don't want to synchronize
// these configurations to the Native SDKs. The user could tho initialize the SDK manually and
// set themselves.
[mutableOptions removeObjectForKey:@"tracesSampleRate"];
[mutableOptions removeObjectForKey:@"tracesSampler"];
[mutableOptions removeObjectForKey:@"enableTracing"];

[self trySetIgnoreErrors:mutableOptions];

return mutableOptions;
}

RCT_EXPORT_MODULE()
RCT_EXPORT_METHOD(initNativeSdk : (NSDictionary *_Nonnull)options resolve : (
RCTPromiseResolveBlock)resolve rejecter : (RCTPromiseRejectBlock)reject)
{
NSMutableDictionary *mutableOptions = [self prepareOptions:options];
#if SENTRY_TARGET_REPLAY_SUPPORTED
BOOL isSessionReplayEnabled = [RNSentryReplay updateOptions:mutableOptions];
#else
// Defaulting to false for unsupported targets
BOOL isSessionReplayEnabled = NO;
#endif
NSError *error = nil;
SentryOptions *sentryOptions = [self createOptionsWithDictionary:options error:&error];
[SentrySDKWrapper setupWithDictionary:mutableOptions
isSessionReplayEnabled:isSessionReplayEnabled
error:&error];
if (error != nil) {
reject(@"SentryReactNative", error.localizedDescription, error);
return;
}

NSString *sdkVersion = [PrivateSentrySDKOnly getSdkVersionString];
[PrivateSentrySDKOnly setSdkName:NATIVE_SDK_NAME andVersionString:sdkVersion];
[PrivateSentrySDKOnly addSdkPackage:REACT_NATIVE_SDK_PACKAGE_NAME
version:REACT_NATIVE_SDK_PACKAGE_VERSION];

[SentrySDKWrapper startWithOptions:sentryOptions];

#if TARGET_OS_IPHONE || TARGET_OS_MACCATALYST
BOOL appIsActive =
[[UIApplication sharedApplication] applicationState] == UIApplicationStateActive;
Expand All @@ -113,8 +155,8 @@ - (instancetype)init
// If the app is active/in foreground, and we have not sent the SentryHybridSdkDidBecomeActive
// notification, send it.
if (appIsActive && !sentHybridSdkDidBecomeActive
&& (PrivateSentrySDKOnly.options.enableAutoSessionTracking
|| PrivateSentrySDKOnly.options.enableWatchdogTerminationTracking)) {
&& ([SentrySDKWrapper enableAutoSessionTracking] ||
[SentrySDKWrapper enableWatchdogTerminationTracking])) {
[[NSNotificationCenter defaultCenter] postNotificationName:@"SentryHybridSdkDidBecomeActive"
object:nil];

Expand All @@ -128,7 +170,7 @@ - (instancetype)init
resolve(@YES);
}

- (void)trySetIgnoreErrors:(NSMutableDictionary *)options
- (void)trySetIgnoreErrors:(NSDictionary *)options
{
NSArray *ignoreErrorsStr = nil;
NSArray *ignoreErrorsRegex = nil;
Expand Down Expand Up @@ -194,144 +236,6 @@ - (BOOL)shouldIgnoreError:(NSString *)message
return NO;
}

- (SentryOptions *_Nullable)createOptionsWithDictionary:(NSDictionary *_Nonnull)options
error:(NSError *_Nonnull *_Nonnull)errorPointer
{
SentryBeforeSendEventCallback beforeSend = ^SentryEvent *(SentryEvent *event) {
// We don't want to send an event after startup that came from a Unhandled JS Exception of
// React Native because we sent it already before the app crashed.
if (nil != event.exceptions.firstObject.type &&
[event.exceptions.firstObject.type rangeOfString:@"Unhandled JS Exception"].location
!= NSNotFound) {
return nil;
}

// Regex and Str are set when one of them has value so we only need to check one of them.
if (self->_ignoreErrorPatternsStr || self->_ignoreErrorPatternsRegex) {
for (SentryException *exception in event.exceptions) {
if ([self shouldIgnoreError:exception.value]) {
return nil;
}
}
if ([self shouldIgnoreError:event.message.message]) {
return nil;
}
}

[self setEventOriginTag:event];
return event;
};

NSMutableDictionary *mutableOptions = [options mutableCopy];
[mutableOptions setValue:beforeSend forKey:@"beforeSend"];

// remove performance traces sample rate and traces sampler since we don't want to synchronize
// these configurations to the Native SDKs. The user could tho initialize the SDK manually and
// set themselves.
[mutableOptions removeObjectForKey:@"tracesSampleRate"];
[mutableOptions removeObjectForKey:@"tracesSampler"];
[mutableOptions removeObjectForKey:@"enableTracing"];

#if SENTRY_TARGET_REPLAY_SUPPORTED
BOOL isSessionReplayEnabled = [RNSentryReplay updateOptions:mutableOptions];
#else
// Defaulting to false for unsupported targets
BOOL isSessionReplayEnabled = NO;
#endif

SentryOptions *sentryOptions = [SentryOptionsInternal initWithDict:mutableOptions
didFailWithError:errorPointer];
if (*errorPointer != nil) {
return nil;
}

// Exclude Dev Server and Sentry Dsn request from Breadcrumbs
NSString *dsn = [self getURLFromDSN:[mutableOptions valueForKey:@"dsn"]];
NSString *devServerUrl = [mutableOptions valueForKey:@"devServerUrl"];
sentryOptions.beforeBreadcrumb
= ^SentryBreadcrumb *_Nullable(SentryBreadcrumb *_Nonnull breadcrumb)
{
NSString *url = breadcrumb.data[@"url"] ?: @"";

if ([@"http" isEqualToString:breadcrumb.type]
&& ((dsn != nil && [url hasPrefix:dsn])
|| (devServerUrl != nil && [url hasPrefix:devServerUrl]))) {
return nil;
}
return breadcrumb;
};

if ([mutableOptions valueForKey:@"enableNativeCrashHandling"] != nil) {
BOOL enableNativeCrashHandling = [mutableOptions[@"enableNativeCrashHandling"] boolValue];

if (!enableNativeCrashHandling) {
sentryOptions.enableCrashHandler = NO;
}
}

// Set spotlight option
if ([mutableOptions valueForKey:@"spotlight"] != nil) {
id spotlightValue = [mutableOptions valueForKey:@"spotlight"];
if ([spotlightValue isKindOfClass:[NSString class]]) {
NSLog(@"Using Spotlight on address: %@", spotlightValue);
sentryOptions.enableSpotlight = true;
sentryOptions.spotlightUrl = spotlightValue;
} else if ([spotlightValue isKindOfClass:[NSNumber class]]) {
sentryOptions.enableSpotlight = [spotlightValue boolValue];
id defaultSpotlightUrl = [mutableOptions valueForKey:@"defaultSidecarUrl"];
if (defaultSpotlightUrl != nil) {
sentryOptions.spotlightUrl = defaultSpotlightUrl;
}
}
}

if ([mutableOptions valueForKey:@"enableLogs"] != nil) {
id enableLogsValue = [mutableOptions valueForKey:@"enableLogs"];
if ([enableLogsValue isKindOfClass:[NSNumber class]]) {
[RNSentryExperimentalOptions setEnableLogs:[enableLogsValue boolValue]
sentryOptions:sentryOptions];
}
}
[self trySetIgnoreErrors:mutableOptions];

// Enable the App start and Frames tracking measurements
if ([mutableOptions valueForKey:@"enableAutoPerformanceTracing"] != nil) {
BOOL enableAutoPerformanceTracing =
[mutableOptions[@"enableAutoPerformanceTracing"] boolValue];
PrivateSentrySDKOnly.appStartMeasurementHybridSDKMode = enableAutoPerformanceTracing;
#if TARGET_OS_IPHONE || TARGET_OS_MACCATALYST
PrivateSentrySDKOnly.framesTrackingMeasurementHybridSDKMode = enableAutoPerformanceTracing;
#endif
}

// Failed requests can only be enabled in one SDK to avoid duplicates
sentryOptions.enableCaptureFailedRequests = NO;

NSDictionary *experiments = options[@"_experiments"];
if (experiments != nil && [experiments isKindOfClass:[NSDictionary class]]) {
BOOL enableUnhandledCPPExceptions =
[experiments[@"enableUnhandledCPPExceptionsV2"] boolValue];
[RNSentryExperimentalOptions setEnableUnhandledCPPExceptionsV2:enableUnhandledCPPExceptions
sentryOptions:sentryOptions];
}

if (isSessionReplayEnabled) {
[RNSentryExperimentalOptions setEnableSessionReplayInUnreliableEnvironment:YES
sentryOptions:sentryOptions];
}

return sentryOptions;
}

- (NSString *_Nullable)getURLFromDSN:(NSString *)dsn
{
NSURL *url = [NSURL URLWithString:dsn];
if (!url) {
return nil;
}
return [NSString stringWithFormat:@"%@://%@", url.scheme, url.host];
}

- (void)setEventOriginTag:(SentryEvent *)event
{
if (event.sdk != nil) {
Expand Down Expand Up @@ -460,7 +364,7 @@ - (void)stopObserving
contexts[@"os"] = os;
}

NSString *releaseName = SentrySDKInternal.options.releaseName;
NSString *releaseName = [SentrySDKWrapper releaseName];
if (releaseName) {
contexts[@"release"] = releaseName;
}
Expand Down Expand Up @@ -492,7 +396,7 @@ - (void)stopObserving
RCT_EXPORT_METHOD(fetchNativeDeviceContexts : (RCTPromiseResolveBlock)resolve rejecter : (
RCTPromiseRejectBlock)reject)
{
if (PrivateSentrySDKOnly.options.debug) {
if ([SentrySDKWrapper debug]) {
NSLog(@"Bridge call to: deviceContexts");
}
__block NSMutableDictionary<NSString *, id> *serializedScope;
Expand All @@ -507,7 +411,7 @@ - (void)stopObserving
forKey:@"user"];
}

if (PrivateSentrySDKOnly.options.debug) {
if ([SentrySDKWrapper debug]) {
NSData *data = [NSJSONSerialization dataWithJSONObject:serializedScope
options:0
error:nil];
Expand Down
16 changes: 16 additions & 0 deletions packages/core/ios/SentrySDKWrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,20 @@

+ (void)startWithOptions:(SentryOptions *)options;

+ (SentryOptions *)createOptionsWithDictionary:(NSDictionary *)options
isSessionReplayEnabled:(BOOL)isSessionReplayEnabled
error:(NSError **)errorPointer;

+ (void)setupWithDictionary:(NSDictionary *)options
isSessionReplayEnabled:(BOOL)isSessionReplayEnabled
error:(NSError **)errorPointer;

+ (BOOL)debug;

+ (NSString *)releaseName;

+ (BOOL)enableAutoSessionTracking;

+ (BOOL)enableWatchdogTerminationTracking;

@end
Loading
Loading