diff --git a/bin/bundle-frameworks b/bin/bundle-frameworks deleted file mode 100755 index c6720be941..0000000000 --- a/bin/bundle-frameworks +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh -set -ex -mkdir -p "${CONFIGURATION_BUILD_DIR}/${EXECUTABLE_NAME}.app/Frameworks" -cp -r "${CONFIGURATION_BUILD_DIR}/Sentry.framework" "${CONFIGURATION_BUILD_DIR}/${EXECUTABLE_NAME}.app/Frameworks" -cp -r "${CONFIGURATION_BUILD_DIR}/KSCrash.framework" "${CONFIGURATION_BUILD_DIR}/${EXECUTABLE_NAME}.app/Frameworks" -/usr/bin/xcrun codesign --force --sign "$EXPANDED_CODE_SIGN_IDENTITY" --preserve-metadata=identifier,entitlement "${CONFIGURATION_BUILD_DIR}/${EXECUTABLE_NAME}.app/Frameworks/Sentry.framework" -/usr/bin/xcrun codesign --force --sign "$EXPANDED_CODE_SIGN_IDENTITY" --preserve-metadata=identifier,entitlement "${CONFIGURATION_BUILD_DIR}/${EXECUTABLE_NAME}.app/Frameworks/KSCrash.framework" diff --git a/examples/ReactNativeExample/ios/ReactNativeExample.xcodeproj/project.pbxproj b/examples/ReactNativeExample/ios/ReactNativeExample.xcodeproj/project.pbxproj index 0d6dd8f294..6a74e77a88 100644 --- a/examples/ReactNativeExample/ios/ReactNativeExample.xcodeproj/project.pbxproj +++ b/examples/ReactNativeExample/ios/ReactNativeExample.xcodeproj/project.pbxproj @@ -24,6 +24,7 @@ 146834051AC3E58100842450 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 146834041AC3E56700842450 /* libReact.a */; }; 5E9157361DD0AC6A00FF2AA8 /* libRCTAnimation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E9157331DD0AC6500FF2AA8 /* libRCTAnimation.a */; }; 832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832341B51AAA6A8300B99B32 /* libRCTText.a */; }; + 8C44FB5926B54E818A892A25 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 2030FF38C5C7479A9E3F72F3 /* libz.tbd */; }; C0D5AD675F9445918A2A5F71 /* libRNSentry.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3D1D4EF2667C40A491FCA3A2 /* libRNSentry.a */; }; /* End PBXBuildFile section */ @@ -252,6 +253,7 @@ 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = ReactNativeExample/Info.plist; sourceTree = ""; }; 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = ReactNativeExample/main.m; sourceTree = ""; }; 146833FF1AC3E56700842450 /* React.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = React.xcodeproj; path = "../node_modules/react-native/React/React.xcodeproj"; sourceTree = ""; }; + 2030FF38C5C7479A9E3F72F3 /* libz.tbd */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; }; 389218E3ED8B4610A9B360F1 /* RNSentry.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RNSentry.xcodeproj; path = "../node_modules/react-native-sentry/ios/RNSentry.xcodeproj"; sourceTree = ""; }; 3D1D4EF2667C40A491FCA3A2 /* libRNSentry.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNSentry.a; sourceTree = ""; }; 5E91572D1DD0AC6500FF2AA8 /* RCTAnimation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTAnimation.xcodeproj; path = "../node_modules/react-native/Libraries/NativeAnimation/RCTAnimation.xcodeproj"; sourceTree = ""; }; @@ -284,6 +286,7 @@ 00C302EA1ABCBA2D00DB3ED1 /* libRCTVibration.a in Frameworks */, 139FDEF61B0652A700C62182 /* libRCTWebSocket.a in Frameworks */, C0D5AD675F9445918A2A5F71 /* libRNSentry.a in Frameworks */, + 8C44FB5926B54E818A892A25 /* libz.tbd in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -400,7 +403,7 @@ isa = PBXGroup; children = ( 5E9157331DD0AC6500FF2AA8 /* libRCTAnimation.a */, - 5E9157351DD0AC6500FF2AA8 /* libRCTAnimation-tvOS.a */, + 5E9157351DD0AC6500FF2AA8 /* libRCTAnimation.a */, ); name = Products; sourceTree = ""; @@ -413,6 +416,14 @@ name = Products; sourceTree = ""; }; + 63AF67B21EDC552500EBCFF7 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 2030FF38C5C7479A9E3F72F3 /* libz.tbd */, + ); + name = Frameworks; + sourceTree = ""; + }; 78C398B11ACF4ADC00677621 /* Products */ = { isa = PBXGroup; children = ( @@ -453,6 +464,7 @@ 83CBB9F61A601CBA00E9B192 = { isa = PBXGroup; children = ( + 63AF67B21EDC552500EBCFF7 /* Frameworks */, 13B07FAE1A68108700A75B9A /* ReactNativeExample */, 832341AE1AAA6A7D00B99B32 /* Libraries */, 00E356EF1AD99517003FC87E /* ReactNativeExampleTests */, @@ -501,6 +513,7 @@ 13B07F8E1A680F5B00A75B9A /* Resources */, 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */, 6350253C1E1E816100408AE7 /* Copy Files */, + 7F30919BF7F84991BBAB4FDF /* Upload Debug Symbols to Sentry */, ); buildRules = ( ); @@ -753,10 +766,10 @@ remoteRef = 5E9157321DD0AC6500FF2AA8 /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; - 5E9157351DD0AC6500FF2AA8 /* libRCTAnimation-tvOS.a */ = { + 5E9157351DD0AC6500FF2AA8 /* libRCTAnimation.a */ = { isa = PBXReferenceProxy; fileType = archive.ar; - path = "libRCTAnimation-tvOS.a"; + path = libRCTAnimation.a; remoteRef = 5E9157341DD0AC6500FF2AA8 /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -815,7 +828,21 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "../node_modules/react-native-sentry/bin/bundle-frameworks\nexport SENTRY_ORG=org\nexport SENTRY_PROJECT=project\nexport SENTRY_AUTH_TOKEN=token\n#export SENTRY_URL=\nexport NODE_BINARY=node\nsentry-cli react-native-xcode ../node_modules/react-native/packager/react-native-xcode.sh"; + shellScript = "#../node_modules/react-native-sentry/bin/bundle-frameworks\nexport SENTRY_ORG=org\nexport SENTRY_PROJECT=project\nexport SENTRY_AUTH_TOKEN=token\n#export SENTRY_URL=\nexport NODE_BINARY=node\nsentry-cli react-native-xcode ../node_modules/react-native/packager/react-native-xcode.sh"; + }; + 7F30919BF7F84991BBAB4FDF /* Upload Debug Symbols to Sentry */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Upload Debug Symbols to Sentry"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "export SENTRY_PROPERTIES=sentry.properties\n../node_modules/sentry-cli-binary/bin/sentry-cli upload-dsym"; }; /* End PBXShellScriptBuildPhase section */ @@ -900,7 +927,7 @@ 13B07F941A680F5B00A75B9A /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CURRENT_PROJECT_VERSION = 1; DEAD_CODE_STRIPPING = NO; @@ -923,7 +950,7 @@ 13B07F951A680F5B00A75B9A /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = 97JCY7859U; diff --git a/examples/ReactNativeExample/package.json b/examples/ReactNativeExample/package.json index 72c12f6933..5de1421768 100644 --- a/examples/ReactNativeExample/package.json +++ b/examples/ReactNativeExample/package.json @@ -8,7 +8,7 @@ }, "dependencies": { "react": "^16.0.0-alpha.6", - "react-native": "^0.44.0", + "react-native": "^0.44.1", "react-native-sentry": "file:../../" } } diff --git a/ios/RNSentry.m b/ios/RNSentry.m index 1e42e909b9..a3a9de07a4 100644 --- a/ios/RNSentry.m +++ b/ios/RNSentry.m @@ -7,7 +7,8 @@ #import "RCTConvert.h" #endif -@import Sentry; +#import +#import @interface RNSentry() @@ -45,7 +46,7 @@ + (NSRegularExpression *)frameRegex { static dispatch_once_t onceTokenRegex; static NSRegularExpression *regex = nil; dispatch_once(&onceTokenRegex, ^{ -// NSString *pattern = @"at (.+?) \\((?:(.+?):([0-9]+?):([0-9]+?))\\)"; // Regex with debugger + // NSString *pattern = @"at (.+?) \\((?:(.+?):([0-9]+?):([0-9]+?))\\)"; // Regex with debugger NSString *pattern = @"(?:([^@]+)@(.+?):([0-9]+?):([0-9]+))"; // Regex without debugger regex = [NSRegularExpression regularExpressionWithPattern:pattern options:0 error:nil]; }); @@ -61,11 +62,11 @@ + (NSRegularExpression *)frameRegex { NSArray *matches = [[RNSentry frameRegex] matchesInString:line options:0 range:searchedRange]; for (NSTextCheckingResult *match in matches) { [frames addObject:@{ - @"methodName": [line substringWithRange:[match rangeAtIndex:1]], - @"column": [formatter numberFromString:[line substringWithRange:[match rangeAtIndex:4]]], - @"lineNumber": [formatter numberFromString:[line substringWithRange:[match rangeAtIndex:3]]], - @"file": [line substringWithRange:[match rangeAtIndex:2]] - }]; + @"methodName": [line substringWithRange:[match rangeAtIndex:1]], + @"column": [formatter numberFromString:[line substringWithRange:[match rangeAtIndex:4]]], + @"lineNumber": [formatter numberFromString:[line substringWithRange:[match rangeAtIndex:3]]], + @"file": [line substringWithRange:[match rangeAtIndex:2]] + }]; } } return frames; @@ -77,16 +78,99 @@ + (NSRegularExpression *)frameRegex { for (NSDictionary *ravenFrame in ravenFrames) { if (ravenFrame[@"lineno"] != NSNull.null) { [frames addObject:@{ - @"methodName": ravenFrame[@"function"], - @"column": [formatter numberFromString:[NSString stringWithFormat:@"%@", ravenFrame[@"colno"]]], - @"lineNumber": [formatter numberFromString:[NSString stringWithFormat:@"%@", ravenFrame[@"lineno"]]], - @"file": ravenFrame[@"filename"] - }]; + @"methodName": ravenFrame[@"function"], + @"column": [formatter numberFromString:[NSString stringWithFormat:@"%@", ravenFrame[@"colno"]]], + @"lineNumber": [formatter numberFromString:[NSString stringWithFormat:@"%@", ravenFrame[@"lineno"]]], + @"file": ravenFrame[@"filename"] + }]; } } return frames; } +- (NSInteger)indexOfReactNativeCallFrame:(NSArray *)frames nativeCallAddress:(NSUInteger)nativeCallAddress { + NSInteger smallestDiff = NSIntegerMax; + NSInteger index = -1; + NSUInteger counter = 0; + for (SentryFrame *frame in frames) { + NSUInteger instructionAddress; + [[NSScanner scannerWithString:frame.instructionAddress] scanHexLongLong:&instructionAddress]; + if (instructionAddress < nativeCallAddress) { + continue; + } + NSInteger diff = instructionAddress - nativeCallAddress; + if (diff < smallestDiff) { + smallestDiff = diff; + index = counter; + } + counter++; + } + if (index > -1) { + return index + 1; + } + return index; +} + +- (NSArray *)convertReactNativeStacktrace:(NSDictionary *)stacktrace { + NSMutableArray *frames = [NSMutableArray new]; + for (NSDictionary *frame in stacktrace) { + if (nil == frame[@"methodName"]) { + continue; + } + NSString *simpleFilename = [[[frame[@"file"] lastPathComponent] componentsSeparatedByString:@"?"] firstObject]; + SentryFrame *sentryFrame = [[SentryFrame alloc] init]; + sentryFrame.fileName = [NSString stringWithFormat:@"app:///%@", simpleFilename]; + sentryFrame.function = frame[@"methodName"]; + sentryFrame.lineNumber = frame[@"lineNumber"]; + sentryFrame.columnNumber = frame[@"column"]; + sentryFrame.platform = @"javascript"; + [frames addObject:sentryFrame]; + } + return [frames reverseObjectEnumerator].allObjects; +} + +- (void)injectReactNativeFrames:(SentryEvent *)event { + NSString *address = event.extra[@"__sentry_address"]; + SentryThread *crashedThread = nil; + for (SentryThread *thread in event.threads) { + if ([thread.crashed boolValue]) { + crashedThread = thread; + break; + } + } + NSArray *frames = crashedThread.stacktrace.frames; + NSInteger indexOfReactFrames = [self indexOfReactNativeCallFrame:frames + nativeCallAddress:[address integerValue]]; + if (indexOfReactFrames == -1) { + return; + } + + NSMutableArray *finalFrames = [NSMutableArray new]; + + NSArray *reactFrames = [self convertReactNativeStacktrace:event.extra[@"__sentry_stack"]]; + for (NSInteger i = 0; i < frames.count; i++) { + [finalFrames addObject:[frames objectAtIndex:i]]; + if (i == indexOfReactFrames) { + [finalFrames addObjectsFromArray:reactFrames]; + } + } + + crashedThread.stacktrace.frames = finalFrames; +} + +- (void)setReleaseVersionDist:(SentryEvent *)event { + if (event.extra[@"__sentry_version"]) { + NSDictionary *infoDict = [[NSBundle mainBundle] infoDictionary]; + event.releaseName = [NSString stringWithFormat:@"%@-%@", infoDict[@"CFBundleIdentifier"], event.extra[@"__sentry_version"]]; + } + if (event.extra[@"__sentry_release"]) { + event.releaseName = [NSString stringWithFormat:@"%@", event.extra[@"__sentry_release"]]; + } + if (event.extra[@"__sentry_dist"]) { + event.dist = [NSString stringWithFormat:@"%@", event.extra[@"__sentry_dist"]]; + } +} + RCT_EXPORT_MODULE() - (NSDictionary *)constantsToExport @@ -96,8 +180,17 @@ + (NSRegularExpression *)frameRegex { RCT_EXPORT_METHOD(startWithDsnString:(NSString * _Nonnull)dsnString) { - [SentryClient setShared:[[SentryClient alloc] initWithDsnString:dsnString]]; - [[SentryClient shared] startCrashHandler]; + NSError *error = nil; + SentryClient *client = [[SentryClient alloc] initWithDsn:dsnString didFailWithError:&error]; + [SentryClient setSharedClient:client]; + [SentryClient.sharedClient startCrashHandlerWithError:&error]; + if (error) { + [NSException raise:@"SentryReactNative" format:@"%@", error.localizedDescription]; + } + SentryClient.sharedClient.beforeSerializeEvent = ^(SentryEvent * _Nonnull event) { + [self injectReactNativeFrames:event]; + [self setReleaseVersionDist:event]; + }; } RCT_EXPORT_METHOD(activateStacktraceMerging:(RCTPromiseResolveBlock)resolve @@ -116,9 +209,11 @@ + (NSRegularExpression *)frameRegex { if (params != nil && params.count > 0) { for (id param in params) { if ([param isKindOfClass:NSDictionary.class] && param[@"__sentry_stack"]) { - @synchronized ([SentryClient shared]) { - [[SentryClient shared] addExtra:@"__sentry_address" value:[NSNumber numberWithUnsignedInteger:callNativeModuleAddress]]; - [[SentryClient shared] addExtra:@"__sentry_stack" value:SentryParseJavaScriptStacktrace([RCTConvert NSString:param[@"__sentry_stack"]])]; + @synchronized (SentryClient.sharedClient) { + NSMutableDictionary *prevExtra = SentryClient.sharedClient.extra.mutableCopy; + [prevExtra setValue:[NSNumber numberWithUnsignedInteger:callNativeModuleAddress] forKey:@"__sentry_address"]; + [prevExtra setValue:SentryParseJavaScriptStacktrace([RCTConvert NSString:param[@"__sentry_stack"]]) forKey:@"__sentry_stack"]; + SentryClient.sharedClient.extra = prevExtra; } } else { if (param != nil) { @@ -135,43 +230,49 @@ + (NSRegularExpression *)frameRegex { RCT_EXPORT_METHOD(clearContext) { - [SentryClient shared].tags = @{}; - [SentryClient shared].extra = @{}; - [SentryClient shared].user = nil; + [SentryClient.sharedClient clearContext]; } RCT_EXPORT_METHOD(setLogLevel:(int)level) { - [SentryClient setLogLevel:level]; + [SentryClient setLogLevel:[self sentryLogLevelFromLevel:level]]; +} + +RCT_EXPORT_METHOD(setTags:(NSDictionary *_Nonnull)tags) +{ + SentryClient.sharedClient.tags = [self sanitizeDictionary:tags]; } -RCT_EXPORT_METHOD(setTags:(NSDictionary * _Nonnull)tags) +RCT_EXPORT_METHOD(setExtra:(NSDictionary *_Nonnull)extra) { - [SentryClient shared].tags = [self sanitizeDictionary:tags]; + SentryClient.sharedClient.extra = extra; } -RCT_EXPORT_METHOD(setExtra:(NSDictionary * _Nonnull)extra) +RCT_EXPORT_METHOD(addExtra:(NSString *_Nonnull)key value:(id)value) { - [SentryClient shared].extra = extra; + NSMutableDictionary *prevExtra = SentryClient.sharedClient.extra.mutableCopy; + [prevExtra setValue:value forKey:key]; + SentryClient.sharedClient.extra = prevExtra; } -RCT_EXPORT_METHOD(setUser:(NSDictionary * _Nonnull)user) +RCT_EXPORT_METHOD(setUser:(NSDictionary *_Nonnull)user) { - [SentryClient shared].user = [[SentryUser alloc] initWithId:[RCTConvert NSString:user[@"userID"]] - email:[RCTConvert NSString:user[@"email"]] - username:[RCTConvert NSString:user[@"username"]] - extra:[RCTConvert NSDictionary:user[@"extra"]]]; + SentryUser *sentryUser = [[SentryUser alloc] initWithUserId:[RCTConvert NSString:user[@"userID"]]]; + sentryUser.email = [RCTConvert NSString:user[@"email"]]; + sentryUser.username = [RCTConvert NSString:user[@"username"]]; + sentryUser.extra = [RCTConvert NSDictionary:user[@"extra"]]; + SentryClient.sharedClient.user = sentryUser; } RCT_EXPORT_METHOD(captureBreadcrumb:(NSDictionary * _Nonnull)breadcrumb) { - SentryBreadcrumb *crumb = [[SentryBreadcrumb alloc] initWithCategory:breadcrumb[@"category"] - timestamp:[NSDate dateWithTimeIntervalSince1970:[breadcrumb[@"timestamp"] integerValue]] - message:breadcrumb[@"message"] - type:breadcrumb[@"type"] - level:[self sentrySeverityFromLevel:breadcrumb[@"level"]] - data:[RCTConvert NSDictionary:breadcrumb[@"data"]]]; - [[SentryClient shared].breadcrumbs add:crumb]; + SentryBreadcrumb *crumb = [[SentryBreadcrumb alloc] initWithLevel:[self sentrySeverityFromLevel:breadcrumb[@"level"]] + category:breadcrumb[@"category"]]; + crumb.message = breadcrumb[@"message"]; + crumb.timestamp = [NSDate dateWithTimeIntervalSince1970:[breadcrumb[@"timestamp"] integerValue]]; + crumb.type = breadcrumb[@"type"]; + crumb.data = [RCTConvert NSDictionary:breadcrumb[@"data"]]; + [SentryClient.sharedClient.breadcrumbs addBreadcrumb:crumb]; } RCT_EXPORT_METHOD(captureEvent:(NSDictionary * _Nonnull)event) @@ -180,32 +281,22 @@ + (NSRegularExpression *)frameRegex { SentryUser *user = nil; if (event[@"user"] != nil) { - user = [[SentryUser alloc] initWithId:[NSString stringWithFormat:@"%@", event[@"user"][@"userID"]] - email:[NSString stringWithFormat:@"%@", event[@"user"][@"email"]] - username:[NSString stringWithFormat:@"%@", event[@"user"][@"username"]] - extra:[RCTConvert NSDictionary:event[@"user"][@"extra"]]]; + user = [[SentryUser alloc] initWithUserId:[NSString stringWithFormat:@"%@", event[@"user"][@"userID"]]]; + user.email = [NSString stringWithFormat:@"%@", event[@"user"][@"email"]]; + user.username = [NSString stringWithFormat:@"%@", event[@"user"][@"username"]]; + user.extra = [RCTConvert NSDictionary:event[@"user"][@"extra"]]; } if (event[@"message"]) { - SentryEvent *sentryEvent = [[SentryEvent alloc] init:event[@"message"] - eventID:event[@"event_id"] - timestamp:[NSDate date] - level:level - logger:event[@"logger"] - culprit:nil - serverName:nil - release:nil - buildNumber:nil - tags:[self sanitizeDictionary:event[@"tags"]] - modules:nil - extra:event[@"extra"] - fingerprint:nil - user:user - exceptions:nil - stacktrace:nil]; - [[SentryClient shared] captureEvent:sentryEvent]; + SentryEvent *sentryEvent = [[SentryEvent alloc] initWithLevel:level]; + sentryEvent.eventId = event[@"event_id"]; + sentryEvent.message = event[@"message"]; + sentryEvent.logger = event[@"logger"]; + sentryEvent.tags = [self sanitizeDictionary:event[@"tags"]]; + sentryEvent.extra = event[@"extra"]; + sentryEvent.user = user; + [SentryClient.sharedClient sendEvent:sentryEvent withCompletionHandler:NULL]; } else if (event[@"exception"]) { - // TODO what do we do here with extra/tags/users that are not global? self.lastReceivedException = event; } @@ -213,22 +304,35 @@ + (NSRegularExpression *)frameRegex { RCT_EXPORT_METHOD(crash) { - [[SentryClient shared] crash]; + [SentryClient.sharedClient crash]; } - (SentrySeverity)sentrySeverityFromLevel:(NSString *)level { if ([level isEqualToString:@"fatal"]) { - return SentrySeverityFatal; + return kSentrySeverityFatal; } else if ([level isEqualToString:@"warning"]) { - return SentrySeverityWarning; + return kSentrySeverityWarning; } else if ([level isEqualToString:@"info"]) { - return SentrySeverityInfo; + return kSentrySeverityInfo; } else if ([level isEqualToString:@"debug"]) { - return SentrySeverityDebug; + return kSentrySeverityDebug; } else if ([level isEqualToString:@"error"]) { - return SentrySeverityError; + return kSentrySeverityError; + } + return kSentrySeverityFatal; +} + +- (SentryLogLevel)sentryLogLevelFromLevel:(int)level { + switch (level) { + case 1: + return kSentryLogLevelError; + case 2: + return kSentryLogLevelDebug; + case 3: + return kSentryLogLevelVerbose; + default: + return kSentryLogLevelNone; } - return SentrySeverityFatal; } - (NSDictionary *)sanitizeDictionary:(NSDictionary *)dictionary { @@ -244,9 +348,7 @@ - (void)reportReactNativeCrashWithMessage:(NSString *)message stacktrace:(NSArra if (nil != self.lastReceivedException) { newMessage = [NSString stringWithFormat:@"%@:%@", self.lastReceivedException[@"exception"][@"values"][0][@"type"], self.lastReceivedException[@"exception"][@"values"][0][@"value"]]; } - NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: newMessage }; - NSError *error = [[NSError alloc] initWithDomain:@"" code:99 userInfo:userInfo]; - [[SentryClient shared] reportReactNativeCrashWithError:error stacktrace:stack terminateProgram:terminateProgram]; + [SentryClient.sharedClient reportUserException:@"ReactNativeException" reason:newMessage language:@"cocoa" lineOfCode:@"" stackTrace:stack logAllThreads:YES terminateProgram:terminateProgram]; } #pragma mark RCTExceptionsManagerDelegate diff --git a/ios/RNSentry.xcodeproj/project.pbxproj b/ios/RNSentry.xcodeproj/project.pbxproj index 98b63eed50..93f0097533 100644 --- a/ios/RNSentry.xcodeproj/project.pbxproj +++ b/ios/RNSentry.xcodeproj/project.pbxproj @@ -10,66 +10,12 @@ 63329BC71E47AB8D0099D77A /* RSSwizzle.m in Sources */ = {isa = PBXBuildFile; fileRef = 63329BC61E47AB8D0099D77A /* RSSwizzle.m */; }; 6350257B1E1E845F00408AE7 /* RNSentry.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = B3E7B5881CC2AC0600A0062D /* RNSentry.h */; }; 6378C6FB1EAF630500A1F1EE /* RNSentryEventEmitter.m in Sources */ = {isa = PBXBuildFile; fileRef = 6378C6FA1EAF630500A1F1EE /* RNSentryEventEmitter.m */; }; + 6387B7BC1ED84D350045A84C /* libKSCrashLib.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 632235ED1E76E24300F58A1F /* libKSCrashLib.a */; }; + 6387B8591ED8521B0045A84C /* libSentryStatic.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 6387B8561ED8520D0045A84C /* libSentryStatic.a */; }; B3E7B58A1CC2AC0600A0062D /* RNSentry.m in Sources */ = {isa = PBXBuildFile; fileRef = B3E7B5891CC2AC0600A0062D /* RNSentry.m */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ - 632232681E76C4A500F58A1F /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 632232591E76C4A500F58A1F /* Sentry.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 03E94AEC1C22595B009F8F29; - remoteInfo = "Sentry-OSX"; - }; - 6322326A1E76C4A500F58A1F /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 632232591E76C4A500F58A1F /* Sentry.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 03E94B0B1C22596A009F8F29; - remoteInfo = "Sentry-iOS"; - }; - 6322326C1E76C4A500F58A1F /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 632232591E76C4A500F58A1F /* Sentry.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 03C7150C1CE4DB540080AE60; - remoteInfo = "Sentry-tvOS"; - }; - 6322326E1E76C4A500F58A1F /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 632232591E76C4A500F58A1F /* Sentry.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 63CDAB1A1DD9D45900B63921; - remoteInfo = "Sentry-WatchOS"; - }; - 632232701E76C4A500F58A1F /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 632232591E76C4A500F58A1F /* Sentry.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 03E94AF61C22595C009F8F29; - remoteInfo = "Sentry-OSXTests"; - }; - 632232721E76C4A500F58A1F /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 632232591E76C4A500F58A1F /* Sentry.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 03E94B141C22596A009F8F29; - remoteInfo = "Sentry-iOSTests"; - }; - 632232741E76C4A500F58A1F /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 632232591E76C4A500F58A1F /* Sentry.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 03C715151CE4DB540080AE60; - remoteInfo = "Sentry-tvOSTests"; - }; - 632232761E76C4A500F58A1F /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 632232591E76C4A500F58A1F /* Sentry.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 63CDAB5E1DDB164500B63921; - remoteInfo = iOS; - }; 632235EC1E76E24300F58A1F /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 632235E51E76E24300F58A1F /* KSCrash-iOS.xcodeproj */; @@ -98,19 +44,54 @@ remoteGlobalIDString = EDF2BF211CCF15AD004BADF4; remoteInfo = KSCrash_static; }; - 632237221E76F6A900F58A1F /* PBXContainerItemProxy */ = { + 6387B7BA1ED84D2F0045A84C /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; - containerPortal = 632232591E76C4A500F58A1F /* Sentry.xcodeproj */; + containerPortal = 632235E51E76E24300F58A1F /* KSCrash-iOS.xcodeproj */; proxyType = 1; - remoteGlobalIDString = 03E94B0A1C22596A009F8F29; - remoteInfo = "Sentry-iOS"; + remoteGlobalIDString = CB6D132517EB749A00BC2C04; + remoteInfo = KSCrashLib; }; - 632237241E76F6AC00F58A1F /* PBXContainerItemProxy */ = { + 6387B84D1ED8520D0045A84C /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; - containerPortal = 632235E51E76E24300F58A1F /* KSCrash-iOS.xcodeproj */; + containerPortal = 6387B8441ED8520D0045A84C /* Sentry.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 63AA759B1EB8AEF500D153DE; + remoteInfo = Sentry; + }; + 6387B84F1ED8520D0045A84C /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 6387B8441ED8520D0045A84C /* Sentry.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 63AA76651EB8CB2F00D153DE; + remoteInfo = SentryTests; + }; + 6387B8511ED8520D0045A84C /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 6387B8441ED8520D0045A84C /* Sentry.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 63AA76B61EB9ED8E00D153DE; + remoteInfo = SentrySwift; + }; + 6387B8531ED8520D0045A84C /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 6387B8441ED8520D0045A84C /* Sentry.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 63AA76BE1EB9ED8E00D153DE; + remoteInfo = SentrySwiftTests; + }; + 6387B8551ED8520D0045A84C /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 6387B8441ED8520D0045A84C /* Sentry.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 6387B7C21ED84F910045A84C; + remoteInfo = SentryStatic; + }; + 6387B8571ED852170045A84C /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 6387B8441ED8520D0045A84C /* Sentry.xcodeproj */; proxyType = 1; - remoteGlobalIDString = 03DE7B691C84DEF700F789BA; - remoteInfo = KSCrash; + remoteGlobalIDString = 6387B7C11ED84F910045A84C; + remoteInfo = SentryStatic; }; /* End PBXContainerItemProxy section */ @@ -130,12 +111,13 @@ /* Begin PBXFileReference section */ 134814201AA4EA6300B7C361 /* libRNSentry.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRNSentry.a; sourceTree = BUILT_PRODUCTS_DIR; }; - 632232591E76C4A500F58A1F /* Sentry.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Sentry.xcodeproj; path = Sentry/Sentry.xcodeproj; sourceTree = ""; }; 632235E51E76E24300F58A1F /* KSCrash-iOS.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = "KSCrash-iOS.xcodeproj"; path = "KSCrash/iOS/KSCrash-iOS.xcodeproj"; sourceTree = ""; }; 63329BC51E47AB8D0099D77A /* RSSwizzle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RSSwizzle.h; sourceTree = ""; }; 63329BC61E47AB8D0099D77A /* RSSwizzle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RSSwizzle.m; sourceTree = ""; }; 6378C6F91EAF630500A1F1EE /* RNSentryEventEmitter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNSentryEventEmitter.h; sourceTree = ""; }; 6378C6FA1EAF630500A1F1EE /* RNSentryEventEmitter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNSentryEventEmitter.m; sourceTree = ""; }; + 6387B7971ED84BA70045A84C /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; }; + 6387B8441ED8520D0045A84C /* Sentry.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Sentry.xcodeproj; path = Sentry/Sentry.xcodeproj; sourceTree = ""; }; B3E7B5881CC2AC0600A0062D /* RNSentry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNSentry.h; sourceTree = ""; }; B3E7B5891CC2AC0600A0062D /* RNSentry.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNSentry.m; sourceTree = ""; }; /* End PBXFileReference section */ @@ -145,6 +127,8 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 6387B7BC1ED84D350045A84C /* libKSCrashLib.a in Frameworks */, + 6387B8591ED8521B0045A84C /* libSentryStatic.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -162,13 +146,14 @@ 58B511D21A9E6C8500147676 = { isa = PBXGroup; children = ( - 6378C6F91EAF630500A1F1EE /* RNSentryEventEmitter.h */, - 6378C6FA1EAF630500A1F1EE /* RNSentryEventEmitter.m */, 632232581E76C45800F58A1F /* Libraries */, 63329BC41E47AB790099D77A /* Vendor */, B3E7B5881CC2AC0600A0062D /* RNSentry.h */, B3E7B5891CC2AC0600A0062D /* RNSentry.m */, + 6378C6F91EAF630500A1F1EE /* RNSentryEventEmitter.h */, + 6378C6FA1EAF630500A1F1EE /* RNSentryEventEmitter.m */, 134814211AA4EA7D00B7C361 /* Products */, + 6387B7961ED84BA70045A84C /* Frameworks */, ); sourceTree = ""; }; @@ -176,26 +161,11 @@ isa = PBXGroup; children = ( 632235E51E76E24300F58A1F /* KSCrash-iOS.xcodeproj */, - 632232591E76C4A500F58A1F /* Sentry.xcodeproj */, + 6387B8441ED8520D0045A84C /* Sentry.xcodeproj */, ); name = Libraries; sourceTree = ""; }; - 6322325A1E76C4A500F58A1F /* Products */ = { - isa = PBXGroup; - children = ( - 632232691E76C4A500F58A1F /* Sentry.framework */, - 6322326B1E76C4A500F58A1F /* Sentry.framework */, - 6322326D1E76C4A500F58A1F /* Sentry.framework */, - 6322326F1E76C4A500F58A1F /* Sentry.framework */, - 632232711E76C4A500F58A1F /* SentryTests.xctest */, - 632232731E76C4A500F58A1F /* Sentry-iOSTests.xctest */, - 632232751E76C4A500F58A1F /* Sentry-tvOSTests.xctest */, - 632232771E76C4A500F58A1F /* iOS.app */, - ); - name = Products; - sourceTree = ""; - }; 632235E61E76E24300F58A1F /* Products */ = { isa = PBXGroup; children = ( @@ -216,6 +186,26 @@ name = Vendor; sourceTree = ""; }; + 6387B7961ED84BA70045A84C /* Frameworks */ = { + isa = PBXGroup; + children = ( + 6387B7971ED84BA70045A84C /* libz.tbd */, + ); + name = Frameworks; + sourceTree = ""; + }; + 6387B8451ED8520D0045A84C /* Products */ = { + isa = PBXGroup; + children = ( + 6387B84E1ED8520D0045A84C /* Sentry.framework */, + 6387B8501ED8520D0045A84C /* SentryTests.xctest */, + 6387B8521ED8520D0045A84C /* SentrySwift.framework */, + 6387B8541ED8520D0045A84C /* SentrySwiftTests.xctest */, + 6387B8561ED8520D0045A84C /* libSentryStatic.a */, + ); + name = Products; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -230,8 +220,8 @@ buildRules = ( ); dependencies = ( - 632237251E76F6AC00F58A1F /* PBXTargetDependency */, - 632237231E76F6A900F58A1F /* PBXTargetDependency */, + 6387B7BB1ED84D2F0045A84C /* PBXTargetDependency */, + 6387B8581ED852170045A84C /* PBXTargetDependency */, ); name = RNSentry; productName = RCTDataManager; @@ -268,8 +258,8 @@ ProjectRef = 632235E51E76E24300F58A1F /* KSCrash-iOS.xcodeproj */; }, { - ProductGroup = 6322325A1E76C4A500F58A1F /* Products */; - ProjectRef = 632232591E76C4A500F58A1F /* Sentry.xcodeproj */; + ProductGroup = 6387B8451ED8520D0045A84C /* Products */; + ProjectRef = 6387B8441ED8520D0045A84C /* Sentry.xcodeproj */; }, ); projectRoot = ""; @@ -280,88 +270,67 @@ /* End PBXProject section */ /* Begin PBXReferenceProxy section */ - 632232691E76C4A500F58A1F /* Sentry.framework */ = { + 632235ED1E76E24300F58A1F /* libKSCrashLib.a */ = { isa = PBXReferenceProxy; - fileType = wrapper.framework; - path = Sentry.framework; - remoteRef = 632232681E76C4A500F58A1F /* PBXContainerItemProxy */; + fileType = archive.ar; + path = libKSCrashLib.a; + remoteRef = 632235EC1E76E24300F58A1F /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; - 6322326B1E76C4A500F58A1F /* Sentry.framework */ = { + 632235EF1E76E24300F58A1F /* KSCrashTests.xctest */ = { + isa = PBXReferenceProxy; + fileType = wrapper.cfbundle; + path = KSCrashTests.xctest; + remoteRef = 632235EE1E76E24300F58A1F /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 632235F11E76E24300F58A1F /* KSCrash.framework */ = { isa = PBXReferenceProxy; fileType = wrapper.framework; - path = Sentry.framework; - remoteRef = 6322326A1E76C4A500F58A1F /* PBXContainerItemProxy */; + path = KSCrash.framework; + remoteRef = 632235F01E76E24300F58A1F /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; - 6322326D1E76C4A500F58A1F /* Sentry.framework */ = { + 632235F31E76E24300F58A1F /* KSCrash.framework */ = { isa = PBXReferenceProxy; fileType = wrapper.framework; - path = Sentry.framework; - remoteRef = 6322326C1E76C4A500F58A1F /* PBXContainerItemProxy */; + path = KSCrash.framework; + remoteRef = 632235F21E76E24300F58A1F /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; - 6322326F1E76C4A500F58A1F /* Sentry.framework */ = { + 6387B84E1ED8520D0045A84C /* Sentry.framework */ = { isa = PBXReferenceProxy; fileType = wrapper.framework; path = Sentry.framework; - remoteRef = 6322326E1E76C4A500F58A1F /* PBXContainerItemProxy */; + remoteRef = 6387B84D1ED8520D0045A84C /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; - 632232711E76C4A500F58A1F /* SentryTests.xctest */ = { + 6387B8501ED8520D0045A84C /* SentryTests.xctest */ = { isa = PBXReferenceProxy; fileType = wrapper.cfbundle; path = SentryTests.xctest; - remoteRef = 632232701E76C4A500F58A1F /* PBXContainerItemProxy */; + remoteRef = 6387B84F1ED8520D0045A84C /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; - 632232731E76C4A500F58A1F /* Sentry-iOSTests.xctest */ = { + 6387B8521ED8520D0045A84C /* SentrySwift.framework */ = { isa = PBXReferenceProxy; - fileType = wrapper.cfbundle; - path = "Sentry-iOSTests.xctest"; - remoteRef = 632232721E76C4A500F58A1F /* PBXContainerItemProxy */; + fileType = wrapper.framework; + path = SentrySwift.framework; + remoteRef = 6387B8511ED8520D0045A84C /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; - 632232751E76C4A500F58A1F /* Sentry-tvOSTests.xctest */ = { + 6387B8541ED8520D0045A84C /* SentrySwiftTests.xctest */ = { isa = PBXReferenceProxy; fileType = wrapper.cfbundle; - path = "Sentry-tvOSTests.xctest"; - remoteRef = 632232741E76C4A500F58A1F /* PBXContainerItemProxy */; + path = SentrySwiftTests.xctest; + remoteRef = 6387B8531ED8520D0045A84C /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; - 632232771E76C4A500F58A1F /* iOS.app */ = { - isa = PBXReferenceProxy; - fileType = wrapper.application; - path = iOS.app; - remoteRef = 632232761E76C4A500F58A1F /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 632235ED1E76E24300F58A1F /* libKSCrashLib.a */ = { + 6387B8561ED8520D0045A84C /* libSentryStatic.a */ = { isa = PBXReferenceProxy; fileType = archive.ar; - path = libKSCrashLib.a; - remoteRef = 632235EC1E76E24300F58A1F /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 632235EF1E76E24300F58A1F /* KSCrashTests.xctest */ = { - isa = PBXReferenceProxy; - fileType = wrapper.cfbundle; - path = KSCrashTests.xctest; - remoteRef = 632235EE1E76E24300F58A1F /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 632235F11E76E24300F58A1F /* KSCrash.framework */ = { - isa = PBXReferenceProxy; - fileType = wrapper.framework; - path = KSCrash.framework; - remoteRef = 632235F01E76E24300F58A1F /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 632235F31E76E24300F58A1F /* KSCrash.framework */ = { - isa = PBXReferenceProxy; - fileType = wrapper.framework; - path = KSCrash.framework; - remoteRef = 632235F21E76E24300F58A1F /* PBXContainerItemProxy */; + path = libSentryStatic.a; + remoteRef = 6387B8551ED8520D0045A84C /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXReferenceProxy section */ @@ -380,15 +349,15 @@ /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ - 632237231E76F6A900F58A1F /* PBXTargetDependency */ = { + 6387B7BB1ED84D2F0045A84C /* PBXTargetDependency */ = { isa = PBXTargetDependency; - name = "Sentry-iOS"; - targetProxy = 632237221E76F6A900F58A1F /* PBXContainerItemProxy */; + name = KSCrashLib; + targetProxy = 6387B7BA1ED84D2F0045A84C /* PBXContainerItemProxy */; }; - 632237251E76F6AC00F58A1F /* PBXTargetDependency */ = { + 6387B8581ED852170045A84C /* PBXTargetDependency */ = { isa = PBXTargetDependency; - name = KSCrash; - targetProxy = 632237241E76F6AC00F58A1F /* PBXContainerItemProxy */; + name = SentryStatic; + targetProxy = 6387B8571ED852170045A84C /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ diff --git a/ios/Sentry b/ios/Sentry index 02c952e72d..e8ed69af8c 160000 --- a/ios/Sentry +++ b/ios/Sentry @@ -1 +1 @@ -Subproject commit 02c952e72deabf4b8ae8acce1f678c6fb5d0a38f +Subproject commit e8ed69af8cf4d1d56f7bbd918d6eb342214cae13 diff --git a/lib/Sentry.js b/lib/Sentry.js index ee99b545a5..a1e7d5b40c 100644 --- a/lib/Sentry.js +++ b/lib/Sentry.js @@ -1,329 +1,364 @@ import { - NativeModules, - NativeEventEmitter + NativeModules, + NativeEventEmitter } from 'react-native'; import Raven from 'raven-js'; const { - RNSentry, - RNSentryEventEmitter + RNSentry, + RNSentryEventEmitter } = NativeModules; const DEFAULT_MODULE_IGNORES = [ - "AccessibilityManager", - "ActionSheetManager", - "AlertManager", - "AppState", - "AsyncLocalStorage", - "Clipboard", - "DevLoadingView", - "DevMenu", - "ExceptionsManager", - "I18nManager", - "ImageEditingManager", - "ImageStoreManager", - "ImageViewManager", - "IOSConstants", - "JSCExecutor", - "JSCSamplingProfiler", - "KeyboardObserver", - "LinkingManager", - "LocationObserver", - "NativeAnimatedModule", - "NavigatorManager", - "NetInfo", - "Networking", - "RedBox", - "ScrollViewManager", - "SettingsManager", - "SourceCode", - "StatusBarManager", - "Timing", - "UIManager", - "Vibration", - "WebSocketModule", - "WebViewManager" + "AccessibilityManager", + "ActionSheetManager", + "AlertManager", + "AppState", + "AsyncLocalStorage", + "Clipboard", + "DevLoadingView", + "DevMenu", + "ExceptionsManager", + "I18nManager", + "ImageEditingManager", + "ImageStoreManager", + "ImageViewManager", + "IOSConstants", + "JSCExecutor", + "JSCSamplingProfiler", + "KeyboardObserver", + "LinkingManager", + "LocationObserver", + "NativeAnimatedModule", + "NavigatorManager", + "NetInfo", + "Networking", + "RedBox", + "ScrollViewManager", + "SettingsManager", + "SourceCode", + "StatusBarManager", + "Timing", + "UIManager", + "Vibration", + "WebSocketModule", + "WebViewManager" ]; export const SentrySeverity = { - Fatal: "fatal", - Error: "error", - Warning: "warning", - Info: "info", - Debug: "debug", - Critical: "critical", + Fatal: "fatal", + Error: "error", + Warning: "warning", + Info: "info", + Debug: "debug", + Critical: "critical", } export const SentryLog = { - None: 0, - Error: 1, - Debug: 2, - Verbose: 3 + None: 0, + Error: 1, + Debug: 2, + Verbose: 3 } export class Sentry { - static install() { - if (RNSentry && RNSentry.nativeClientAvailable) { - Sentry._nativeClient = new NativeClient(Sentry._dsn, Sentry.options); - Sentry.eventEmitter = new NativeEventEmitter(RNSentryEventEmitter); - Sentry.eventEmitter.addListener(RNSentryEventEmitter.EVENT_SENT_SUCCESSFULLY, (event) => { - Sentry._lastEvent = event; - if (Sentry._eventSentSuccessfully) Sentry._eventSentSuccessfully(event); - }); - } - Sentry._ravenClient = new RavenClient(Sentry._dsn, Sentry.options); - } - - static config(dsn, options) { - if (dsn.constructor !== String) { - throw new Error('Sentry: A DSN must be provided'); - } - Sentry._dsn = dsn; - Sentry.options = { - logLevel: SentryLog.None, - instrument: false, - } - Object.assign(Sentry.options, options); - return Sentry; - } - - static isNativeClientAvailable() { - return (Sentry._nativeClient); - } - - static crash() { - throw new Error('Sentry: TEST crash'); - } - - static nativeCrash() { - if (Sentry.isNativeClientAvailable()) Sentry._nativeClient.nativeCrash(); - } - - static setEventSentSuccessfully(callback) { - Sentry._eventSentSuccessfully = callback; - } - - static setDataCallback(callback) { - Sentry._ravenClient.setDataCallback(callback); - } - - static setUserContext(user) { - Sentry._ravenClient.setUserContext(user); - if (Sentry.isNativeClientAvailable()) Sentry._nativeClient.setUserContext(user); - } - - static setTagsContext(tags) { - Sentry._ravenClient.setTagsContext(tags); - if (Sentry.isNativeClientAvailable()) Sentry._nativeClient.setTagsContext(tags); - } - - static setExtraContext(extra) { - Sentry._ravenClient.setExtraContext(extra); - if (Sentry.isNativeClientAvailable()) Sentry._nativeClient.setExtraContext(extra); - } - - static captureMessage(message, options) { - Sentry._ravenClient.captureMessage(message, options); - } - - static captureException(ex, options) { - Sentry._ravenClient.captureException(ex, options); - } - - static captureBreadcrumb(msg, options) { - Sentry._ravenClient.captureBreadcrumb(msg, options); - } - - static clearContext(clearContext) { - if (Sentry.isNativeClientAvailable()) Sentry._nativeClient.clearContext(); - Sentry._ravenClient.clearContext(); - } - - static context(options, func, args) { - return Sentry._ravenClient.context(options, func, args); - } - - static wrap(options, func, _before) { - return Sentry._ravenClient.wrap(options, func, _before); - } - - static lastException() { - if (Sentry._lastEvent) return Sentry._lastEvent; - return null; - } - - static lastEventId() { - if (Sentry._lastEvent) return Sentry._lastEvent.event_id; - return null; - } - - // Private helpers - - static _breadcrumbCallback(crumb) { - if (Sentry.isNativeClientAvailable()) Sentry._nativeClient.captureBreadcrumb(crumb); - } - - static _captureEvent(event) { - if (Sentry.isNativeClientAvailable()) Sentry._nativeClient.captureEvent(event); - } + static install() { + if (RNSentry && RNSentry.nativeClientAvailable) { + Sentry._nativeClient = new NativeClient(Sentry._dsn, Sentry.options); + Sentry.eventEmitter = new NativeEventEmitter(RNSentryEventEmitter); + Sentry.eventEmitter.addListener(RNSentryEventEmitter.EVENT_SENT_SUCCESSFULLY, (event) => { + Sentry._lastEvent = event; + if (Sentry._eventSentSuccessfully) Sentry._eventSentSuccessfully(event); + }); + } + Sentry._ravenClient = new RavenClient(Sentry._dsn, Sentry.options); + } + + static config(dsn, options) { + if (dsn.constructor !== String) { + throw new Error('Sentry: A DSN must be provided'); + } + Sentry._dsn = dsn; + Sentry.options = { + logLevel: SentryLog.None, + instrument: false + } + Object.assign(Sentry.options, options); + return Sentry; + } + + static isNativeClientAvailable() { + return (Sentry._nativeClient); + } + + static crash() { + throw new Error('Sentry: TEST crash'); + } + + static nativeCrash() { + if (Sentry.isNativeClientAvailable()) Sentry._nativeClient.nativeCrash(); + } + + static setEventSentSuccessfully(callback) { + Sentry._eventSentSuccessfully = callback; + } + + static setDataCallback(callback) { + Sentry._ravenClient.setDataCallback(callback); + } + + static setUserContext(user) { + Sentry._ravenClient.setUserContext(user); + if (Sentry.isNativeClientAvailable()) Sentry._nativeClient.setUserContext(user); + } + + static setTagsContext(tags) { + Sentry._ravenClient.setTagsContext(tags); + if (Sentry.isNativeClientAvailable()) Sentry._nativeClient.setTagsContext(tags); + } + + static setExtraContext(extra) { + Sentry._ravenClient.setExtraContext(extra); + if (Sentry.isNativeClientAvailable()) Sentry._nativeClient.setExtraContext(extra); + } + + static captureMessage(message, options) { + Sentry._ravenClient.captureMessage(message, options); + } + + static captureException(ex, options) { + Sentry._ravenClient.captureException(ex, options); + } + + static captureBreadcrumb(msg, options) { + Sentry._ravenClient.captureBreadcrumb(msg, options); + } + + static clearContext(clearContext) { + if (Sentry.isNativeClientAvailable()) Sentry._nativeClient.clearContext(); + Sentry._ravenClient.clearContext(); + } + + static context(options, func, args) { + return Sentry._ravenClient.context(options, func, args); + } + + static wrap(options, func, _before) { + return Sentry._ravenClient.wrap(options, func, _before); + } + + static lastException() { + if (Sentry._lastEvent) return Sentry._lastEvent; + return null; + } + + static lastEventId() { + if (Sentry._lastEvent) return Sentry._lastEvent.event_id; + return null; + } + + static setRelease(release) { + Sentry._setInternalOption('release', release); + Sentry._ravenClient.setRelease(release); + } + + static setDist(dist) { + Sentry._setInternalOption('dist', dist); + } + + // Private helpers + + static _setInternalOption(key, value) { + if (Sentry.isNativeClientAvailable()) { + Sentry._nativeClient.addExtraContext('__sentry_' + key, value); + } + if (undefined === Sentry.options.internal) { + Sentry.options.internal = {}; + } + Sentry.options.internal[key] = value; + } + + static _getInternalOption(key) { + return Sentry.options.internal[key]; + } + + static _breadcrumbCallback(crumb) { + if (Sentry.isNativeClientAvailable()) Sentry._nativeClient.captureBreadcrumb(crumb); + } + + static _captureEvent(event) { + if (Sentry.isNativeClientAvailable()) Sentry._nativeClient.captureEvent(event); + } } class NativeClient { - constructor(dsn, options) { - if (dsn.constructor !== String) { - throw new Error('Sentry: A DSN must be provided'); - } - if (!RNSentry) { - throw new Error('Sentry: There is no native client installed.'); - } - - this._dsn = dsn; - this._activatedMerging = false; - this.options = { - ignoreModulesExclude: [], - ignoreModulesInclude: [], - deactivateStacktraceMerging: false - } - Object.assign(this.options, options); - - RNSentry.startWithDsnString(this._dsn); - if (this.options.deactivateStacktraceMerging === false) { - this._activateStacktraceMerging(); - } - RNSentry.setLogLevel(options.logLevel); - } - - nativeCrash() { - RNSentry.crash(); - } - - captureEvent(event) { - RNSentry.captureEvent(event); - } - - setUserContext(user) { - RNSentry.setUser(user); - } - - setTagsContext(tags) { - RNSentry.setTags(tags); - } - - setExtraContext(extra) { - RNSentry.setExtra(extra); - } - - captureBreadcrumb(crumb) { - RNSentry.captureBreadcrumb(crumb); - } - - clearContext() { - RNSentry.clearContext(); - } - - _activateStacktraceMerging = async() => { - return RNSentry.activateStacktraceMerging().then(activated => { - if (this._activatedMerging) { - return; - } - this._ignoredModules = {}; - __fbBatchedBridgeConfig.remoteModuleConfig.forEach((module, moduleID) => { - if (module !== null && - this.options.ignoreModulesExclude.indexOf(module[0]) === -1 && - (DEFAULT_MODULE_IGNORES.indexOf(module[0]) >= 0 || - this.options.ignoreModulesInclude.indexOf(module[0]) >= 0)) { - this._ignoredModules[moduleID] = true; - } - }); - this._activatedMerging = true; - this._overwriteEnqueueNativeCall(); - }); - } - - _overwriteEnqueueNativeCall() { - const BatchedBridge = require('react-native/Libraries/BatchedBridge/BatchedBridge'); - const original = BatchedBridge.enqueueNativeCall; - const that = this; - BatchedBridge.enqueueNativeCall = function(moduleID: number, methodID: number, params: Array < any > , onFail: ? Function, onSucc : ? Function) { - if (that._ignoredModules[moduleID]) { - return original.apply(this, arguments); - } - params.push({ - '__sentry_stack': new Error().stack - }); - return original.apply(this, arguments); + constructor(dsn, options) { + if (dsn.constructor !== String) { + throw new Error('Sentry: A DSN must be provided'); + } + if (!RNSentry) { + throw new Error('Sentry: There is no native client installed.'); + } + + this._dsn = dsn; + this._activatedMerging = false; + this.options = { + ignoreModulesExclude: [], + ignoreModulesInclude: [], + deactivateStacktraceMerging: false + } + Object.assign(this.options, options); + + RNSentry.startWithDsnString(this._dsn); + if (this.options.deactivateStacktraceMerging === false) { + this._activateStacktraceMerging(); + } + RNSentry.setLogLevel(options.logLevel); + } + + nativeCrash() { + RNSentry.crash(); + } + + captureEvent(event) { + RNSentry.captureEvent(event); + } + + setUserContext(user) { + RNSentry.setUser(user); + } + + setTagsContext(tags) { + RNSentry.setTags(tags); + } + + setExtraContext(extra) { + RNSentry.setExtra(extra); + } + + addExtraContext(key, value) { + RNSentry.addExtra(key, value); + } + + captureBreadcrumb(crumb) { + RNSentry.captureBreadcrumb(crumb); + } + + clearContext() { + RNSentry.clearContext(); + } + + _activateStacktraceMerging = async() => { + return RNSentry.activateStacktraceMerging().then(activated => { + if (this._activatedMerging) { + return; + } + this._ignoredModules = {}; + __fbBatchedBridgeConfig.remoteModuleConfig.forEach((module, moduleID) => { + if (module !== null && + this.options.ignoreModulesExclude.indexOf(module[0]) === -1 && + (DEFAULT_MODULE_IGNORES.indexOf(module[0]) >= 0 || + this.options.ignoreModulesInclude.indexOf(module[0]) >= 0)) { + this._ignoredModules[moduleID] = true; } - } + }); + this._activatedMerging = true; + this._overwriteEnqueueNativeCall(); + }); + } + + _overwriteEnqueueNativeCall() { + const BatchedBridge = require('react-native/Libraries/BatchedBridge/BatchedBridge'); + const original = BatchedBridge.enqueueNativeCall; + const that = this; + BatchedBridge.enqueueNativeCall = function(moduleID: number, methodID: number, params: Array < any > , onFail: ? Function, onSucc : ? Function) { + if (that._ignoredModules[moduleID]) { + return original.apply(this, arguments); + } + params.push({ + '__sentry_stack': new Error().stack + }); + return original.apply(this, arguments); + } + } } class RavenClient { - constructor(dsn, options) { - if (dsn.constructor !== String) { - throw new Error('SentryClient: A DSN must be provided'); - } - this._dsn = dsn; - this.options = { - allowSecretKey: true, - allowDuplicates: Sentry.isNativeClientAvailable() - } - Object.assign(this.options, options); - Raven.addPlugin(require('./raven-plugin'), { - 'nativeClientAvailable': Sentry.isNativeClientAvailable() - }); - Raven.config(dsn, this.options).install(); - if (options.logLevel >= SentryLog.Debug) { - Raven.debug = true; - } - if (Sentry.isNativeClientAvailable()) { - // We overwrite the default transport handler when the native - // client is available, because we want to send the event with native - Raven.setTransport((options) => { - Sentry._captureEvent(options.data); - }); - Raven.setBreadcrumbCallback(Sentry._breadcrumbCallback); - const oldCaptureBreadcrumb = Raven.captureBreadcrumb; - Raven.captureBreadcrumb = function(obj) { - if (obj.data && typeof obj.data === 'object') { - obj.data = Object.assign({}, obj.data); - } - return oldCaptureBreadcrumb.apply(this, arguments); - } + constructor(dsn, options) { + if (dsn.constructor !== String) { + throw new Error('SentryClient: A DSN must be provided'); + } + this._dsn = dsn; + this.options = { + allowSecretKey: true, + allowDuplicates: Sentry.isNativeClientAvailable() + } + Object.assign(this.options, options); + Raven.addPlugin(require('./raven-plugin'), { + 'nativeClientAvailable': Sentry.isNativeClientAvailable() + }, (data) => { + if (Sentry.options.internal) { + data.dist = Sentry.options.internal['dist']; + } + }); + Raven.config(dsn, this.options).install(); + if (options.logLevel >= SentryLog.Debug) { + Raven.debug = true; + } + if (Sentry.isNativeClientAvailable()) { + // We overwrite the default transport handler when the native + // client is available, because we want to send the event with native + Raven.setTransport((options) => { + Sentry._captureEvent(options.data); + }); + Raven.setBreadcrumbCallback(Sentry._breadcrumbCallback); + const oldCaptureBreadcrumb = Raven.captureBreadcrumb; + Raven.captureBreadcrumb = function(obj) { + if (obj.data && typeof obj.data === 'object') { + obj.data = Object.assign({}, obj.data); } + return oldCaptureBreadcrumb.apply(this, arguments); + } } + } - setDataCallback(callback) { - Raven.setDataCallback(callback); - } + setDataCallback(callback) { + Raven.setDataCallback(callback); + } - setUserContext(user) { - Raven.setUserContext(user); - } + setUserContext(user) { + Raven.setUserContext(user); + } - setTagsContext(tags) { - Raven.setTagsContext(tags); - } + setTagsContext(tags) { + Raven.setTagsContext(tags); + } - setExtraContext(extra) { - Raven.setExtraContext(extra) - } + setExtraContext(extra) { + Raven.setExtraContext(extra) + } - captureException(ex, options) { - Raven.captureException(ex, options); - } + captureException(ex, options) { + Raven.captureException(ex, options); + } - captureBreadcrumb(msg, options) { - Raven.captureBreadcrumb(msg, options); - } + captureBreadcrumb(msg, options) { + Raven.captureBreadcrumb(msg, options); + } - captureMessage(message, options) { - Raven.captureMessage(message, options); - } + captureMessage(message, options) { + Raven.captureMessage(message, options); + } - context(options, func, args) { - return Raven.context(options, func, args); - } + setRelease(release) { + Raven.setRelease(release); + } - wrap(options, func, _before) { - return Raven.wrap(options, func, _before); - } + context(options, func, args) { + return Raven.context(options, func, args); + } + + wrap(options, func, _before) { + return Raven.wrap(options, func, _before); + } } diff --git a/lib/raven-plugin.js b/lib/raven-plugin.js index 1a731a06ae..33d0d11a1e 100644 --- a/lib/raven-plugin.js +++ b/lib/raven-plugin.js @@ -55,7 +55,7 @@ function urlencode(obj) { /** * Initializes React Native plugin */ -function reactNativePlugin(Raven, options) { +function reactNativePlugin(Raven, options, internalDataCallback) { options = options || {}; // react-native doesn't have a document, so can't use default Image @@ -64,7 +64,10 @@ function reactNativePlugin(Raven, options) { // Use data callback to strip device-specific paths from stack traces Raven.setDataCallback(function(data) { - reactNativePlugin._normalizeData(data, options.pathStrip) + reactNativePlugin._normalizeData(data, options.pathStrip); + if (internalDataCallback) { + internalDataCallback(data); + } }); // Check for a previously persisted payload, and report it. diff --git a/scripts/postlink b/scripts/postlink index cfbe3e09df..78f7fa4b0b 100644 --- a/scripts/postlink +++ b/scripts/postlink @@ -3,6 +3,7 @@ const fs = require('fs'); const inquirer = require('inquirer'); const xcode = require('xcode'); const chalk = require('chalk'); +const pbxFile = require('xcode/lib/pbxFile'); const PLATFORMS = ['android', 'ios']; const OBJC_HEADER = '\ @@ -223,32 +224,6 @@ function patchBuildGradle(contents) { }); } -function patchAlwaysIncludeSwift(proj) { - let nativeTargets = proj.hash.project.objects.PBXNativeTarget; - let buildConfigs = proj.pbxXCBuildConfigurationSection(); - - for (let key in nativeTargets) { - let data = nativeTargets[key]; - if (typeof data === 'string') { - continue; - } - - if (!data.productReference_comment.match(/\.app$/)) { - continue; - } - - let cfgList = proj.pbxXCConfigurationList()[data.buildConfigurationList]; - if (!cfgList) { - continue; - } - - for (let cfgRef of cfgList.buildConfigurations) { - let cfg = buildConfigs[cfgRef.value]; - cfg.buildSettings.ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = 'YES'; - } - } -} - function patchExistingXcodeBuildScripts(buildScripts) { for (let script of buildScripts) { if (!script.shellScript.match(/packager\/react-native-xcode\.sh\b/) || @@ -288,25 +263,12 @@ function addNewXcodeBuildPhaseForSymbols(buildScripts, proj) { ); } -function addNewXcodeBuildPhaseForBundleFw(buildScripts, proj) { - for (let script of buildScripts) { - if (script.shellScript.match(/react-native-sentry\/bin\/bundle-frameworks/)) { - return; - } - } - - proj.addBuildPhase( - [], - 'PBXShellScriptBuildPhase', - 'Bundle react-native-sentry Frameworks', - null, - { - shellPath: '/bin/sh', - shellScript: ( - '../node_modules/react-native-sentry/bin/bundle-frameworks' - ) - } - ); +function addZLibToXcode(proj) { + proj.addPbxGroup([], 'Frameworks', 'Application'); + proj.addFramework('libz.tbd', { + link: true, + target: proj.getFirstTarget().uuid + }); } function patchXcodeProj(contents, filename) { @@ -322,10 +284,9 @@ function patchXcodeProj(contents, filename) { proj.hash.project.objects.PBXShellScriptBuildPhase || {}) .filter((val) => val.isa); - patchAlwaysIncludeSwift(proj); patchExistingXcodeBuildScripts(buildScripts); addNewXcodeBuildPhaseForSymbols(buildScripts, proj); - addNewXcodeBuildPhaseForBundleFw(buildScripts, proj); + addZLibToXcode(proj); // we always modify the xcode file in memory but we only want to save it // in case the user wants configuration for ios. This is why we check