Skip to content

Commit

Permalink
Merge pull request #1089 from bugsnag/nickdowell/internal-error-repor…
Browse files Browse the repository at this point in the history
…ting

[PLAT-6482] Internal error reporting
  • Loading branch information
nickdowell committed May 10, 2021
2 parents 1461cf0 + 0aad729 commit f58f253
Show file tree
Hide file tree
Showing 15 changed files with 457 additions and 12 deletions.
26 changes: 26 additions & 0 deletions Bugsnag.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -679,6 +679,16 @@
01840B7325DC26E200F95648 /* BSGEventUploader.m in Sources */ = {isa = PBXBuildFile; fileRef = 01840B6E25DC26E200F95648 /* BSGEventUploader.m */; };
01840B7425DC26E200F95648 /* BSGEventUploader.m in Sources */ = {isa = PBXBuildFile; fileRef = 01840B6E25DC26E200F95648 /* BSGEventUploader.m */; };
01840B7525DC26E200F95648 /* BSGEventUploader.m in Sources */ = {isa = PBXBuildFile; fileRef = 01840B6E25DC26E200F95648 /* BSGEventUploader.m */; };
01847D962644140F00ADA4C7 /* BSGInternalErrorReporter.h in Headers */ = {isa = PBXBuildFile; fileRef = 01847D942644140F00ADA4C7 /* BSGInternalErrorReporter.h */; };
01847D972644140F00ADA4C7 /* BSGInternalErrorReporter.h in Headers */ = {isa = PBXBuildFile; fileRef = 01847D942644140F00ADA4C7 /* BSGInternalErrorReporter.h */; };
01847D982644140F00ADA4C7 /* BSGInternalErrorReporter.h in Headers */ = {isa = PBXBuildFile; fileRef = 01847D942644140F00ADA4C7 /* BSGInternalErrorReporter.h */; };
01847D992644140F00ADA4C7 /* BSGInternalErrorReporter.m in Sources */ = {isa = PBXBuildFile; fileRef = 01847D952644140F00ADA4C7 /* BSGInternalErrorReporter.m */; };
01847D9A2644140F00ADA4C7 /* BSGInternalErrorReporter.m in Sources */ = {isa = PBXBuildFile; fileRef = 01847D952644140F00ADA4C7 /* BSGInternalErrorReporter.m */; };
01847D9B2644140F00ADA4C7 /* BSGInternalErrorReporter.m in Sources */ = {isa = PBXBuildFile; fileRef = 01847D952644140F00ADA4C7 /* BSGInternalErrorReporter.m */; };
01847D9C2644140F00ADA4C7 /* BSGInternalErrorReporter.m in Sources */ = {isa = PBXBuildFile; fileRef = 01847D952644140F00ADA4C7 /* BSGInternalErrorReporter.m */; };
01847DAC26441A5E00ADA4C7 /* BSGInternalErrorReporterTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 01847DAB26441A5E00ADA4C7 /* BSGInternalErrorReporterTests.m */; };
01847DAD26441A5E00ADA4C7 /* BSGInternalErrorReporterTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 01847DAB26441A5E00ADA4C7 /* BSGInternalErrorReporterTests.m */; };
01847DAE26441A5E00ADA4C7 /* BSGInternalErrorReporterTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 01847DAB26441A5E00ADA4C7 /* BSGInternalErrorReporterTests.m */; };
0187D464255BD7B800C503D9 /* BugsnagApiClientTest.m in Sources */ = {isa = PBXBuildFile; fileRef = CB9103632502320A00E9D1E2 /* BugsnagApiClientTest.m */; };
019480D42625F3EB00E833ED /* BSGAppKitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 019480D32625F3EB00E833ED /* BSGAppKitTests.m */; };
01B14C56251CE55F00118748 /* report-react-native-promise-rejection.json in Resources */ = {isa = PBXBuildFile; fileRef = 01B14C55251CE55F00118748 /* report-react-native-promise-rejection.json */; };
Expand Down Expand Up @@ -1321,6 +1331,9 @@
017824BD262D65A000D18AFA /* Bugsnag.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Bugsnag.xcconfig; sourceTree = "<group>"; };
01840B6D25DC26E200F95648 /* BSGEventUploader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BSGEventUploader.h; sourceTree = "<group>"; };
01840B6E25DC26E200F95648 /* BSGEventUploader.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BSGEventUploader.m; sourceTree = "<group>"; };
01847D942644140F00ADA4C7 /* BSGInternalErrorReporter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BSGInternalErrorReporter.h; sourceTree = "<group>"; };
01847D952644140F00ADA4C7 /* BSGInternalErrorReporter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BSGInternalErrorReporter.m; sourceTree = "<group>"; };
01847DAB26441A5E00ADA4C7 /* BSGInternalErrorReporterTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BSGInternalErrorReporterTests.m; sourceTree = "<group>"; };
01937CF9257A7B4C00F2DE31 /* Bugsnag+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Bugsnag+Private.h"; sourceTree = "<group>"; };
01937D09257A7ED000F2DE31 /* BugsnagSessionTracker+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "BugsnagSessionTracker+Private.h"; sourceTree = "<group>"; };
01937D11257A814D00F2DE31 /* BugsnagMetadata+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "BugsnagMetadata+Private.h"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1708,6 +1721,7 @@
00896A3F2486DBDD00DC48C2 /* BSGConfigurationBuilderTests.m */,
008966C62486D43600DC48C2 /* BSGConnectivityTest.m */,
01BDB1CE25DEBF4600A91FAF /* BSGEventUploadKSCrashReportOperationTests.m */,
01847DAB26441A5E00ADA4C7 /* BSGInternalErrorReporterTests.m */,
CBCF77AA250142E0004AF22A /* BSGJSONSerializationTests.m */,
008966C82486D43600DC48C2 /* BSGOutOfMemoryTests.m */,
CB6419AA25A73E8C00613D25 /* BSGStorageMigratorTests.m */,
Expand Down Expand Up @@ -1838,6 +1852,8 @@
010FF28225ED2A8D00E4F2B0 /* BSGAppHangDetector.h */,
010FF28325ED2A8D00E4F2B0 /* BSGAppHangDetector.m */,
019480C42625EE9800E833ED /* BSGAppKit.h */,
01847D942644140F00ADA4C7 /* BSGInternalErrorReporter.h */,
01847D952644140F00ADA4C7 /* BSGInternalErrorReporter.m */,
CBCF77A125010648004AF22A /* BSGJSONSerialization.h */,
CBCF77A225010648004AF22A /* BSGJSONSerialization.m */,
008968112486DA5600DC48C2 /* BSGSerialization.h */,
Expand Down Expand Up @@ -2022,6 +2038,7 @@
0126F7AB25DD5118008483C2 /* BSGEventUploadFileOperation.h in Headers */,
3A700A9A24A63AC60068CD1B /* BSG_KSCrashReportWriter.h in Headers */,
3A700A9B24A63AC60068CD1B /* BugsnagErrorTypes.h in Headers */,
01847D962644140F00ADA4C7 /* BSGInternalErrorReporter.h in Headers */,
01840B6F25DC26E200F95648 /* BSGEventUploader.h in Headers */,
3A700A9C24A63AC60068CD1B /* BugsnagEvent.h in Headers */,
3A700A9D24A63AC60068CD1B /* BugsnagClient.h in Headers */,
Expand Down Expand Up @@ -2125,6 +2142,7 @@
0126F7AC25DD5118008483C2 /* BSGEventUploadFileOperation.h in Headers */,
3A700AAE24A63CFD0068CD1B /* BSG_KSCrashReportWriter.h in Headers */,
3A700AAF24A63CFD0068CD1B /* BugsnagErrorTypes.h in Headers */,
01847D972644140F00ADA4C7 /* BSGInternalErrorReporter.h in Headers */,
01840B7025DC26E200F95648 /* BSGEventUploader.h in Headers */,
3A700AB024A63CFD0068CD1B /* BugsnagEvent.h in Headers */,
3A700AB124A63CFD0068CD1B /* BugsnagClient.h in Headers */,
Expand Down Expand Up @@ -2228,6 +2246,7 @@
0126F7AD25DD5118008483C2 /* BSGEventUploadFileOperation.h in Headers */,
3A700AC224A63D110068CD1B /* BSG_KSCrashReportWriter.h in Headers */,
3A700AC324A63D110068CD1B /* BugsnagErrorTypes.h in Headers */,
01847D982644140F00ADA4C7 /* BSGInternalErrorReporter.h in Headers */,
01840B7125DC26E200F95648 /* BSGEventUploader.h in Headers */,
3A700AC424A63D110068CD1B /* BugsnagEvent.h in Headers */,
3A700AC524A63D110068CD1B /* BugsnagClient.h in Headers */,
Expand Down Expand Up @@ -2624,6 +2643,7 @@
0126F79E25DD510E008483C2 /* BSGEventUploadObjectOperation.m in Sources */,
0089682B2486DA5600DC48C2 /* BSGSerialization.m in Sources */,
011ADCE626049A3600B20D72 /* BugsnagClient+OutOfMemory.m in Sources */,
01847D992644140F00ADA4C7 /* BSGInternalErrorReporter.m in Sources */,
008968E92486DAB800DC48C2 /* BugsnagSessionFileStore.m in Sources */,
00896A172486DAD100DC48C2 /* BSG_KSCrashSentry_CPPException.mm in Sources */,
008969CF2486DAD100DC48C2 /* BSG_KSCrashState.m in Sources */,
Expand Down Expand Up @@ -2715,6 +2735,7 @@
01E8765E256684E700F4B70A /* URLSessionMock.m in Sources */,
008967AB2486D43700DC48C2 /* KSMach_Tests.m in Sources */,
0089672A2486D43700DC48C2 /* BugsnagStacktraceTest.m in Sources */,
01847DAC26441A5E00ADA4C7 /* BSGInternalErrorReporterTests.m in Sources */,
0163BF5925823D8D008DC28B /* NotificationBreadcrumbTests.m in Sources */,
008967392486D43700DC48C2 /* BugsnagEventFromKSCrashReportTest.m in Sources */,
008967182486D43700DC48C2 /* BugsnagErrorTest.m in Sources */,
Expand Down Expand Up @@ -2794,6 +2815,7 @@
0126F79F25DD510E008483C2 /* BSGEventUploadObjectOperation.m in Sources */,
0089682C2486DA5600DC48C2 /* BSGSerialization.m in Sources */,
011ADCE726049A3600B20D72 /* BugsnagClient+OutOfMemory.m in Sources */,
01847D9A2644140F00ADA4C7 /* BSGInternalErrorReporter.m in Sources */,
008968EA2486DAB800DC48C2 /* BugsnagSessionFileStore.m in Sources */,
00896A182486DAD100DC48C2 /* BSG_KSCrashSentry_CPPException.mm in Sources */,
008969D02486DAD100DC48C2 /* BSG_KSCrashState.m in Sources */,
Expand Down Expand Up @@ -2857,6 +2879,7 @@
008967792486D43700DC48C2 /* KSMachHeader_Tests.m in Sources */,
0089675E2486D43700DC48C2 /* BugsnagSessionTrackingPayloadTest.m in Sources */,
008967A92486D43700DC48C2 /* KSCrashIdentifierTests.m in Sources */,
01847DAD26441A5E00ADA4C7 /* BSGInternalErrorReporterTests.m in Sources */,
0089672B2486D43700DC48C2 /* BugsnagStacktraceTest.m in Sources */,
008966F22486D43700DC48C2 /* BugsnagMetadataRedactionTest.m in Sources */,
CBDD6D0725AC3EFF00A2E12B /* BSGStorageMigratorTests.m in Sources */,
Expand Down Expand Up @@ -2963,6 +2986,7 @@
0126F7A025DD510E008483C2 /* BSGEventUploadObjectOperation.m in Sources */,
0089682D2486DA5600DC48C2 /* BSGSerialization.m in Sources */,
011ADCE826049A3600B20D72 /* BugsnagClient+OutOfMemory.m in Sources */,
01847D9B2644140F00ADA4C7 /* BSGInternalErrorReporter.m in Sources */,
008968EB2486DAB800DC48C2 /* BugsnagSessionFileStore.m in Sources */,
00896A192486DAD100DC48C2 /* BSG_KSCrashSentry_CPPException.mm in Sources */,
008969D12486DAD100DC48C2 /* BSG_KSCrashState.m in Sources */,
Expand Down Expand Up @@ -3058,6 +3082,7 @@
008967772486D43700DC48C2 /* XCTestCase+KSCrash.m in Sources */,
008967322486D43700DC48C2 /* BugsnagStateEventTest.m in Sources */,
CBA2249D251E429C00B87416 /* TestSupport.m in Sources */,
01847DAE26441A5E00ADA4C7 /* BSGInternalErrorReporterTests.m in Sources */,
004E35372487AFF2007FBAE4 /* BugsnagHandledStateTest.m in Sources */,
016875C8258D003200DFFF69 /* NSUserDefaultsStub.m in Sources */,
01C17AE92542ED7F00C102C9 /* KSCrashReportWriterTests.m in Sources */,
Expand Down Expand Up @@ -3147,6 +3172,7 @@
0126F79125DD508C008483C2 /* BSGEventUploadOperation.m in Sources */,
008967EB2486DA2D00DC48C2 /* BugsnagErrorTypes.m in Sources */,
008967D62486DA2D00DC48C2 /* BugsnagEndpointConfiguration.m in Sources */,
01847D9C2644140F00ADA4C7 /* BSGInternalErrorReporter.m in Sources */,
00AD1F262486A17900A27979 /* Bugsnag.m in Sources */,
0127149825F6171000D3500A /* BugsnagClient+AppHangs.m in Sources */,
008968CE2486DA9600DC48C2 /* BugsnagThread.m in Sources */,
Expand Down
5 changes: 4 additions & 1 deletion Bugsnag/Client/BugsnagClient.m
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#import "BSGConnectivity.h"
#import "BSGEventUploader.h"
#import "BSGFileLocations.h"
#import "BSGInternalErrorReporter.h"
#import "BSGJSONSerialization.h"
#import "BSGNotificationBreadcrumbs.h"
#import "BSGSerialization.h"
Expand Down Expand Up @@ -219,7 +220,7 @@ void BSGWriteSessionCrashData(BugsnagSession *session) {
// MARK: - BugsnagClient
// =============================================================================

@interface BugsnagClient () <BSGBreadcrumbSink>
@interface BugsnagClient () <BSGBreadcrumbSink, BSGInternalErrorReporterDataSource>

@property (nonatomic) BSGNotificationBreadcrumbs *notificationBreadcrumbs;

Expand Down Expand Up @@ -318,6 +319,8 @@ - (instancetype)initWithConfiguration:(BugsnagConfiguration *)configuration {
if (self.user.id == nil) { // populate with an autogenerated ID if no value set
[self setUser:[BSG_KSSystemInfo deviceAndAppHash] withEmail:configuration.user.email andName:configuration.user.name];
}

BSGInternalErrorReporter.sharedInstance = [[BSGInternalErrorReporter alloc] initWithDataSource:self];
}
return self;
}
Expand Down
33 changes: 29 additions & 4 deletions Bugsnag/Delivery/BSGEventUploadKSCrashReportOperation.m
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#import "BSGEventUploadKSCrashReportOperation.h"

