Skip to content

Commit

Permalink
Wrap automatic collection
Browse files Browse the repository at this point in the history
  • Loading branch information
kattrali committed Jul 22, 2016
1 parent 14ca6c2 commit debc6ab
Show file tree
Hide file tree
Showing 4 changed files with 167 additions and 56 deletions.
7 changes: 7 additions & 0 deletions Source/BugsnagConfiguration.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ typedef NSDictionary *_Nullable (^BugsnagBeforeNotifyHook)(
* The version of the application
*/
@property(nonatomic, readwrite, retain, nullable) NSString *appVersion;

/**
* Additional information about the state of the app or environment at the
* time the report was generated
Expand All @@ -104,6 +105,12 @@ typedef NSDictionary *_Nullable (^BugsnagBeforeNotifyHook)(
*/
@property(nonatomic, readonly, strong, nullable)
BugsnagBreadcrumbs *breadcrumbs;

/**
* Whether to allow collection of automatic breadcrumbs for notable events
*/
@property(nonatomic, readwrite) BOOL automaticallyCollectBreadcrumbs;

/**
* Hooks for modifying crash reports before it is sent to Bugsnag
*/
Expand Down
17 changes: 16 additions & 1 deletion Source/BugsnagConfiguration.m
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@
#import "BugsnagBreadcrumb.h"
#import "BugsnagConfiguration.h"
#import "BugsnagMetaData.h"
#import "Bugsnag.h"
#import "BugsnagNotifier.h"

@interface Bugsnag ()
+ (BugsnagNotifier*)notifier;
@end

@interface BugsnagConfiguration ()
@property(nonatomic, readwrite, strong) NSMutableArray *beforeNotifyHooks;
Expand All @@ -42,12 +48,13 @@ - (id)init {
_metaData = [[BugsnagMetaData alloc] init];
_config = [[BugsnagMetaData alloc] init];
_apiKey = @"";
_autoNotify = true;
_autoNotify = YES;
_notifyURL = [NSURL URLWithString:@"https://notify.bugsnag.com/"];
_beforeNotifyHooks = [NSMutableArray new];
_BugsnagBeforeSendBlock = [NSMutableArray new];
_notifyReleaseStages = nil;
_breadcrumbs = [BugsnagBreadcrumbs new];
_automaticallyCollectBreadcrumbs = YES;
#if DEBUG
_releaseStage = @"development";
#else
Expand Down Expand Up @@ -96,6 +103,14 @@ - (void)setNotifyReleaseStages:(NSArray *)newNotifyReleaseStages;
toTabWithName:@"config"];
}

- (void)setAutomaticallyCollectBreadcrumbs:(BOOL)automaticallyCollectBreadcrumbs {
if (automaticallyCollectBreadcrumbs == _automaticallyCollectBreadcrumbs)
return;

_automaticallyCollectBreadcrumbs = automaticallyCollectBreadcrumbs;
[[Bugsnag notifier] updateAutomaticBreadcrumbDetectionSettings];
}

