@@ -306,6 +306,7 @@ @interface BugsnagClient ()
306306@property (nonatomic , strong ) NSString *lastOrientation;
307307#endif
308308@property NSMutableDictionary *extraRuntimeInfo;
309+ @property (nonatomic ) BugsnagUser *user;
309310@end
310311
311312@interface BugsnagConfiguration ()
@@ -351,6 +352,8 @@ @interface BugsnagSessionTracker ()
351352
352353@interface BugsnagUser ()
353354- (instancetype )initWithDictionary : (NSDictionary *)dict ;
355+ - (instancetype )initWithUserId : (NSString *)userId name : (NSString *)name emailAddress : (NSString *)emailAddress ;
356+ - (NSDictionary *)toJson ;
354357@end
355358
356359@interface BugsnagBreadcrumbs ()
@@ -410,7 +413,7 @@ - (id)initWithConfiguration:(BugsnagConfiguration *)initConfiguration {
410413 }];
411414
412415 self.breadcrumbs = [[BugsnagBreadcrumbs alloc ] initWithConfiguration: self .configuration];
413-
416+
414417 // Start with a copy of the configuration metadata
415418 self.metadata = [[configuration metadata ] deepCopy ];
416419 // sync initial state
@@ -431,15 +434,16 @@ - (id)initWithConfiguration:(BugsnagConfiguration *)initConfiguration {
431434 [self .configuration.config addObserverWithBlock: observer];
432435 [self .state addObserverWithBlock: observer];
433436
434- self.pluginClient = [[BugsnagPluginClient alloc ] initWithPlugins: self .configuration.plugins];
437+ self.pluginClient = [[BugsnagPluginClient alloc ] initWithPlugins: self .configuration.plugins
438+ client: self ];
435439
436440#if BSG_PLATFORM_IOS
437441 _lastOrientation = BSGOrientationNameFromEnum ([UIDevice currentDevice ].orientation );
438442#endif
439- BugsnagUser *user = self.configuration .user ;
443+ _user = self.configuration .user ;
440444
441- if (user .id == nil ) { // populate with an autogenerated ID if no value set
442- [self setUser: [BSG_KSSystemInfo deviceAndAppHash ] withEmail: user .email andName: user .name];
445+ if (_user .id == nil ) { // populate with an autogenerated ID if no value set
446+ [self setUser: [BSG_KSSystemInfo deviceAndAppHash ] withEmail: _user .email andName: _user .name];
443447 }
444448 }
445449 return self;
@@ -450,6 +454,15 @@ - (void)addObserverWithBlock:(BugsnagObserverBlock _Nonnull)observer {
450454
451455 // additionally listen for metadata updates
452456 [self .metadata addObserverWithBlock: observer];
457+
458+ // sync the new observer with changes to metadata so far
459+ BugsnagStateEvent *event = [[BugsnagStateEvent alloc ] initWithName: kStateEventMetadata data: self .metadata];
460+ observer (event);
461+
462+ NSDictionary *userJson = [self .user toJson ];
463+ observer ([[BugsnagStateEvent alloc ] initWithName: kStateEventUser data: userJson]);
464+
465+ observer ([[BugsnagStateEvent alloc ] initWithName: kStateEventContext data: self .context]);
453466}
454467
455468- (void )removeObserverWithBlock : (BugsnagObserverBlock _Nonnull)observer {
@@ -563,7 +576,7 @@ - (void)start {
563576 selector: @selector (orientationChanged: )
564577 name: UIDeviceOrientationDidChangeNotification
565578 object: nil ];
566-
579+
567580 [center addObserver: self
568581 selector: @selector (lowMemoryWarning: )
569582 name: UIApplicationDidReceiveMemoryWarningNotification
@@ -592,7 +605,7 @@ - (void)start {
592605 _started = YES ;
593606 // autoDetectErrors disables all unhandled event reporting
594607 BOOL configuredToReportOOMs = self.configuration .autoDetectErrors && self.configuration .enabledErrorTypes .ooms ;
595-
608+
596609 // Disable if a debugger is enabled, since the development cycle of starting
597610 // and restarting an app is also an uncatchable kill
598611 BOOL noDebuggerEnabled = !bsg_ksmachisBeingTraced ();
@@ -646,15 +659,15 @@ - (void)computeDidCrashLastLaunch {
646659 }
647660 }
648661 self.appDidCrashLastLaunch = handledCrashLastLaunch || [self .oomWatchdog didOOMLastLaunch ];
649-
662+
650663 // Ignore potential false positive OOM if previous session crashed and was
651664 // reported. There are two checks in place:
652665 //
653666 // 1. crashState->crashedLastLaunch: Accurate unless the crash callback crashes
654667 //
655668 // 2. crash sentinel file exists: This file is written in the event of a crash
656669 // and insures against the crash callback crashing
657-
670+
658671 if (!handledCrashLastLaunch && [self .oomWatchdog didOOMLastLaunch ]) {
659672 [self notifyOutOfMemoryEvent ];
660673 }
@@ -665,6 +678,7 @@ - (void)computeDidCrashLastLaunch {
665678
666679- (void )setCodeBundleId : (NSString *)codeBundleId {
667680 _codeBundleId = codeBundleId;
681+ [self .state addMetadata: codeBundleId withKey: BSGKeyCodeBundleId toSection: BSGKeyApp];
668682 self.oomWatchdog .codeBundleId = codeBundleId;
669683 self.sessionTracker .codeBundleId = codeBundleId;
670684}
@@ -748,7 +762,7 @@ - (void)setupConnectivityListener {
748762 if (connected) {
749763 [strongSelf flushPendingReports ];
750764 }
751-
765+
752766 [self addAutoBreadcrumbOfType: BSGBreadcrumbTypeState
753767 withMessage: @" Connectivity changed"
754768 andMetadata: @{
@@ -787,22 +801,21 @@ - (void)leaveBreadcrumbWithMessage:(NSString *_Nonnull)message
787801
788802- (BugsnagUser *_Nonnull)user
789803{
790- NSDictionary *userInfo = [self .metadata getMetadataFromSection: BSGKeyUser];
791- return [[BugsnagUser alloc ] initWithDictionary: userInfo ?: @{}];
804+ return self.configuration .user ;
792805}
793806
794807- (void )setUser : (NSString *_Nullable)userId
795808 withEmail : (NSString *_Nullable)email
796809 andName : (NSString *_Nullable)name
797810{
798- [self .metadata addMetadata : userId withKey: BSGKeyId toSection: BSGKeyUser ];
799- [ self .metadata addMetadata: name withKey: BSGKeyName toSection: BSGKeyUser ];
800- [self .metadata addMetadata: email withKey: BSGKeyEmail toSection: BSGKeyUser];
811+ [self .configuration setUser : userId withEmail: email andName: name ];
812+ NSDictionary *userJson = [_user toJson ];
813+ [self .state addMetadata: userJson toSection: BSGKeyUser];
801814
802815 NSMutableDictionary *dict = [NSMutableDictionary new ];
803- BSGDictInsertIfNotNil (dict, self. user . id , @" id" );
804- BSGDictInsertIfNotNil (dict, self. user . email , @" email" );
805- BSGDictInsertIfNotNil (dict, self. user . name , @" name" );
816+ BSGDictInsertIfNotNil (dict, userId , @" id" );
817+ BSGDictInsertIfNotNil (dict, email, @" email" );
818+ BSGDictInsertIfNotNil (dict, name, @" name" );
806819 [self notifyObservers: [[BugsnagStateEvent alloc ] initWithName: kStateEventUser data: dict]];
807820}
808821
@@ -905,7 +918,7 @@ - (void)notify:(NSException *_Nonnull)exception {
905918 [self notify: exception handledState: state block: nil ];
906919}
907920
908- - (void )notify : (NSException *)exception
921+ - (void )notify : (NSException *)exception
909922 block : (BugsnagOnErrorBlock)block
910923{
911924 BugsnagHandledState *state =
@@ -972,15 +985,14 @@ - (void)notify:(NSException *)exception
972985 * 4. -[BSG_KSCrash captureThreads:depth:]
973986 */
974987 int depth = (int )(BSGNotifierStackFrameCount);
975- NSArray *threads = [[BSG_KSCrash sharedInstance ] captureThreads: exception depth: depth];
988+
989+ BOOL recordAllThreads = self.configuration .sendThreads == BSGThreadSendPolicyAlways;
990+ NSArray *threads = [[BSG_KSCrash sharedInstance ] captureThreads: exception
991+ depth: depth
992+ recordAllThreads: recordAllThreads];
976993 NSArray *errors = @[[self generateError: exception threads: threads]];
977994
978995 BugsnagMetadata *metadata = [self .metadata deepCopy ];
979- NSDictionary *deviceFields = [self .state getMetadataFromSection: BSGKeyDeviceState];
980-
981- if (deviceFields) {
982- [metadata addMetadata: deviceFields toSection: BSGKeyDevice];
983- }
984996
985997 NSDictionary *systemInfo = [BSG_KSSystemInfo systemInfo ];
986998 BugsnagEvent *event = [[BugsnagEvent alloc ] initWithApp: [self generateAppWithState: systemInfo]
@@ -1008,6 +1020,13 @@ - (void)notify:(NSException *)exception
10081020- (void )notifyInternal : (BugsnagEvent *_Nonnull)event
10091021 block : (BugsnagOnErrorBlock)block
10101022{
1023+ // enhance device information with additional metadata
1024+ NSDictionary *deviceFields = [self .state getMetadataFromSection: BSGKeyDeviceState];
1025+
1026+ if (deviceFields) {
1027+ [event.metadata addMetadata: deviceFields toSection: BSGKeyDevice];
1028+ }
1029+
10111030 @try {
10121031 if (block != nil && !block (event)) { // skip notifying if callback false
10131032 return ;
@@ -1158,25 +1177,25 @@ - (void)orientationChanged:(NSNotification *)notification {
11581177 _lastOrientation = orientation;
11591178 return ;
11601179 }
1161-
1180+
11621181 // We have an orientation, it's not a dupe and we have a lastOrientation.
11631182 // Send a breadcrumb and preserve the orientation.
1164-
1183+
11651184 [self addAutoBreadcrumbOfType: BSGBreadcrumbTypeState
11661185 withMessage: BSGBreadcrumbNameForNotificationName (notification.name)
11671186 andMetadata: @{
11681187 @" from" : _lastOrientation,
11691188 @" to" : orientation
11701189 }];
1171-
1190+
11721191 _lastOrientation = orientation;
11731192}
11741193
11751194- (void )lowMemoryWarning : (NSNotification *)notif {
11761195 [self .state addMetadata: [BSG_RFC3339DateTool stringFromDate: [NSDate date ]]
11771196 withKey: BSEventLowMemoryWarning
11781197 toSection: BSGKeyDeviceState];
1179-
1198+
11801199 if ([[self configuration ] shouldRecordBreadcrumbType: BSGBreadcrumbTypeState]) {
11811200 [self sendBreadcrumbForNotification: notif];
11821201 }
@@ -1231,7 +1250,7 @@ - (void)updateAutomaticBreadcrumbDetectionSettings {
12311250 object: nil ];
12321251 }
12331252 }
1234-
1253+
12351254 // Navigation events
12361255 if ([[self configuration ] shouldRecordBreadcrumbType: BSGBreadcrumbTypeNavigation]) {
12371256 // UI/NSTableView events
@@ -1313,7 +1332,7 @@ - (void)updateAutomaticBreadcrumbDetectionSettings {
13131332 NSWindowDidExitFullScreenNotification
13141333 ];
13151334#endif
1316-
1335+
13171336 // Fall-through
13181337 return nil ;
13191338}
@@ -1332,7 +1351,7 @@ - (void)updateAutomaticBreadcrumbDetectionSettings {
13321351 NSControlTextDidEndEditingNotification
13331352 ];
13341353#endif
1335-
1354+
13361355 // Fall-through
13371356 return nil ;
13381357}
@@ -1559,10 +1578,19 @@ - (NSArray *)collectBreadcrumbs {
15591578 return data;
15601579}
15611580
1562- - (NSArray *)collectThreads {
1563- int depth = (int )(BSGNotifierStackFrameCount);
1581+ - (NSArray *)collectThreads : (BOOL )unhandled {
1582+ // discard the following
1583+ // 1. [BugsnagReactNative getPayloadInfo:resolve:reject:]
1584+ // 2. [BugsnagClient collectThreads:]
1585+ // 3. [BSG_KSCrash captureThreads:depth:unhandled:]
1586+ int depth = 3 ;
15641587 NSException *exc = [NSException exceptionWithName: @" Bugsnag" reason: @" " userInfo: nil ];
1565- NSArray <BugsnagThread *> *threads = [[BSG_KSCrash sharedInstance ] captureThreads: exc depth: depth];
1588+ BSGThreadSendPolicy sendThreads = self.configuration .sendThreads ;
1589+ BOOL recordAllThreads = sendThreads == BSGThreadSendPolicyAlways
1590+ || (unhandled && sendThreads == BSGThreadSendPolicyUnhandledOnly);
1591+ NSArray <BugsnagThread *> *threads = [[BSG_KSCrash sharedInstance ] captureThreads: exc
1592+ depth: depth
1593+ recordAllThreads: recordAllThreads];
15661594 return [BugsnagThread serializeThreads: threads];
15671595}
15681596
@@ -1573,6 +1601,7 @@ - (void)addRuntimeVersionInfo:(NSString *)info
15731601 if (info != nil && key != nil ) {
15741602 self.extraRuntimeInfo [key] = info;
15751603 }
1604+ [self .state addMetadata: self .extraRuntimeInfo withKey: BSGKeyExtraRuntimeInfo toSection: BSGKeyDevice];
15761605}
15771606
15781607@end
0 commit comments