#import "BSGInternalErrorReporter.h"
#import "BSGJSONSerialization.h"
#import "BSG_KSCrashDoctor.h"
#import "BSG_KSCrashReportFields.h"
Expand All @@ -22,17 +23,41 @@
@implementation BSGEventUploadKSCrashReportOperation

- (BugsnagEvent *)loadEventAndReturnError:(NSError * __autoreleasing *)errorPtr {
id json = [BSGJSONSerialization JSONObjectWithContentsOfFile:self.file options:0 error:errorPtr];
if (!json) {
NSError *error = nil;

NSData *data = [NSData dataWithContentsOfFile:self.file options:0 error:&error];
if (!data) {
[BSGInternalErrorReporter.sharedInstance reportErrorWithClass:@"File reading error"
message:BSGErrorDescription(error)
diagnostics:error.userInfo];
if (errorPtr) {
*errorPtr = error;
}
return nil;
}

json = [self fixupCrashReport:json];
id json = [BSGJSONSerialization JSONObjectWithData:data options:0 error:&error];
if (!json) {
NSMutableDictionary *diagnostics = [NSMutableDictionary dictionary];
diagnostics[@"data"] = [data base64EncodedStringWithOptions:0];
[BSGInternalErrorReporter.sharedInstance reportErrorWithClass:@"JSON parsing error"
message:BSGErrorDescription(error)
diagnostics:diagnostics];
if (errorPtr) {
*errorPtr = error;
}
return nil;
}

NSDictionary *crashReport = [self fixupCrashReport:json];
if (!crashReport) {
[BSGInternalErrorReporter.sharedInstance reportErrorWithClass:@"Unexpected JSON payload"
message:@"-fixupCrashReport: returned nil"
diagnostics:@{@"json": json}];
return nil;
}

BugsnagEvent *event = [[BugsnagEvent alloc] initWithKSReport:json];
BugsnagEvent *event = [[BugsnagEvent alloc] initWithKSReport:crashReport];

if (!event.app.type) {
// Use current value for crashes from older notifier versions that didn't persist config.appType
Expand Down
2 changes: 1 addition & 1 deletion Bugsnag/Delivery/BugsnagApiClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ typedef NS_ENUM(NSInteger, BugsnagApiClientDeliveryStatus) {
toURL:(NSURL *)url
completionHandler:(void (^)(BugsnagApiClientDeliveryStatus status, NSError * _Nullable error))completionHandler;

- (NSString *)SHA1HashStringWithData:(NSData *)data;
+ (NSString *)SHA1HashStringWithData:(NSData *)data;

@property (readonly, nonatomic) NSOperationQueue *sendQueue;

Expand Down
4 changes: 2 additions & 2 deletions Bugsnag/Delivery/BugsnagApiClient.m
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ - (void)sendJSONPayload:(NSDictionary *)payload
}

NSMutableDictionary<BugsnagHTTPHeaderName, NSString *> *mutableHeaders = [headers mutableCopy];
mutableHeaders[BugsnagHTTPHeaderNameIntegrity] = [NSString stringWithFormat:@"sha1 %@", [self SHA1HashStringWithData:data]];
mutableHeaders[BugsnagHTTPHeaderNameIntegrity] = [NSString stringWithFormat:@"sha1 %@", [BugsnagApiClient SHA1HashStringWithData:data]];

NSMutableURLRequest *request = [self prepareRequest:url headers:mutableHeaders];
bsg_log_debug(@"Sending %lu byte payload to %@", (unsigned long)data.length, url);
Expand Down Expand Up @@ -150,7 +150,7 @@ - (NSMutableURLRequest *)prepareRequest:(NSURL *)url
return request;
}

- (NSString *)SHA1HashStringWithData:(NSData *)data {
+ (NSString *)SHA1HashStringWithData:(NSData *)data {
if (!data) {
return nil;
}
Expand Down
66 changes: 66 additions & 0 deletions Bugsnag/Helpers/BSGInternalErrorReporter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
//
// BSGInternalErrorReporter.h
// Bugsnag
//
// Created by Nick Dowell on 06/05/2021.
// Copyright © 2021 Bugsnag Inc. All rights reserved.
//

#import <Foundation/Foundation.h>

@class BugsnagAppWithState;
@class BugsnagConfiguration;
@class BugsnagDeviceWithState;
@class BugsnagEvent;
@class BugsnagNotifier;

NS_ASSUME_NONNULL_BEGIN

/// Returns a concise desription of the error including its domain, code, and debug description or localizedDescription.
FOUNDATION_EXPORT NSString *BSGErrorDescription(NSError *error);

// MARK: -

@protocol BSGInternalErrorReporterDataSource <NSObject>

@property (readonly, nonatomic) BugsnagConfiguration *configuration;

@property (readonly, nonatomic) BugsnagNotifier *notifier;

- (BugsnagAppWithState *)generateAppWithState:(NSDictionary *)systemInfo;

- (BugsnagDeviceWithState *)generateDeviceWithState:(NSDictionary *)systemInfo;

@end

// MARK: -

@interface BSGInternalErrorReporter : NSObject

@property (class, nonatomic) BSGInternalErrorReporter *sharedInstance;

- (instancetype)initWithDataSource:(id<BSGInternalErrorReporterDataSource>)dataSource NS_DESIGNATED_INITIALIZER;

- (instancetype)init UNAVAILABLE_ATTRIBUTE;

/// Reports an error to Bugsnag's internal bugsnag-cocoa project dashboard.
/// @param errorClass The class of error which occurred. This field is used to group the errors together so should not contain any contextual
/// information that would prevent correct grouping. This would ordinarily be the Exception name when dealing with an exception.
/// @param message The error message associated with the error. Usually this will contain some information about this specific instance of the error
/// and is not used to group the errors.
/// @param diagnostics JSON compatible information to include in the `BugsnagDiagnostics` metadata section.
- (void)reportErrorWithClass:(NSString *)errorClass
message:(nullable NSString *)message
diagnostics:(nullable NSDictionary<NSString *, id> *)diagnostics;

// Private

- (nullable BugsnagEvent *)eventWithErrorClass:(NSString *)errorClass
message:(nullable NSString *)message
diagnostics:(nullable NSDictionary<NSString *, id> *)diagnostics;

- (nullable NSURLRequest *)requestForEvent:(BugsnagEvent *)event error:(NSError * __autoreleasing *)errorPtr;

@end

NS_ASSUME_NONNULL_END
Loading

0 comments on commit f58f253

Please sign in to comment.