- (void)setContext:(NSString *)newContext {
_context = newContext;
[self.config addAttribute:@"context"
Expand Down
5 changes: 5 additions & 0 deletions Source/BugsnagNotifier.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,4 +81,9 @@
* @param notificationName name of the notification
*/
- (void)crumbleNotification:(NSString *_Nonnull)notificationName;

/**
* Enable or disable automatic breadcrumb collection based on configuration
*/
- (void)updateAutomaticBreadcrumbDetectionSettings;
@end
194 changes: 139 additions & 55 deletions Source/BugsnagNotifier.m
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
#import <UIKit/UIKit.h>
#include <sys/utsname.h>
#elif TARGET_OS_MAC
#import <AppKit/AppKit.h>
#endif

NSString *const NOTIFIER_VERSION = @"5.3.0";
Expand Down Expand Up @@ -150,7 +152,7 @@ - (void) start {
}

[self performSelectorInBackground:@selector(sendPendingReports) withObject:nil];

[self updateAutomaticBreadcrumbDetectionSettings];
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
[self.details setValue:@"iOS Bugsnag Notifier" forKey:@"name"];

Expand All @@ -174,23 +176,6 @@ - (void) start {
selector:@selector(lowMemoryWarning:)
name:UIApplicationDidReceiveMemoryWarningNotification
object:nil];
[self crumbleNotification:UIWindowDidBecomeHiddenNotification];
[self crumbleNotification:UIWindowDidBecomeVisibleNotification];
[self crumbleNotification:UIApplicationWillTerminateNotification];
[self crumbleNotification:UIApplicationWillEnterForegroundNotification];
[self crumbleNotification:UIApplicationDidEnterBackgroundNotification];
[self crumbleNotification:UIApplicationUserDidTakeScreenshotNotification];
[self crumbleNotification:UIKeyboardDidShowNotification];
[self crumbleNotification:UIKeyboardDidHideNotification];
[self crumbleNotification:UITextFieldTextDidBeginEditingNotification];
[self crumbleNotification:UITextViewTextDidBeginEditingNotification];
[self crumbleNotification:UITextFieldTextDidEndEditingNotification];
[self crumbleNotification:UITextViewTextDidEndEditingNotification];
[self crumbleNotification:UIMenuControllerDidShowMenuNotification];
[self crumbleNotification:UIMenuControllerDidHideMenuNotification];
[self crumbleNotification:NSUndoManagerDidUndoChangeNotification];
[self crumbleNotification:NSUndoManagerDidRedoChangeNotification];
[self crumbleNotification:UITableViewSelectionDidChangeNotification];

[UIDevice currentDevice].batteryMonitoringEnabled = YES;
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
Expand All @@ -199,26 +184,6 @@ - (void) start {
[self orientationChanged:nil];
#elif TARGET_OS_MAC
[self.details setValue:@"OSX Bugsnag Notifier" forKey:@"name"];
[self crumbleNotification:NSApplicationDidBecomeActiveNotification];
[self crumbleNotification:NSApplicationDidResignActiveNotification];
[self crumbleNotification:NSApplicationDidHideNotification];
[self crumbleNotification:NSApplicationDidUnhideNotification];
[self crumbleNotification:NSApplicationWillTerminateNotification];
[self crumbleNotification:NSWorkspaceScreensDidSleepNotification];
[self crumbleNotification:NSWorkspaceScreensDidWakeNotification];
[self crumbleNotification:NSWindowWillCloseNotification];
[self crumbleNotification:NSWindowDidBecomeKeyNotification];
[self crumbleNotification:NSWindowWillMiniaturizeNotification];
[self crumbleNotification:NSWindowDidEnterFullScreenNotification];
[self crumbleNotification:NSWindowDidExitFullScreenNotification];
[self crumbleNotification:NSControlTextDidBeginEditingNotification];
[self crumbleNotification:NSControlTextDidEndEditingNotification];
[self crumbleNotification:NSTableViewSelectionDidChangeNotification];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(didReceiveMenuAction:)
name:NSMenuWillSendActionNotification
object:nil];
#endif
}

Expand Down Expand Up @@ -358,35 +323,114 @@ - (void)orientationChanged:(NSNotification *)notif {
[[self state] addAttribute:@"orientation"
withValue:orientation
toTabWithName:@"deviceState"];
[Bugsnag leaveBreadcrumbWithBlock:^(BugsnagBreadcrumb *_Nonnull breadcrumb) {
breadcrumb.type = BSGBreadcrumbTypeState;
breadcrumb.name = [self breadcrumbNameForNotificationName:notif.name];
breadcrumb.metadata = @{ @"orientation" : orientation };
}];
if ([self.configuration automaticallyCollectBreadcrumbs]) {
[Bugsnag leaveBreadcrumbWithBlock:^(BugsnagBreadcrumb *_Nonnull breadcrumb) {
breadcrumb.type = BSGBreadcrumbTypeState;
breadcrumb.name = [self breadcrumbNameForNotificationName:notif.name];
breadcrumb.metadata = @{ @"orientation" : orientation };
}];
}
}

- (void)lowMemoryWarning:(NSNotification *)notif {
[[self state] addAttribute:BSEventLowMemoryWarning
withValue:[[Bugsnag payloadDateFormatter]
stringFromDate:[NSDate date]]
toTabWithName:@"deviceState"];
[self sendBreadcrumbForNotification:notif];
if ([self.configuration automaticallyCollectBreadcrumbs]) {
[self sendBreadcrumbForNotification:notif];
}
}
#endif

- (void)updateAutomaticBreadcrumbDetectionSettings {
if ([self.configuration automaticallyCollectBreadcrumbs]) {
for (NSString *name in [self automaticBreadcrumbStateEvents]) {
[self crumbleNotification:name];
}
for (NSString *name in [self automaticBreadcrumbControlEvents]) {
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(sendBreadcrumbForControlNotification:)
name:name
object:nil];
}
for (NSString *name in [self automaticBreadcrumbMenuItemEvents]) {
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(sendBreadcrumbForMenuItemNotification:)
name:name
object:nil];
}
} else {
NSArray* eventNames = [[[self automaticBreadcrumbStateEvents]
arrayByAddingObjectsFromArray:[self automaticBreadcrumbControlEvents]]
arrayByAddingObjectsFromArray:[self automaticBreadcrumbMenuItemEvents]];
for (NSString *name in eventNames) {
[[NSNotificationCenter defaultCenter] removeObserver:self
name:name
object:nil];
}
}
}

