Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add pre-notify hooks #90

Merged
merged 4 commits into from
Feb 5, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 27 additions & 11 deletions Source/Bugsnag/BugsnagConfiguration.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,24 +28,40 @@

#import "BugsnagMetaData.h"
#import "KSCrashReportWriter.h"
/**
* A handler for modifying data before sending it to Bugsnag
*
* @param rawEventReports The raw event data written at crash time. This
* includes data added in onCrashHandler.
* @param report The default report payload
*
* @return the report payload intended to be sent or nil to cancel sending
*/
typedef NSDictionary * (^BugsnagBeforeNotifyHook)(NSArray *rawEventReports,
NSDictionary *report);

@class BugsnagBreadcrumbs;

@interface BugsnagConfiguration : NSObject

@property(nonatomic,readwrite,retain) NSString* apiKey;
@property(nonatomic,readwrite,retain) NSURL* notifyURL;
@property(nonatomic,readwrite,retain) NSString* releaseStage;
@property(nonatomic,readwrite,retain) NSArray* notifyReleaseStages;
@property(nonatomic,readwrite,retain) NSString* context;
@property(nonatomic,readwrite,retain) NSString* appVersion;
@property(nonatomic,readwrite,retain) BugsnagMetaData* metaData;
@property(nonatomic,readwrite,retain) BugsnagMetaData* config;
@property(nonatomic,readonly,strong) BugsnagBreadcrumbs* breadcrumbs;
@property(nonatomic) void (*onCrashHandler)(const KSCrashReportWriter* writer);
@property(nonatomic, readwrite, retain) NSString *apiKey;
@property(nonatomic, readwrite, retain) NSURL *notifyURL;
@property(nonatomic, readwrite, retain) NSString *releaseStage;
@property(nonatomic, readwrite, retain) NSArray *notifyReleaseStages;
@property(nonatomic, readwrite, retain) NSString *context;
@property(nonatomic, readwrite, retain) NSString *appVersion;
@property(nonatomic, readwrite, retain) BugsnagMetaData *metaData;
@property(nonatomic, readwrite, retain) BugsnagMetaData *config;
@property(nonatomic, readonly, strong) BugsnagBreadcrumbs *breadcrumbs;
@property(nonatomic, readonly, strong) NSArray *beforeNotifyHooks;
@property(nonatomic) void (*onCrashHandler)(const KSCrashReportWriter *writer);

@property(nonatomic) BOOL autoNotify;

- (void) setUser:(NSString*) userId withName:(NSString*) name andEmail:(NSString*) email;
- (void)setUser:(NSString *)userId
withName:(NSString *)name
andEmail:(NSString *)email;

- (void)addBeforeNotifyHook:(BugsnagBeforeNotifyHook)hook;

@end
95 changes: 50 additions & 45 deletions Source/Bugsnag/BugsnagConfiguration.m
Original file line number Diff line number Diff line change
Expand Up @@ -24,69 +24,74 @@
// THE SOFTWARE.
//

#import "BugsnagConfiguration.h"
#import "BugsnagBreadcrumb.h"
#import "BugsnagConfiguration.h"

@implementation BugsnagConfiguration
@interface BugsnagConfiguration ()
@property(nonatomic, readwrite, strong) NSMutableArray *beforeNotifyHooks;
@end

