Skip to content

Commit 64f94c9

Browse files
authored
Merge pull request #214 from getsentry/bugfix/stacktrace-merging-performance
Improve performance on stacktrace merging
2 parents 74ec796 + 661f99e commit 64f94c9

File tree

4 files changed

+54
-24
lines changed

4 files changed

+54
-24
lines changed

ios/RNSentry.m

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
@interface RNSentry()
1616

17-
@property (nonatomic, strong) NSDictionary *lastReceivedException;
17+
@property (nonatomic, strong) NSMutableDictionary *moduleMapping;
1818

1919
@end
2020

@@ -201,6 +201,7 @@ - (void)setReleaseVersionDist:(SentryEvent *)event {
201201
static dispatch_once_t onceStartToken;
202202
dispatch_once(&onceStartToken, ^{
203203
NSError *error = nil;
204+
self.moduleMapping = [[NSMutableDictionary alloc] init];
204205
SentryClient *client = [[SentryClient alloc] initWithDsn:dsnString didFailWithError:&error];
205206
client.beforeSerializeEvent = ^(SentryEvent * _Nonnull event) {
206207
[self injectReactNativeFrames:event];
@@ -240,7 +241,7 @@ - (void)swizzleInvokeWithBridge:(Class)class {
240241
static const void *key = &key;
241242
SEL selector = @selector(invokeWithBridge:module:arguments:);
242243
uintptr_t callNativeModuleAddress = [class instanceMethodForSelector:selector];
243-
244+
__block RNSentry *_self = self;
244245
SentrySwizzleInstanceMethod(class,
245246
selector,
246247
SentrySWReturnType(id),
@@ -251,6 +252,8 @@ - (void)swizzleInvokeWithBridge:(Class)class {
251252
if (arguments != nil && arguments.count > 0) {
252253
for (id param in arguments) {
253254
if ([param isKindOfClass:NSDictionary.class] && param[@"__sentry_stack"]) {
255+
[_self.moduleMapping setValue:[NSString stringWithFormat:@"%@", [module class]] forKey:[NSString stringWithFormat:@"%@", param[@"__sentry_moduleID"]]];
256+
[RNSentryEventEmitter emitModuleTableUpdate:_self.moduleMapping];
254257
[[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithUnsignedInteger:callNativeModuleAddress] forKey:@"RNSentry.__sentry_address"];
255258
[[NSUserDefaults standardUserDefaults] setObject:[RCTConvert NSString:param[@"__sentry_stack"]] forKey:@"RNSentry.__sentry_stack"];
256259
[[NSUserDefaults standardUserDefaults] synchronize];

ios/RNSentryEventEmitter.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,6 @@
1212
@interface RNSentryEventEmitter : RCTEventEmitter <RCTBridgeModule>
1313

1414
+ (void)emitStoredEvent;
15+
+ (void)emitModuleTableUpdate:(NSDictionary *)moduleTable;
1516

1617
@end

ios/RNSentryEventEmitter.m

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
NSString *const kEventSentSuccessfully = @"Sentry/eventSentSuccessfully";
1212
NSString *const kEventStored = @"Sentry/eventStored";
13+
NSString *const kModuleTable = @"Sentry/moduleTable";
1314

1415
@implementation RNSentryEventEmitter
1516

@@ -18,12 +19,13 @@ @implementation RNSentryEventEmitter
1819
- (NSDictionary<NSString *, NSString *> *)constantsToExport {
1920
return @{
2021
@"EVENT_SENT_SUCCESSFULLY": kEventSentSuccessfully,
21-
@"EVENT_STORED": kEventStored
22+
@"EVENT_STORED": kEventStored,
23+
@"MODULE_TABLE": kModuleTable
2224
};
2325
}
2426

2527
- (NSArray<NSString *> *)supportedEvents {
26-
return @[kEventSentSuccessfully, kEventStored];
28+
return @[kEventSentSuccessfully, kEventStored, kModuleTable];
2729
}
2830

2931

@@ -44,6 +46,13 @@ + (void)emitStoredEvent {
4446
[self postNotificationName:kEventStored withPayload:@""];
4547
}
4648

49+
+ (void)emitModuleTableUpdate:(NSDictionary *)moduleTable {
50+
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:moduleTable
51+
options:0
52+
error:nil];
53+
[self postNotificationName:kModuleTable withPayload:[[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]];
54+
}
55+
4756
+ (void)postNotificationName:(NSString *)name withPayload:(NSObject *)object {
4857
NSDictionary<NSString *, id> *payload = @{@"payload": object};
4958

lib/NativeClient.js

Lines changed: 37 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import {NativeModules} from 'react-native';
2-
const {RNSentry} = NativeModules;
1+
import {NativeModules, NativeEventEmitter} from 'react-native';
2+
const {RNSentry, RNSentryEventEmitter} = NativeModules;
33

44
const DEFAULT_MODULE_IGNORES = [
55
'AccessibilityManager',
@@ -58,6 +58,10 @@ export class NativeClient {
5858
RNSentry.startWithDsnString(this._dsn);
5959
if (this.options.deactivateStacktraceMerging === false) {
6060
this._activateStacktraceMerging();
61+
const eventEmitter = new NativeEventEmitter(RNSentryEventEmitter);
62+
eventEmitter.addListener(RNSentryEventEmitter.MODULE_TABLE, moduleTable => {
63+
this._updateIgnoredModules(JSON.parse(moduleTable.payload));
64+
});
6165
}
6266
RNSentry.setLogLevel(options.logLevel);
6367
}
@@ -94,6 +98,29 @@ export class NativeClient {
9498
RNSentry.clearContext();
9599
}
96100

101+
_updateIgnoredModules(modules) {
102+
const values = Object.values(modules);
103+
const keys = Object.keys(modules);
104+
for (let i = 0; i < values.length; i++) {
105+
const moduleName = values[i].replace(/RCT/, '');
106+
const moduleID = keys[i];
107+
if (this._ignoredModules[moduleID]) {
108+
continue;
109+
}
110+
this._addIgnoredModule(moduleID, moduleName);
111+
}
112+
}
113+
114+
_addIgnoredModule(moduleID, moduleName) {
115+
if (
116+
this.options.ignoreModulesExclude.indexOf(moduleName) === -1 &&
117+
(DEFAULT_MODULE_IGNORES.indexOf(moduleName) >= 0 ||
118+
this.options.ignoreModulesInclude.indexOf(moduleName) >= 0)
119+
) {
120+
this._ignoredModules[moduleID] = true;
121+
}
122+
}
123+
97124
_activateStacktraceMerging = async () => {
98125
return RNSentry.activateStacktraceMerging()
99126
.then(activated => {
@@ -105,26 +132,15 @@ export class NativeClient {
105132
if (typeof __fbBatchedBridgeConfig !== 'undefined') {
106133
/* global __fbBatchedBridgeConfig */
107134
__fbBatchedBridgeConfig.remoteModuleConfig.forEach((module, moduleID) => {
108-
if (
109-
module !== null &&
110-
this.options.ignoreModulesExclude.indexOf(module[0]) === -1 &&
111-
(DEFAULT_MODULE_IGNORES.indexOf(module[0]) >= 0 ||
112-
this.options.ignoreModulesInclude.indexOf(module[0]) >= 0)
113-
) {
114-
this._ignoredModules[moduleID] = true;
135+
if (module !== null) {
136+
this._addIgnoredModule(moduleID, module[0]);
115137
}
116138
});
117139
} else if (BatchedBridge._remoteModuleTable) {
118-
for (let module in BatchedBridge._remoteModuleTable) {
119-
if (BatchedBridge._remoteModuleTable.hasOwnProperty(module)) {
120-
let moduleName = BatchedBridge._remoteModuleTable[module];
121-
if (
122-
this.options.ignoreModulesExclude.indexOf(moduleName) === -1 &&
123-
(DEFAULT_MODULE_IGNORES.indexOf(moduleName) >= 0 ||
124-
this.options.ignoreModulesInclude.indexOf(moduleName) >= 0)
125-
) {
126-
this._ignoredModules[module] = true;
127-
}
140+
for (let moduleID in BatchedBridge._remoteModuleTable) {
141+
if (BatchedBridge._remoteModuleTable.hasOwnProperty(moduleID)) {
142+
let moduleName = BatchedBridge._remoteModuleTable[moduleID];
143+
this._addIgnoredModule(moduleID, moduleName);
128144
}
129145
}
130146
}
@@ -152,7 +168,8 @@ export class NativeClient {
152168
return original.apply(this, arguments);
153169
}
154170
params.push({
155-
__sentry_stack: new Error().stack
171+
__sentry_stack: new Error().stack,
172+
__sentry_moduleID: moduleID
156173
});
157174
return original.apply(this, arguments);
158175
};

0 commit comments

Comments
 (0)