- (NSArray <NSString *>*)automaticBreadcrumbStateEvents {
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
return @[UIWindowDidBecomeHiddenNotification,
UIWindowDidBecomeVisibleNotification,
UIApplicationWillTerminateNotification,
UIApplicationWillEnterForegroundNotification,
UIApplicationDidEnterBackgroundNotification,
UIApplicationUserDidTakeScreenshotNotification,
UIKeyboardDidShowNotification,
UIKeyboardDidHideNotification,
UIMenuControllerDidShowMenuNotification,
UIMenuControllerDidHideMenuNotification,
NSUndoManagerDidUndoChangeNotification,
NSUndoManagerDidRedoChangeNotification,
UITableViewSelectionDidChangeNotification];
#elif TARGET_OS_MAC
- (void)didReceiveMenuAction:(NSNotification *)notif {
NSMenuItem *menuItem = [[notif userInfo] valueForKey:@"MenuItem"];
if ([menuItem isKindOfClass:[NSMenuItem class]]) {
[Bugsnag
leaveBreadcrumbWithBlock:^(BugsnagBreadcrumb *_Nonnull breadcrumb) {
breadcrumb.type = BSGBreadcrumbTypeState;
breadcrumb.name = [self breadcrumbNameForNotificationName:notif.name];
if (menuItem.title.length > 0)
breadcrumb.metadata = @{ @"action" : menuItem.title };
}];
}
return @[NSApplicationDidBecomeActiveNotification,
NSApplicationDidResignActiveNotification,
NSApplicationDidHideNotification,
NSApplicationDidUnhideNotification,
NSApplicationWillTerminateNotification,
NSWorkspaceScreensDidSleepNotification,
NSWorkspaceScreensDidWakeNotification,
NSWindowWillCloseNotification,
NSWindowDidBecomeKeyNotification,
NSWindowWillMiniaturizeNotification,
NSWindowDidEnterFullScreenNotification,
NSWindowDidExitFullScreenNotification,
NSTableViewSelectionDidChangeNotification];
#else
return nil;
#endif
}

- (NSArray <NSString *>*)automaticBreadcrumbControlEvents {
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
return @[UITextFieldTextDidBeginEditingNotification,
UITextViewTextDidBeginEditingNotification,
UITextFieldTextDidEndEditingNotification,
UITextViewTextDidEndEditingNotification];
#elif TARGET_OS_MAC
return @[NSControlTextDidBeginEditingNotification,
NSControlTextDidEndEditingNotification];
#else
return nil;
#endif
}

- (NSArray <NSString *>*)automaticBreadcrumbMenuItemEvents {
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
return nil;
#elif TARGET_OS_MAC
return @[NSMenuWillSendActionNotification];
#else
return nil;
#endif
}

- (void)crumbleNotification:(NSString *)notificationName {
[[NSNotificationCenter defaultCenter]
Expand All @@ -408,6 +452,46 @@ - (void)sendBreadcrumbForNotification:(NSNotification *)note {
[self serializeBreadcrumbs];
}

- (void)sendBreadcrumbForMenuItemNotification:(NSNotification *)notif {
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
#elif TARGET_OS_MAC
NSMenuItem *menuItem = [[notif userInfo] valueForKey:@"MenuItem"];
if ([menuItem isKindOfClass:[NSMenuItem class]]) {
[Bugsnag
leaveBreadcrumbWithBlock:^(BugsnagBreadcrumb *_Nonnull breadcrumb) {
breadcrumb.type = BSGBreadcrumbTypeState;
breadcrumb.name = [self breadcrumbNameForNotificationName:notif.name];
if (menuItem.title.length > 0)
breadcrumb.metadata = @{ @"action" : menuItem.title };
}];
}
#endif
}

- (void)sendBreadcrumbForControlNotification:(NSNotification *)note {
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
UIControl* control = note.object;
[Bugsnag leaveBreadcrumbWithBlock:^(BugsnagBreadcrumb *_Nonnull breadcrumb) {
breadcrumb.type = BSGBreadcrumbTypeUser;
breadcrumb.name = [self breadcrumbNameForNotificationName:note.name];
NSString *label = control.accessibilityLabel;
if (label.length > 0) {
breadcrumb.metadata = @{ @"label": label };
}
}];
#elif TARGET_OS_MAC
NSControl *control = note.object;
[Bugsnag leaveBreadcrumbWithBlock:^(BugsnagBreadcrumb *_Nonnull breadcrumb) {
breadcrumb.type = BSGBreadcrumbTypeUser;
breadcrumb.name = [self breadcrumbNameForNotificationName:note.name];
NSString *label = control.accessibilityLabel;
if (label.length > 0) {
breadcrumb.metadata = @{ @"label": label };
}
}];
#endif
}

- (NSString *)breadcrumbNameForNotificationName:(NSString *)name {
return [name stringByReplacingOccurrencesOfString:@"Notification"
withString:@""];
Expand Down

0 comments on commit debc6ab

Please sign in to comment.