-(id)init {
if (self = [super init]) {
self.metaData = [[BugsnagMetaData alloc] init];
self.config = [[BugsnagMetaData alloc] init];
self.apiKey = @"";
self.autoNotify = true;
self.notifyURL = [NSURL URLWithString:@"https://notify.bugsnag.com/"];
@implementation BugsnagConfiguration

self.notifyReleaseStages = nil;
_breadcrumbs = [BugsnagBreadcrumbs new];
- (id)init {
if (self = [super init]) {
_metaData = [[BugsnagMetaData alloc] init];
_config = [[BugsnagMetaData alloc] init];
_apiKey = @"";
_autoNotify = true;
_notifyURL = [NSURL URLWithString:@"https://notify.bugsnag.com/"];
_beforeNotifyHooks = [NSMutableArray new];
_notifyReleaseStages = nil;
_breadcrumbs = [BugsnagBreadcrumbs new];
#if DEBUG
self.releaseStage = @"development";
_releaseStage = @"development";
#else
self.releaseStage = @"production";
_releaseStage = @"production";
#endif
}
return self;
}
return self;
}
-(void)setUser:(NSString*)userId withName: (NSString*) userName andEmail:(NSString*)userEmail
{
[self.metaData addAttribute:@"id" withValue:userId toTabWithName:@"user"];
[self.metaData addAttribute:@"name" withValue:userName toTabWithName:@"user"];
[self.metaData addAttribute:@"email" withValue:userEmail toTabWithName:@"user"];
- (void)setUser:(NSString *)userId
withName:(NSString *)userName
andEmail:(NSString *)userEmail {
[self.metaData addAttribute:@"id" withValue:userId toTabWithName:@"user"];
[self.metaData addAttribute:@"name" withValue:userName toTabWithName:@"user"];
[self.metaData addAttribute:@"email"
withValue:userEmail
toTabWithName:@"user"];
}

@synthesize metaData;
@synthesize config;

@synthesize notifyURL;
@synthesize apiKey;
@synthesize autoNotify;
@synthesize releaseStage;
@synthesize notifyReleaseStages;
@synthesize context;
@synthesize appVersion;

-(void) setReleaseStage:(NSString *)newReleaseStage {
self->releaseStage = newReleaseStage;
[self.config addAttribute:@"releaseStage" withValue:newReleaseStage toTabWithName:@"config"];
- (void)addBeforeNotifyHook:(BugsnagBeforeNotifyHook)hook {
[(NSMutableArray *)self.beforeNotifyHooks addObject:[hook copy]];
}

- (void)setReleaseStage:(NSString *)newReleaseStage {
_releaseStage = newReleaseStage;
[self.config addAttribute:@"releaseStage"
withValue:newReleaseStage
toTabWithName:@"config"];
}

- (void)setNotifyReleaseStages:(NSArray *)newNotifyReleaseStages;
{
NSArray *notifyReleaseStagesCopy = [newNotifyReleaseStages copy];
self->notifyReleaseStages = notifyReleaseStagesCopy;
[self.config addAttribute:@"notifyReleaseStages" withValue:notifyReleaseStagesCopy toTabWithName:@"config"];
NSArray *notifyReleaseStagesCopy = [newNotifyReleaseStages copy];
_notifyReleaseStages = notifyReleaseStagesCopy;
[self.config addAttribute:@"notifyReleaseStages"
withValue:notifyReleaseStagesCopy
toTabWithName:@"config"];
}

-(void) setContext:(NSString *)newContext
{
self->context = newContext;
[self.config addAttribute:@"context" withValue: newContext toTabWithName:@"config"];
- (void)setContext:(NSString *)newContext {
_context = newContext;
[self.config addAttribute:@"context"
withValue:newContext
toTabWithName:@"config"];
}

-(void) setAppVersion:(NSString *)newVersion
{
self->appVersion = newVersion;
[self.config addAttribute:@"appVersion" withValue: newVersion toTabWithName:@"config"];
- (void)setAppVersion:(NSString *)newVersion {
_appVersion = newVersion;
[self.config addAttribute:@"appVersion"
withValue:newVersion
toTabWithName:@"config"];
}
@end
19 changes: 16 additions & 3 deletions Source/Bugsnag/BugsnagSink.m
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,22 @@ - (void) filterReports:(NSArray*) reports onCompletion:(KSCrashReportFilterCompl
}
return;
}


NSData* jsonData = [KSJSONCodec encode:[self getBodyFromReports: bugsnagReports]

NSDictionary *reportData = [self getBodyFromReports:bugsnagReports];
for (BugsnagBeforeNotifyHook hook in configuration.beforeNotifyHooks) {
if (reportData) {
reportData = hook(reports, reportData);
} else {
break;
}
}
if (reportData == nil) {
if (onCompletion) {
onCompletion(@[], YES, nil);
}
return;
}
NSData* jsonData = [KSJSONCodec encode:reportData
options:KSJSONEncodeOptionSorted | KSJSONEncodeOptionPretty
error:&error];

Expand Down
32 changes: 30 additions & 2 deletions docs/Configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,29 @@ to NO:
[Bugsnag configuration].autoNotify = NO;
```

### `beforeNotifyHooks`

When an app first launches after a crash or a manual notification is triggered,
crash reports are sent to Bugsnag. The `beforeNotifyHooks` allow you to
modify or filter report information uploaded. Each `report` has an `apiKey`,
`notifier` info, and `events`, which contains crash details and `metaData` about
the application state. The `rawEventReports` are the data written at crash-time,
including any additional information written during `onCrashHandler`.

**NOTE:** If a hook returns nil from execution, no report is sent.

**NOTE:** Segmentation faults and other similar crashes cannot be caught within
handlers.

```objective-c
BugsnagConfiguration *config = [BugsnagConfiguration new];
[config addBeforeNotifyHook:^NSDictionary *(NSArray *rawEventReports, NSDictionary *report) {
NSMutableDictionary *reportCopy = [report mutableCopy];
// ...
return [reportCopy copy];
}];
```

### `context`

Bugsnag uses the concept of "contexts" to help display and group your errors.
Expand Down Expand Up @@ -72,15 +95,17 @@ config.apiKey = @"YOUR_API_KEY_HERE";
When a crash occurs in an application, information about the runtime state of
the application is collected and prepared to be sent to Bugsnag on the next
launch. The `onCrashHandler` hook allows you to execute additional code after
the crash report has been written.
the crash report has been written. This data is available for inspection after
the next launch during the [`beforeNotifyHooks`](#beforenotifyhooks) phase.

**NOTE:** All functions called from a signal handler must be
[asynchronous-safe](https://www.securecoding.cert.org/confluence/display/c/SIG30-C.+Call+only+asynchronous-safe+functions+within+signal+handlers).
This excludes any Objective-C, in particular.

```objective-c
```c
void HandleCrashedThread(const KSCrashReportWriter *writer) {
// possibly serialize data, call another crash reporter
writer->addJSONElement(writer, "dessertMap", dessertMapObj);
}

// ...
Expand All @@ -89,6 +114,9 @@ BugsnagConfiguration *config = [[BugsnagConfiguration alloc] init];
config.onCrashHandler = &HandleCrashedThread;
```

[Functions available on `KSCrashReportWriter`](https://github.com/kstenerud/KSCrash/blob/master/Source/KSCrash/Recording/KSCrashReportWriter.h)


### `releaseStage`

In order to distinguish between errors that occur in different stages of the
Expand Down