From 88c614ae00ffc76211dddb32ca0b2fa1c8b1c8c0 Mon Sep 17 00:00:00 2001 From: Daniel Griesser Date: Wed, 29 Mar 2017 17:38:05 +0200 Subject: [PATCH 01/10] Remove decision of native client is used or not instead always setup raven --- lib/Sentry.js | 86 ++++++++++++++++++++++++++++++++------------- lib/raven-plugin.js | 7 ++++ 2 files changed, 69 insertions(+), 24 deletions(-) diff --git a/lib/Sentry.js b/lib/Sentry.js index 78dd7ea577..f5a1a92969 100644 --- a/lib/Sentry.js +++ b/lib/Sentry.js @@ -60,11 +60,10 @@ export const SentryLog = { export class Sentry { static install() { - if (RNSentry && RNSentry.nativeClientAvailable && Sentry.options.forceRavenClient === false) { - Sentry._client = new NativeClient(Sentry._dsn, Sentry.options); - } else { - Sentry._client = new RavenClient(Sentry._dsn, Sentry.options); + if (RNSentry && RNSentry.nativeClientAvailable) { + Sentry._nativeClient = new NativeClient(Sentry._dsn, Sentry.options); } + Sentry._ravenClient = new RavenClient(Sentry._dsn, Sentry.options); } static config(dsn, options) { @@ -74,35 +73,49 @@ export class Sentry { Sentry._dsn = dsn; Sentry.options = { logLevel: SentryLog.None, - forceRavenClient: false, } Object.assign(Sentry.options, options); - Sentry._originalConsole = console || {}; return Sentry; } + static isNativeClientAvailable = () => { + return (Sentry._nativeClient); + } + static crash = () => { - Sentry._client.crash(); + Sentry._ravenClient.crash(); } static nativeCrash = () => { - Sentry._client.nativeCrash(); + Sentry._ravenClient.nativeCrash(); } static setUserContext = (user) => { - Sentry._client.setUserContext(user); + Sentry._ravenClient.setUserContext(user); } static setTagsContext = (tags) => { - Sentry._client.setTagsContext(tags); + Sentry._ravenClient.setTagsContext(tags); } static setExtraContext = (extras) => { - Sentry._client.setExtraContext(extras); + Sentry._ravenClient.setExtraContext(extras); } static captureMessage = (message, options) => { - Sentry._client.captureMessage(message, options); + Sentry._ravenClient.captureMessage(message, options); + } + + static context = (options, func, args) => { + Sentry._ravenClient.context(options, func, args); + } + + static captureException = (ex, options) => { + Sentry._ravenClient.captureException(ex, options); + } + + static captureBreadcrumb = (msg, options) => { + Sentry._ravenClient.captureBreadcrumb(msg, options); } static log = (level, message) => { @@ -110,7 +123,7 @@ export class Sentry { if (Sentry.options.logLevel < level) { return; } - Sentry._originalConsole.log(message); + Raven._originalConsole.log(message); } } } @@ -183,7 +196,7 @@ class NativeClient { this._ignoredModules = {}; __fbBatchedBridgeConfig.remoteModuleConfig.forEach((module, moduleID) => { if (module !== null && - this.options.ignoreModulesExclude.indexOf(module[0]) == -1 && + 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; @@ -203,7 +216,8 @@ class NativeClient { return original.apply(this, arguments); } params.push({ - '__sentry_stack': new Error().stack + '__sentry_stack': new Error().stack, + '__sentry_breadcrumbs': Raven._breadcrumbs // send breadcrumbs }); return original.apply(this, arguments); } @@ -220,13 +234,22 @@ class RavenClient { allowSecretKey: true, } Object.assign(this.options, options); - Raven.addPlugin(require('./raven-plugin')); + Raven.addPlugin(require('./raven-plugin'), { + 'nativeClientAvailable': Sentry.isNativeClientAvailable() + }); Raven.config(dsn, this.options).install(); + 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) => { + console.log(options); + }); + } } crash = () => { - Sentry.log(SentryLog.Debug, 'Sentry: RavenClient: call crash'); - throw new Error("Sentry: RavenClient: TEST crash"); + Sentry.log(SentryLog.Debug, 'Sentry: call crash'); + throw new Error("Sentry: TEST crash"); } nativeCrash = () => { @@ -235,22 +258,37 @@ class RavenClient { } setUserContext = (user) => { - Sentry.log(SentryLog.Debug, ['Sentry: RavenClient: call setUserContext', user]); + Sentry.log(SentryLog.Debug, ['Sentry: call setUserContext', user]); Raven.setUserContext(user); } setTagsContext = (tags) => { - Sentry.log(SentryLog.Debug, ['Sentry: RavenClient: call setTagsContext', tags]); + Sentry.log(SentryLog.Debug, ['Sentry: call setTagsContext', tags]); Raven.setTagsContext(tags); } - setExtraContext = (extras) => { - Sentry.log(SentryLog.Debug, ['Sentry: RavenClient: call setExtraContext', extras]); - Raven.setExtraContext(extras) + setExtraContext = (extra) => { + Sentry.log(SentryLog.Debug, ['Sentry: call setExtraContext', extra]); + Raven.setExtraContext(extra) + } + + context = (options, func, args) => { + Sentry.log(SentryLog.Debug, ['Sentry: call context', options, func, args]); + Raven.context(options, func, args); + } + + captureException = (ex, options) => { + Sentry.log(SentryLog.Debug, ['Sentry: call captureException', ex, options]); + Raven.captureException(ex, options); + } + + captureBreadcrumb = (msg, options) => { + Sentry.log(SentryLog.Debug, ['Sentry: call captureBreadcrumb', msg, options]); + Raven.captureBreadcrumb(msg, options); } captureMessage = async(message, options) => { - Sentry.log(SentryLog.Debug, ['Sentry: RavenClient: call captureMessage', message, options]); + Sentry.log(SentryLog.Debug, ['Sentry: call captureMessage', message, options]); if (options && options.level) { switch (options.level) { case SentrySeverity.Warning: diff --git a/lib/raven-plugin.js b/lib/raven-plugin.js index 1a731a06ae..ba7b243969 100644 --- a/lib/raven-plugin.js +++ b/lib/raven-plugin.js @@ -80,6 +80,13 @@ function reactNativePlugin(Raven, options) { }) ['catch'](function() {}); + + if (options.nativeClientAvailable) { + return; + // if native client is available we don't want to overwrite the ErrorUtils + // error handler + } + // Make sure that if multiple fatals occur, we only persist the first one. // // The first error is probably the most important/interesting error, and we From 4b70baf1f16f5c33d81ee5fb4397cc8541501432 Mon Sep 17 00:00:00 2001 From: Daniel Griesser Date: Thu, 30 Mar 2017 13:48:31 +0200 Subject: [PATCH 02/10] Add captureException, Simplify call logic raven -> native --- ios/RNSentry.m | 101 ++++++++++++++++++++++++++++++++++++----- lib/Sentry.js | 119 ++++++++++++++++++------------------------------- 2 files changed, 135 insertions(+), 85 deletions(-) diff --git a/ios/RNSentry.m b/ios/RNSentry.m index 5333e7cb8f..96a1c26ec0 100644 --- a/ios/RNSentry.m +++ b/ios/RNSentry.m @@ -54,7 +54,7 @@ + (NSRegularExpression *)frameRegex { [frames addObject:@{ @"methodName": [line substringWithRange:[match rangeAtIndex:1]], @"column": [formatter numberFromString:[line substringWithRange:[match rangeAtIndex:4]]], - @"lineNumber": [formatter numberFromString:[line substringWithRange:[match rangeAtIndex:3]]], + @"lineNumber": [formatter numberFromString:[line substringWithRange:[match rangeAtIndex:3]]], @"file": [line substringWithRange:[match rangeAtIndex:2]] }]; } @@ -62,6 +62,29 @@ + (NSRegularExpression *)frameRegex { return frames; } +NSArray *SentryParseRavenFrames(NSArray *ravenFrames) { + NSNumberFormatter *formatter = [RNSentry numberFormatter]; + NSMutableArray *frames = [NSMutableArray array]; + for (NSDictionary *ravenFrame in ravenFrames) { + if (ravenFrame[@"lineno"] != NSNull.null) { +// SentryFrame *frame = [[SentryFrame alloc] initWithFileName:ravenFrame[@"filename"] +// function:ravenFrame[@"function"] +// module:nil +// line:[[formatter numberFromString:[NSString stringWithFormat:@"%@", ravenFrame[@"lineno"]]] integerValue] +// column: [[formatter numberFromString:[NSString stringWithFormat:@"%@", ravenFrame[@"colno"]]] integerValue]]; +// [frame setPlatform:@"javascript"]; +// [frames addObject:frame]; + [frames addObject:@{ + @"methodName": ravenFrame[@"function"], + @"column": [formatter numberFromString:[NSString stringWithFormat:@"%@", ravenFrame[@"colno"]]], + @"lineNumber": [formatter numberFromString:[NSString stringWithFormat:@"%@", ravenFrame[@"lineno"]]], + @"file": ravenFrame[@"filename"] + }]; + } + } + return frames; +} + RCT_EXPORT_MODULE() - (NSDictionary *)constantsToExport @@ -109,24 +132,19 @@ + (NSRegularExpression *)frameRegex { resolve(@YES); } -RCT_EXPORT_METHOD(captureMessage:(NSString * _Nonnull)message level:(int)level) -{ - [[SentryClient shared] captureMessage:[RCTConvert NSString:message] level:level]; -} - RCT_EXPORT_METHOD(setLogLevel:(int)level) { [SentryClient setLogLevel:level]; } -RCT_EXPORT_METHOD(setExtras:(NSDictionary * _Nonnull)extras) +RCT_EXPORT_METHOD(setTags:(NSDictionary * _Nonnull)tags) { - [SentryClient shared].extra = [RCTConvert NSDictionary:extras]; + [SentryClient shared].tags = [self sanitizeDictionary:[RCTConvert NSDictionary:tags]]; } -RCT_EXPORT_METHOD(setTags:(NSDictionary * _Nonnull)tags) +RCT_EXPORT_METHOD(setExtras:(NSDictionary * _Nonnull)extras) { - [SentryClient shared].tags = [self sanitizeDictionary:[RCTConvert NSDictionary:tags]]; + [SentryClient shared].extra = [RCTConvert NSDictionary:extras]; } RCT_EXPORT_METHOD(setUser:(NSDictionary * _Nonnull)user) @@ -137,6 +155,69 @@ + (NSRegularExpression *)frameRegex { extra:[RCTConvert NSDictionary:user[@"extra"]]]; } +RCT_EXPORT_METHOD(captureEvent:(NSDictionary * _Nonnull)event) +{ + NSDictionary *capturedEvent = [RCTConvert NSDictionary:event]; + + + SentrySeverity level = SentrySeverityError; + switch ([capturedEvent[@"level"] integerValue]) { + case 0: + level = SentrySeverityFatal; + break; + case 2: + level = SentrySeverityWarning; + break; + case 3: + level = SentrySeverityInfo; + break; + case 4: + level = SentrySeverityDebug; + break; + default: + break; + } + + SentryUser *user = nil; + if (capturedEvent[@"user"] != nil) { + user = [[SentryUser alloc] initWithId:[RCTConvert NSString:capturedEvent[@"user"][@"userID"]] + email:[RCTConvert NSString:capturedEvent[@"user"][@"email"]] + username:[RCTConvert NSString:capturedEvent[@"user"][@"username"]] + extra:[RCTConvert NSDictionary:capturedEvent[@"user"][@"extra"]]]; + } + + NSString *message = nil; + SentryException *exception = nil; + SentryStacktrace *stacktrace = nil; + if (capturedEvent[@"message"]) { + message = capturedEvent[@"message"]; + SentryEvent *sentryEvent = [[SentryEvent alloc] init:message + timestamp:[NSDate date] + level:level + logger:capturedEvent[@"logger"] + culprit:nil + serverName:nil + release:nil + buildNumber:nil + tags:[self sanitizeDictionary:capturedEvent[@"tags"]] + modules:nil + extra:capturedEvent[@"extra"] + fingerprint:nil + user:user + exceptions:exception ? @[exception] : nil + stacktrace:stacktrace]; + + [[SentryClient shared] captureEvent:sentryEvent]; + } else if (capturedEvent[@"exception"]) { + message = [NSString stringWithFormat:@"Unhandled JS Exception: %@", capturedEvent[@"exception"][@"values"][0][@"value"]]; + //exception = [[SentryException alloc] initWithValue:message type:message mechanism:nil module:nil]; + //stacktrace = [[SentryStacktrace alloc] initWithFrames:SentryParseRavenFrames(capturedEvent[@"exception"][@"values"][0][@"stacktrace"][@"frames"])]; + [self handleSoftJSExceptionWithMessage:message stack:SentryParseRavenFrames(capturedEvent[@"exception"][@"values"][0][@"stacktrace"][@"frames"]) exceptionId:@1]; +// [[SentryClient shared] reportReactNativeCrashWithError:error stacktrace:stack terminateProgram:NO]; + } + +} + RCT_EXPORT_METHOD(crash) { [[SentryClient shared] crash]; diff --git a/lib/Sentry.js b/lib/Sentry.js index f5a1a92969..0dc79b26ea 100644 --- a/lib/Sentry.js +++ b/lib/Sentry.js @@ -78,47 +78,62 @@ export class Sentry { return Sentry; } - static isNativeClientAvailable = () => { + static isNativeClientAvailable() { return (Sentry._nativeClient); } - static crash = () => { - Sentry._ravenClient.crash(); + static crash() { + Sentry.log(SentryLog.Debug, 'Sentry: call crash'); + throw new Error('Sentry: TEST crash'); } - static nativeCrash = () => { - Sentry._ravenClient.nativeCrash(); + static nativeCrash() { + Sentry.log(SentryLog.Debug, 'Sentry: call nativeCrash'); + if (Sentry.isNativeClientAvailable()) { + Sentry._nativeClient.nativeCrash(); + } else { + Sentry.log(SentryLog.Debug, 'Sentry: call crash'); + } } - static setUserContext = (user) => { + static setUserContext(user) { Sentry._ravenClient.setUserContext(user); + if (Sentry.isNativeClientAvailable()) Sentry._nativeClient.setUserContext(user); } - static setTagsContext = (tags) => { + static setTagsContext(tags) { Sentry._ravenClient.setTagsContext(tags); + if (Sentry.isNativeClientAvailable()) Sentry._nativeClient.setTagsContext(tags); } - static setExtraContext = (extras) => { + static setExtraContext(extras) { Sentry._ravenClient.setExtraContext(extras); + if (Sentry.isNativeClientAvailable()) Sentry._nativeClient.setExtraContext(extras); } - static captureMessage = (message, options) => { + static captureMessage(message, options) { Sentry._ravenClient.captureMessage(message, options); } - static context = (options, func, args) => { + static context(options, func, args) { Sentry._ravenClient.context(options, func, args); } - static captureException = (ex, options) => { + static captureException(ex, options) { Sentry._ravenClient.captureException(ex, options); } - static captureBreadcrumb = (msg, options) => { + static captureBreadcrumb(msg, options) { Sentry._ravenClient.captureBreadcrumb(msg, options); } - static log = (level, message) => { + static captureEvent(event) { + if (Sentry.isNativeClientAvailable()) { + Sentry._nativeClient.captureEvent(event); + } + } + + static log(level, message) { if (Sentry.options && Sentry.options.logLevel) { if (Sentry.options.logLevel < level) { return; @@ -150,45 +165,21 @@ class NativeClient { if (this.options.deactivateStacktraceMerging === false) { this._activateStacktraceMerging(); } + RNSentry.setLogLevel(options.logLevel); } - crash = () => { - Sentry.log(SentryLog.Debug, 'Sentry: NativeClient: call crash'); - throw new Error('Sentry: NativeClient: TEST crash'); - } - - nativeCrash = () => { - Sentry.log(SentryLog.Debug, 'Sentry: NativeClient: call nativeCrash'); + nativeCrash() { + Sentry.log(SentryLog.Debug, 'Sentry: call nativeCrash'); RNSentry.crash(); } - setUserContext = (user) => { - Sentry.log(SentryLog.Debug, ['Sentry: NativeClient: call setUserContext', user]); - RNSentry.setUser(user); - } - - setTagsContext = (tags) => { - Sentry.log(SentryLog.Debug, ['Sentry: NativeClient: call setTagsContext', tags]); - RNSentry.setTags(tags); - } - - setExtraContext = (extras) => { - Sentry.log(SentryLog.Debug, ['Sentry: NativeClient: call setExtraContext', extras]); - RNSentry.setExtras(extras); - } - - captureMessage = (message, options) => { - Sentry.log(SentryLog.Debug, ['Sentry: NativeClient: call captureMessage', message, options]); - if (options === undefined) { - options = { - level: SentrySeverity.Error - }; - } - RNSentry.captureMessage(message, options.level); + captureEvent(event) { + Sentry.log(SentryLog.Debug, ['Sentry: call captureEvent', event]); + RNSentry.captureEvent(event); } _activateStacktraceMerging = async() => { - Sentry.log(SentryLog.Debug, 'Sentry: NativeClient: call _activateStacktraceMerging'); + Sentry.log(SentryLog.Debug, 'Sentry: call _activateStacktraceMerging'); return RNSentry.activateStacktraceMerging().then(activated => { if (this._activatedMerging) { return; @@ -207,7 +198,7 @@ class NativeClient { }); } - _overwriteEnqueueNativeCall = () => { + _overwriteEnqueueNativeCall() { const BatchedBridge = require('react-native/Libraries/BatchedBridge/BatchedBridge'); const original = BatchedBridge.enqueueNativeCall; const that = this; @@ -217,7 +208,7 @@ class NativeClient { } params.push({ '__sentry_stack': new Error().stack, - '__sentry_breadcrumbs': Raven._breadcrumbs // send breadcrumbs + '__sentry_breadcrumbs': [].slice.apply(Raven._breadcrumbs) // send breadcrumbs }); return original.apply(this, arguments); } @@ -242,65 +233,43 @@ class RavenClient { // We overwrite the default transport handler when the native // client is available, because we want to send the event with native Raven.setTransport((options) => { - console.log(options); + Sentry.captureEvent(options.data); }); } } - crash = () => { - Sentry.log(SentryLog.Debug, 'Sentry: call crash'); - throw new Error("Sentry: TEST crash"); - } - - nativeCrash = () => { - /*eslint no-console:0*/ - window.console && console.error && console.error("nativeCrash is not support with the RavenClient"); - } - - setUserContext = (user) => { + setUserContext(user) { Sentry.log(SentryLog.Debug, ['Sentry: call setUserContext', user]); Raven.setUserContext(user); } - setTagsContext = (tags) => { + setTagsContext(tags) { Sentry.log(SentryLog.Debug, ['Sentry: call setTagsContext', tags]); Raven.setTagsContext(tags); } - setExtraContext = (extra) => { + setExtraContext(extra) { Sentry.log(SentryLog.Debug, ['Sentry: call setExtraContext', extra]); Raven.setExtraContext(extra) } - context = (options, func, args) => { + context(options, func, args) { Sentry.log(SentryLog.Debug, ['Sentry: call context', options, func, args]); Raven.context(options, func, args); } - captureException = (ex, options) => { + captureException(ex, options) { Sentry.log(SentryLog.Debug, ['Sentry: call captureException', ex, options]); Raven.captureException(ex, options); } - captureBreadcrumb = (msg, options) => { + captureBreadcrumb(msg, options) { Sentry.log(SentryLog.Debug, ['Sentry: call captureBreadcrumb', msg, options]); Raven.captureBreadcrumb(msg, options); } captureMessage = async(message, options) => { Sentry.log(SentryLog.Debug, ['Sentry: call captureMessage', message, options]); - if (options && options.level) { - switch (options.level) { - case SentrySeverity.Warning: - options.level = 'warning'; - break; - case SentrySeverity.Info: - options.level = 'info'; - break; - default: - options.level = 'error'; - } - } Raven.captureMessage(message, options); } } From 8aff6cc4501032c4363c19ebd3f477808839bcf6 Mon Sep 17 00:00:00 2001 From: Daniel Griesser Date: Thu, 30 Mar 2017 16:44:46 +0200 Subject: [PATCH 03/10] Add breadcrumb capturing --- ios/RNSentry.m | 35 +++++++++++++++++++---------------- lib/Sentry.js | 39 ++++++++++++++++++++++++++++----------- 2 files changed, 47 insertions(+), 27 deletions(-) diff --git a/ios/RNSentry.m b/ios/RNSentry.m index 96a1c26ec0..9d15be8f97 100644 --- a/ios/RNSentry.m +++ b/ios/RNSentry.m @@ -50,7 +50,6 @@ + (NSRegularExpression *)frameRegex { NSRange searchedRange = NSMakeRange(0, [line length]); NSArray *matches = [[RNSentry frameRegex] matchesInString:line options:0 range:searchedRange]; for (NSTextCheckingResult *match in matches) { - NSString *matchText = [line substringWithRange:[match range]]; [frames addObject:@{ @"methodName": [line substringWithRange:[match rangeAtIndex:1]], @"column": [formatter numberFromString:[line substringWithRange:[match rangeAtIndex:4]]], @@ -92,7 +91,6 @@ + (NSRegularExpression *)frameRegex { return @{@"nativeClientAvailable": @YES}; } - RCT_EXPORT_METHOD(startWithDsnString:(NSString * _Nonnull)dsnString) { [SentryClient setShared:[[SentryClient alloc] initWithDsnString:[RCTConvert NSString:dsnString]]]; @@ -155,11 +153,22 @@ + (NSRegularExpression *)frameRegex { extra:[RCTConvert NSDictionary:user[@"extra"]]]; } +RCT_EXPORT_METHOD(captureBreadcrumb:(NSDictionary * _Nonnull)breadcrumb) +{ + NSDictionary *convertedBreadcrumb = [RCTConvert NSDictionary:breadcrumb]; + SentryBreadcrumb *crumb = [[SentryBreadcrumb alloc] initWithCategory:convertedBreadcrumb[@"category"] + timestamp:[NSDate dateWithTimeIntervalSince1970:[convertedBreadcrumb[@"timestamp"] integerValue]] + message:convertedBreadcrumb[@"message"] + type:nil + level:SentrySeverityInfo // TODO pass string instead of severity + data:nil]; + [[SentryClient shared].breadcrumbs add:crumb]; +} + RCT_EXPORT_METHOD(captureEvent:(NSDictionary * _Nonnull)event) { NSDictionary *capturedEvent = [RCTConvert NSDictionary:event]; - SentrySeverity level = SentrySeverityError; switch ([capturedEvent[@"level"] integerValue]) { case 0: @@ -186,12 +195,8 @@ + (NSRegularExpression *)frameRegex { extra:[RCTConvert NSDictionary:capturedEvent[@"user"][@"extra"]]]; } - NSString *message = nil; - SentryException *exception = nil; - SentryStacktrace *stacktrace = nil; if (capturedEvent[@"message"]) { - message = capturedEvent[@"message"]; - SentryEvent *sentryEvent = [[SentryEvent alloc] init:message + SentryEvent *sentryEvent = [[SentryEvent alloc] init:capturedEvent[@"message"] timestamp:[NSDate date] level:level logger:capturedEvent[@"logger"] @@ -204,16 +209,14 @@ + (NSRegularExpression *)frameRegex { extra:capturedEvent[@"extra"] fingerprint:nil user:user - exceptions:exception ? @[exception] : nil - stacktrace:stacktrace]; - + exceptions:nil + stacktrace:nil]; [[SentryClient shared] captureEvent:sentryEvent]; } else if (capturedEvent[@"exception"]) { - message = [NSString stringWithFormat:@"Unhandled JS Exception: %@", capturedEvent[@"exception"][@"values"][0][@"value"]]; - //exception = [[SentryException alloc] initWithValue:message type:message mechanism:nil module:nil]; - //stacktrace = [[SentryStacktrace alloc] initWithFrames:SentryParseRavenFrames(capturedEvent[@"exception"][@"values"][0][@"stacktrace"][@"frames"])]; - [self handleSoftJSExceptionWithMessage:message stack:SentryParseRavenFrames(capturedEvent[@"exception"][@"values"][0][@"stacktrace"][@"frames"]) exceptionId:@1]; -// [[SentryClient shared] reportReactNativeCrashWithError:error stacktrace:stack terminateProgram:NO]; + // TODO what do we do here with extra/tags/users that are not global? + [self handleSoftJSExceptionWithMessage:[NSString stringWithFormat:@"Unhandled JS Exception: %@", capturedEvent[@"exception"][@"values"][0][@"value"]] + stack:SentryParseRavenFrames(capturedEvent[@"exception"][@"values"][0][@"stacktrace"][@"frames"]) + exceptionId:@99]; } } diff --git a/lib/Sentry.js b/lib/Sentry.js index 0dc79b26ea..8b78a90d30 100644 --- a/lib/Sentry.js +++ b/lib/Sentry.js @@ -88,25 +88,26 @@ export class Sentry { } static nativeCrash() { - Sentry.log(SentryLog.Debug, 'Sentry: call nativeCrash'); if (Sentry.isNativeClientAvailable()) { + Sentry.log(SentryLog.Debug, 'Sentry: call nativeCrash'); Sentry._nativeClient.nativeCrash(); - } else { - Sentry.log(SentryLog.Debug, 'Sentry: call crash'); } } static setUserContext(user) { + Sentry.log(SentryLog.Debug, ['Sentry: call setUserContext', user]); Sentry._ravenClient.setUserContext(user); if (Sentry.isNativeClientAvailable()) Sentry._nativeClient.setUserContext(user); } static setTagsContext(tags) { + Sentry.log(SentryLog.Debug, ['Sentry: call setTagsContext', tags]); Sentry._ravenClient.setTagsContext(tags); if (Sentry.isNativeClientAvailable()) Sentry._nativeClient.setTagsContext(tags); } static setExtraContext(extras) { + Sentry.log(SentryLog.Debug, ['Sentry: call setExtraContext', extras]); Sentry._ravenClient.setExtraContext(extras); if (Sentry.isNativeClientAvailable()) Sentry._nativeClient.setExtraContext(extras); } @@ -128,9 +129,11 @@ export class Sentry { } static captureEvent(event) { - if (Sentry.isNativeClientAvailable()) { - Sentry._nativeClient.captureEvent(event); - } + if (Sentry.isNativeClientAvailable()) Sentry._nativeClient.captureEvent(event); + } + + static _breadcrumbCallback(crumb) { + if (Sentry.isNativeClientAvailable()) Sentry._nativeClient.captureBreadcrumb(crumb); } static log(level, message) { @@ -138,7 +141,7 @@ export class Sentry { if (Sentry.options.logLevel < level) { return; } - Raven._originalConsole.log(message); + Raven._logDebug('debug', message); } } } @@ -178,6 +181,22 @@ class NativeClient { RNSentry.captureEvent(event); } + setUserContext(user) { + RNSentry.setUser(user); + } + + setTagsContext(tags) { + RNSentry.setTags(tags); + } + + setExtraContext(extra) { + RNSentry.setExtras(extra); + } + + captureBreadcrumb(crumb) { + RNSentry.captureBreadcrumb(crumb); + } + _activateStacktraceMerging = async() => { Sentry.log(SentryLog.Debug, 'Sentry: call _activateStacktraceMerging'); return RNSentry.activateStacktraceMerging().then(activated => { @@ -235,21 +254,19 @@ class RavenClient { Raven.setTransport((options) => { Sentry.captureEvent(options.data); }); + Raven.setBreadcrumbCallback(Sentry._breadcrumbCallback); } } setUserContext(user) { - Sentry.log(SentryLog.Debug, ['Sentry: call setUserContext', user]); Raven.setUserContext(user); } setTagsContext(tags) { - Sentry.log(SentryLog.Debug, ['Sentry: call setTagsContext', tags]); Raven.setTagsContext(tags); } setExtraContext(extra) { - Sentry.log(SentryLog.Debug, ['Sentry: call setExtraContext', extra]); Raven.setExtraContext(extra) } @@ -268,7 +285,7 @@ class RavenClient { Raven.captureBreadcrumb(msg, options); } - captureMessage = async(message, options) => { + captureMessage(message, options) { Sentry.log(SentryLog.Debug, ['Sentry: call captureMessage', message, options]); Raven.captureMessage(message, options); } From 1f02afac7d86e23f4b43eddbb6d6d2f732aa874d Mon Sep 17 00:00:00 2001 From: Daniel Griesser Date: Thu, 30 Mar 2017 17:08:28 +0200 Subject: [PATCH 04/10] Remove Sentry.log, Fix breadcrumbs and tracking on uncaught exception --- lib/Sentry.js | 28 +++++++--------------------- lib/raven-plugin.js | 7 ------- 2 files changed, 7 insertions(+), 28 deletions(-) diff --git a/lib/Sentry.js b/lib/Sentry.js index 8b78a90d30..5494afc92c 100644 --- a/lib/Sentry.js +++ b/lib/Sentry.js @@ -83,31 +83,26 @@ export class Sentry { } static crash() { - Sentry.log(SentryLog.Debug, 'Sentry: call crash'); throw new Error('Sentry: TEST crash'); } static nativeCrash() { if (Sentry.isNativeClientAvailable()) { - Sentry.log(SentryLog.Debug, 'Sentry: call nativeCrash'); Sentry._nativeClient.nativeCrash(); } } static setUserContext(user) { - Sentry.log(SentryLog.Debug, ['Sentry: call setUserContext', user]); Sentry._ravenClient.setUserContext(user); if (Sentry.isNativeClientAvailable()) Sentry._nativeClient.setUserContext(user); } static setTagsContext(tags) { - Sentry.log(SentryLog.Debug, ['Sentry: call setTagsContext', tags]); Sentry._ravenClient.setTagsContext(tags); if (Sentry.isNativeClientAvailable()) Sentry._nativeClient.setTagsContext(tags); } static setExtraContext(extras) { - Sentry.log(SentryLog.Debug, ['Sentry: call setExtraContext', extras]); Sentry._ravenClient.setExtraContext(extras); if (Sentry.isNativeClientAvailable()) Sentry._nativeClient.setExtraContext(extras); } @@ -135,15 +130,6 @@ export class Sentry { static _breadcrumbCallback(crumb) { if (Sentry.isNativeClientAvailable()) Sentry._nativeClient.captureBreadcrumb(crumb); } - - static log(level, message) { - if (Sentry.options && Sentry.options.logLevel) { - if (Sentry.options.logLevel < level) { - return; - } - Raven._logDebug('debug', message); - } - } } class NativeClient { @@ -172,12 +158,10 @@ class NativeClient { } nativeCrash() { - Sentry.log(SentryLog.Debug, 'Sentry: call nativeCrash'); RNSentry.crash(); } captureEvent(event) { - Sentry.log(SentryLog.Debug, ['Sentry: call captureEvent', event]); RNSentry.captureEvent(event); } @@ -198,7 +182,6 @@ class NativeClient { } _activateStacktraceMerging = async() => { - Sentry.log(SentryLog.Debug, 'Sentry: call _activateStacktraceMerging'); return RNSentry.activateStacktraceMerging().then(activated => { if (this._activatedMerging) { return; @@ -255,6 +238,13 @@ class RavenClient { 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); + } } } @@ -271,22 +261,18 @@ class RavenClient { } context(options, func, args) { - Sentry.log(SentryLog.Debug, ['Sentry: call context', options, func, args]); Raven.context(options, func, args); } captureException(ex, options) { - Sentry.log(SentryLog.Debug, ['Sentry: call captureException', ex, options]); Raven.captureException(ex, options); } captureBreadcrumb(msg, options) { - Sentry.log(SentryLog.Debug, ['Sentry: call captureBreadcrumb', msg, options]); Raven.captureBreadcrumb(msg, options); } captureMessage(message, options) { - Sentry.log(SentryLog.Debug, ['Sentry: call captureMessage', message, options]); Raven.captureMessage(message, options); } } diff --git a/lib/raven-plugin.js b/lib/raven-plugin.js index ba7b243969..1a731a06ae 100644 --- a/lib/raven-plugin.js +++ b/lib/raven-plugin.js @@ -80,13 +80,6 @@ function reactNativePlugin(Raven, options) { }) ['catch'](function() {}); - - if (options.nativeClientAvailable) { - return; - // if native client is available we don't want to overwrite the ErrorUtils - // error handler - } - // Make sure that if multiple fatals occur, we only persist the first one. // // The first error is probably the most important/interesting error, and we From 525259edb55433372153f8c13cf1b7a7886263ba Mon Sep 17 00:00:00 2001 From: Daniel Griesser Date: Fri, 31 Mar 2017 10:46:33 +0200 Subject: [PATCH 05/10] Fix naming for setExtra --- ios/RNSentry.m | 4 ++-- lib/Sentry.js | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ios/RNSentry.m b/ios/RNSentry.m index 9d15be8f97..0dfad25b26 100644 --- a/ios/RNSentry.m +++ b/ios/RNSentry.m @@ -140,9 +140,9 @@ + (NSRegularExpression *)frameRegex { [SentryClient shared].tags = [self sanitizeDictionary:[RCTConvert NSDictionary:tags]]; } -RCT_EXPORT_METHOD(setExtras:(NSDictionary * _Nonnull)extras) +RCT_EXPORT_METHOD(setExtra:(NSDictionary * _Nonnull)extra) { - [SentryClient shared].extra = [RCTConvert NSDictionary:extras]; + [SentryClient shared].extra = [RCTConvert NSDictionary:extra]; } RCT_EXPORT_METHOD(setUser:(NSDictionary * _Nonnull)user) diff --git a/lib/Sentry.js b/lib/Sentry.js index 5494afc92c..0a64ddd194 100644 --- a/lib/Sentry.js +++ b/lib/Sentry.js @@ -102,9 +102,9 @@ export class Sentry { if (Sentry.isNativeClientAvailable()) Sentry._nativeClient.setTagsContext(tags); } - static setExtraContext(extras) { - Sentry._ravenClient.setExtraContext(extras); - if (Sentry.isNativeClientAvailable()) Sentry._nativeClient.setExtraContext(extras); + static setExtraContext(extra) { + Sentry._ravenClient.setExtraContext(extra); + if (Sentry.isNativeClientAvailable()) Sentry._nativeClient.setExtraContext(extra); } static captureMessage(message, options) { @@ -174,7 +174,7 @@ class NativeClient { } setExtraContext(extra) { - RNSentry.setExtras(extra); + RNSentry.setExtra(extra); } captureBreadcrumb(crumb) { From aa58c7fc14d26d6aa32cfd418b0928d40d415606 Mon Sep 17 00:00:00 2001 From: Daniel Griesser Date: Fri, 31 Mar 2017 11:18:56 +0200 Subject: [PATCH 06/10] Add context and wrap function --- ios/RNSentry.m | 7 +++++++ lib/Sentry.js | 44 +++++++++++++++++++++++++++++++++----------- 2 files changed, 40 insertions(+), 11 deletions(-) diff --git a/ios/RNSentry.m b/ios/RNSentry.m index 63bd3b0a39..c581d57993 100644 --- a/ios/RNSentry.m +++ b/ios/RNSentry.m @@ -130,6 +130,13 @@ + (NSRegularExpression *)frameRegex { resolve(@YES); } +RCT_EXPORT_METHOD(clearContext) +{ + [SentryClient shared].tags = @{}; + [SentryClient shared].extra = @{}; + [SentryClient shared].user = nil; +} + RCT_EXPORT_METHOD(setLogLevel:(int)level) { [SentryClient setLogLevel:level]; diff --git a/lib/Sentry.js b/lib/Sentry.js index 0a64ddd194..516b525bbf 100644 --- a/lib/Sentry.js +++ b/lib/Sentry.js @@ -111,10 +111,6 @@ export class Sentry { Sentry._ravenClient.captureMessage(message, options); } - static context(options, func, args) { - Sentry._ravenClient.context(options, func, args); - } - static captureException(ex, options) { Sentry._ravenClient.captureException(ex, options); } @@ -123,13 +119,28 @@ export class Sentry { Sentry._ravenClient.captureBreadcrumb(msg, options); } - static captureEvent(event) { - if (Sentry.isNativeClientAvailable()) Sentry._nativeClient.captureEvent(event); + 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); } + // Private helpers + static _breadcrumbCallback(crumb) { if (Sentry.isNativeClientAvailable()) Sentry._nativeClient.captureBreadcrumb(crumb); } + + static _captureEvent(event) { + if (Sentry.isNativeClientAvailable()) Sentry._nativeClient.captureEvent(event); + } } class NativeClient { @@ -181,6 +192,10 @@ class NativeClient { RNSentry.captureBreadcrumb(crumb); } + clearContext() { + RNSentry.clearContext(); + } + _activateStacktraceMerging = async() => { return RNSentry.activateStacktraceMerging().then(activated => { if (this._activatedMerging) { @@ -231,11 +246,14 @@ class RavenClient { '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); + Sentry._captureEvent(options.data); }); Raven.setBreadcrumbCallback(Sentry._breadcrumbCallback); const oldCaptureBreadcrumb = Raven.captureBreadcrumb; @@ -260,10 +278,6 @@ class RavenClient { Raven.setExtraContext(extra) } - context(options, func, args) { - Raven.context(options, func, args); - } - captureException(ex, options) { Raven.captureException(ex, options); } @@ -275,4 +289,12 @@ class RavenClient { captureMessage(message, options) { Raven.captureMessage(message, options); } + + context(options, func, args) { + return Raven.context(options, func, args); + } + + wrap(options, func, _before) { + return Raven.wrap(options, func, _before); + } } From d2d3de108e31db52d4e9f5b2588ff42687531e8a Mon Sep 17 00:00:00 2001 From: Daniel Griesser Date: Fri, 31 Mar 2017 11:22:07 +0200 Subject: [PATCH 07/10] Fix RCTConvert --- ios/RNSentry.m | 37 +++++++++++++++++-------------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/ios/RNSentry.m b/ios/RNSentry.m index c581d57993..f5920e1eaa 100644 --- a/ios/RNSentry.m +++ b/ios/RNSentry.m @@ -162,10 +162,9 @@ + (NSRegularExpression *)frameRegex { RCT_EXPORT_METHOD(captureBreadcrumb:(NSDictionary * _Nonnull)breadcrumb) { - NSDictionary *convertedBreadcrumb = [RCTConvert NSDictionary:breadcrumb]; - SentryBreadcrumb *crumb = [[SentryBreadcrumb alloc] initWithCategory:convertedBreadcrumb[@"category"] - timestamp:[NSDate dateWithTimeIntervalSince1970:[convertedBreadcrumb[@"timestamp"] integerValue]] - message:convertedBreadcrumb[@"message"] + SentryBreadcrumb *crumb = [[SentryBreadcrumb alloc] initWithCategory:breadcrumb[@"category"] + timestamp:[NSDate dateWithTimeIntervalSince1970:[breadcrumb[@"timestamp"] integerValue]] + message:breadcrumb[@"message"] type:nil level:SentrySeverityInfo // TODO pass string instead of severity data:nil]; @@ -174,10 +173,8 @@ + (NSRegularExpression *)frameRegex { RCT_EXPORT_METHOD(captureEvent:(NSDictionary * _Nonnull)event) { - NSDictionary *capturedEvent = [RCTConvert NSDictionary:event]; - SentrySeverity level = SentrySeverityError; - switch ([capturedEvent[@"level"] integerValue]) { + switch ([event[@"level"] integerValue]) { case 0: level = SentrySeverityFatal; break; @@ -195,34 +192,34 @@ + (NSRegularExpression *)frameRegex { } SentryUser *user = nil; - if (capturedEvent[@"user"] != nil) { - user = [[SentryUser alloc] initWithId:[RCTConvert NSString:capturedEvent[@"user"][@"userID"]] - email:[RCTConvert NSString:capturedEvent[@"user"][@"email"]] - username:[RCTConvert NSString:capturedEvent[@"user"][@"username"]] - extra:[RCTConvert NSDictionary:capturedEvent[@"user"][@"extra"]]]; + if (event[@"user"] != nil) { + user = [[SentryUser alloc] initWithId:[RCTConvert NSString:event[@"user"][@"userID"]] + email:[RCTConvert NSString:event[@"user"][@"email"]] + username:[RCTConvert NSString:event[@"user"][@"username"]] + extra:[RCTConvert NSDictionary:event[@"user"][@"extra"]]]; } - if (capturedEvent[@"message"]) { - SentryEvent *sentryEvent = [[SentryEvent alloc] init:capturedEvent[@"message"] + if (event[@"message"]) { + SentryEvent *sentryEvent = [[SentryEvent alloc] init:event[@"message"] timestamp:[NSDate date] level:level - logger:capturedEvent[@"logger"] + logger:event[@"logger"] culprit:nil serverName:nil release:nil buildNumber:nil - tags:[self sanitizeDictionary:capturedEvent[@"tags"]] + tags:[self sanitizeDictionary:event[@"tags"]] modules:nil - extra:capturedEvent[@"extra"] + extra:event[@"extra"] fingerprint:nil user:user exceptions:nil stacktrace:nil]; [[SentryClient shared] captureEvent:sentryEvent]; - } else if (capturedEvent[@"exception"]) { + } else if (event[@"exception"]) { // TODO what do we do here with extra/tags/users that are not global? - [self handleSoftJSExceptionWithMessage:[NSString stringWithFormat:@"Unhandled JS Exception: %@", capturedEvent[@"exception"][@"values"][0][@"value"]] - stack:SentryParseRavenFrames(capturedEvent[@"exception"][@"values"][0][@"stacktrace"][@"frames"]) + [self handleSoftJSExceptionWithMessage:[NSString stringWithFormat:@"Unhandled JS Exception: %@", event[@"exception"][@"values"][0][@"value"]] + stack:SentryParseRavenFrames(event[@"exception"][@"values"][0][@"stacktrace"][@"frames"]) exceptionId:@99]; } From 8ff46fcdf81dafe05328fef3e89c03765593ab60 Mon Sep 17 00:00:00 2001 From: Daniel Griesser Date: Fri, 31 Mar 2017 11:36:35 +0200 Subject: [PATCH 08/10] Fix SentrySeverity --- ios/RNSentry.m | 36 ++++++++++++++++++------------------ lib/Sentry.js | 4 +--- 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/ios/RNSentry.m b/ios/RNSentry.m index f5920e1eaa..fe503f171c 100644 --- a/ios/RNSentry.m +++ b/ios/RNSentry.m @@ -166,30 +166,14 @@ + (NSRegularExpression *)frameRegex { timestamp:[NSDate dateWithTimeIntervalSince1970:[breadcrumb[@"timestamp"] integerValue]] message:breadcrumb[@"message"] type:nil - level:SentrySeverityInfo // TODO pass string instead of severity + level:[self sentrySeverityFromLevel:[breadcrumb[@"level"] integerValue]] data:nil]; [[SentryClient shared].breadcrumbs add:crumb]; } RCT_EXPORT_METHOD(captureEvent:(NSDictionary * _Nonnull)event) { - SentrySeverity level = SentrySeverityError; - switch ([event[@"level"] integerValue]) { - case 0: - level = SentrySeverityFatal; - break; - case 2: - level = SentrySeverityWarning; - break; - case 3: - level = SentrySeverityInfo; - break; - case 4: - level = SentrySeverityDebug; - break; - default: - break; - } + SentrySeverity level = [self sentrySeverityFromLevel:[event[@"level"] integerValue]]; SentryUser *user = nil; if (event[@"user"] != nil) { @@ -230,6 +214,22 @@ + (NSRegularExpression *)frameRegex { [[SentryClient shared] crash]; } +- (SentrySeverity)sentrySeverityFromLevel:(NSInteger)level { + switch (level) { + case 0: + return SentrySeverityFatal; + case 2: + return SentrySeverityWarning; + case 3: + return SentrySeverityInfo; + case 4: + return SentrySeverityDebug; + default: + return SentrySeverityError; + } + return level; +} + - (NSDictionary *)sanitizeDictionary:(NSDictionary *)dictionary { NSMutableDictionary *dict = [NSMutableDictionary dictionary]; for (NSString *key in dictionary.allKeys) { diff --git a/lib/Sentry.js b/lib/Sentry.js index 516b525bbf..e02a83b07e 100644 --- a/lib/Sentry.js +++ b/lib/Sentry.js @@ -87,9 +87,7 @@ export class Sentry { } static nativeCrash() { - if (Sentry.isNativeClientAvailable()) { - Sentry._nativeClient.nativeCrash(); - } + if (Sentry.isNativeClientAvailable()) Sentry._nativeClient.nativeCrash(); } static setUserContext(user) { From 5aa323e98fcffbfe88cf2b30d5b612dd7fea3619 Mon Sep 17 00:00:00 2001 From: Daniel Griesser Date: Fri, 31 Mar 2017 14:11:05 +0200 Subject: [PATCH 09/10] Remove comment --- ios/RNSentry.m | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/ios/RNSentry.m b/ios/RNSentry.m index fe503f171c..901317a077 100644 --- a/ios/RNSentry.m +++ b/ios/RNSentry.m @@ -66,13 +66,6 @@ + (NSRegularExpression *)frameRegex { NSMutableArray *frames = [NSMutableArray array]; for (NSDictionary *ravenFrame in ravenFrames) { if (ravenFrame[@"lineno"] != NSNull.null) { -// SentryFrame *frame = [[SentryFrame alloc] initWithFileName:ravenFrame[@"filename"] -// function:ravenFrame[@"function"] -// module:nil -// line:[[formatter numberFromString:[NSString stringWithFormat:@"%@", ravenFrame[@"lineno"]]] integerValue] -// column: [[formatter numberFromString:[NSString stringWithFormat:@"%@", ravenFrame[@"colno"]]] integerValue]]; -// [frame setPlatform:@"javascript"]; -// [frames addObject:frame]; [frames addObject:@{ @"methodName": ravenFrame[@"function"], @"column": [formatter numberFromString:[NSString stringWithFormat:@"%@", ravenFrame[@"colno"]]], @@ -116,6 +109,7 @@ + (NSRegularExpression *)frameRegex { @synchronized ([SentryClient shared]) { [[SentryClient shared] addExtra:@"__sentry_address" value:[NSNumber numberWithUnsignedInteger:callNativeModuleAddress]]; [[SentryClient shared] addExtra:@"__sentry_stack" value:SentryParseJavaScriptStacktrace([RCTConvert NSString:param[@"__sentry_stack"]])]; + // [RCTConvert NSArray:param[@"__sentry_breadcrumbs"]] // we will add this in the objc client } } else { if (param != nil) { From b2a0ec7004ae1ebc8c43ba965740713fd20e4770 Mon Sep 17 00:00:00 2001 From: Daniel Griesser Date: Fri, 31 Mar 2017 14:34:26 +0200 Subject: [PATCH 10/10] Remove sending breadcrumbs in enqueueNativeCall --- ios/RNSentry.m | 1 - lib/Sentry.js | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/ios/RNSentry.m b/ios/RNSentry.m index 901317a077..ee6c5b4422 100644 --- a/ios/RNSentry.m +++ b/ios/RNSentry.m @@ -109,7 +109,6 @@ + (NSRegularExpression *)frameRegex { @synchronized ([SentryClient shared]) { [[SentryClient shared] addExtra:@"__sentry_address" value:[NSNumber numberWithUnsignedInteger:callNativeModuleAddress]]; [[SentryClient shared] addExtra:@"__sentry_stack" value:SentryParseJavaScriptStacktrace([RCTConvert NSString:param[@"__sentry_stack"]])]; - // [RCTConvert NSArray:param[@"__sentry_breadcrumbs"]] // we will add this in the objc client } } else { if (param != nil) { diff --git a/lib/Sentry.js b/lib/Sentry.js index e02a83b07e..863ea49682 100644 --- a/lib/Sentry.js +++ b/lib/Sentry.js @@ -222,8 +222,7 @@ class NativeClient { return original.apply(this, arguments); } params.push({ - '__sentry_stack': new Error().stack, - '__sentry_breadcrumbs': [].slice.apply(Raven._breadcrumbs) // send breadcrumbs + '__sentry_stack': new Error().stack }); return original.apply(this, arguments); }