diff --git a/Crashlytics/Crashlytics/Components/FIRCLSUserLogging.h b/Crashlytics/Crashlytics/Components/FIRCLSUserLogging.h index e0cadd483fb..980cd57cbf2 100644 --- a/Crashlytics/Crashlytics/Components/FIRCLSUserLogging.h +++ b/Crashlytics/Crashlytics/Components/FIRCLSUserLogging.h @@ -81,7 +81,9 @@ void FIRCLSUserLoggingRecordUserKeysAndValues(NSDictionary* keysAndValues); void FIRCLSUserLoggingRecordInternalKeyValue(NSString* key, id value); void FIRCLSUserLoggingWriteInternalKeyValue(NSString* key, NSString* value); -void FIRCLSUserLoggingRecordError(NSError* error, NSDictionary* additionalUserInfo); +void FIRCLSUserLoggingRecordError(NSError* error, + NSDictionary* additionalUserInfo, + NSUInteger skipStacks); NSDictionary* FIRCLSUserLoggingGetCompactedKVEntries(FIRCLSUserLoggingKVStorage* storage, bool decodeHex); diff --git a/Crashlytics/Crashlytics/Components/FIRCLSUserLogging.m b/Crashlytics/Crashlytics/Components/FIRCLSUserLogging.m index 31b4deef1e9..c9f120dff3a 100644 --- a/Crashlytics/Crashlytics/Components/FIRCLSUserLogging.m +++ b/Crashlytics/Crashlytics/Components/FIRCLSUserLogging.m @@ -379,7 +379,8 @@ static void FIRCLSUserLoggingWriteError(FIRCLSFile *file, } void FIRCLSUserLoggingRecordError(NSError *error, - NSDictionary *additionalUserInfo) { + NSDictionary *additionalUserInfo, + NSUInteger numberOfStacksToSkip) { if (!error) { return; } @@ -391,6 +392,10 @@ void FIRCLSUserLoggingRecordError(NSError *error, // record the stacktrace and timestamp here, so we // are as close as possible to the user's log statement NSArray *addresses = [NSThread callStackReturnAddresses]; + if (numberOfStacksToSkip > 0 && [addresses count] > numberOfStacksToSkip) { + NSRange range = NSMakeRange(numberOfStacksToSkip, [addresses count] - numberOfStacksToSkip); + addresses = [addresses subarrayWithRange:range]; + } uint64_t timestamp = time(NULL); FIRCLSUserLoggingWriteAndCheckABFiles( diff --git a/Crashlytics/Crashlytics/FIRCrashlytics.m b/Crashlytics/Crashlytics/FIRCrashlytics.m index 4d112cddad4..4beb6574c6a 100644 --- a/Crashlytics/Crashlytics/FIRCrashlytics.m +++ b/Crashlytics/Crashlytics/FIRCrashlytics.m @@ -94,6 +94,7 @@ @interface FIRCrashlytics () *)userInfo { - FIRCLSUserLoggingRecordError(error, userInfo); + FIRCLSUserLoggingRecordError(error, userInfo, self.stackFramesToSkip); } - (void)recordExceptionModel:(FIRExceptionModel *)exceptionModel { @@ -391,6 +393,10 @@ - (void)recordOnDemandExceptionModel:(FIRExceptionModel *)exceptionModel { usingExistingReportManager:self.existingReportManager]; } +- (void)setNumberOfStackFramesToSkipForNotFatalErrors:(NSUInteger)frames { + self.stackFramesToSkip = frames; +} + #pragma mark - FIRSessionsSubscriber - (void)onSessionChanged:(FIRSessionDetails *_Nonnull)session { diff --git a/Crashlytics/Crashlytics/Public/FirebaseCrashlytics/FIRCrashlytics.h b/Crashlytics/Crashlytics/Public/FirebaseCrashlytics/FIRCrashlytics.h index 1ace1bed780..4921414cf7d 100644 --- a/Crashlytics/Crashlytics/Public/FirebaseCrashlytics/FIRCrashlytics.h +++ b/Crashlytics/Crashlytics/Public/FirebaseCrashlytics/FIRCrashlytics.h @@ -243,6 +243,8 @@ NS_SWIFT_NAME(Crashlytics) */ - (void)deleteUnsentReports; +- (void)setNumberOfStackFramesToSkipForNotFatalErrors:(NSUInteger)frames; + @end NS_ASSUME_NONNULL_END diff --git a/Crashlytics/UnitTests/FIRCLSLoggingTests.m b/Crashlytics/UnitTests/FIRCLSLoggingTests.m index a5c72f5c73c..d44a5e3171c 100644 --- a/Crashlytics/UnitTests/FIRCLSLoggingTests.m +++ b/Crashlytics/UnitTests/FIRCLSLoggingTests.m @@ -365,7 +365,7 @@ - (void)testLoggedError { code:-1 userInfo:@{@"key1" : @"value", @"key2" : @"value2"}]; - FIRCLSUserLoggingRecordError(error, @{@"additional" : @"key"}); + FIRCLSUserLoggingRecordError(error, @{@"additional" : @"key"}, 0); NSArray* errors = [self errorAContents]; @@ -405,7 +405,7 @@ - (void)testWritingMaximumNumberOfLoggedErrors { userInfo:@{@"key1" : @"value", @"key2" : @"value2"}]; for (size_t i = 0; i < _firclsContext.readonly->logging.errorStorage.maxEntries; ++i) { - FIRCLSUserLoggingRecordError(error, nil); + FIRCLSUserLoggingRecordError(error, nil, 0); } NSArray* errors = [self errorAContents]; @@ -414,7 +414,7 @@ - (void)testWritingMaximumNumberOfLoggedErrors { // at this point, if we log one more, we should expect a roll over to the next file - FIRCLSUserLoggingRecordError(error, nil); + FIRCLSUserLoggingRecordError(error, nil, 0); XCTAssertEqual([[self errorAContents] count], 8, @""); XCTAssertEqual([[self errorBContents] count], 1, @""); @@ -422,7 +422,7 @@ - (void)testWritingMaximumNumberOfLoggedErrors { // and our next entry should continue into the B file - FIRCLSUserLoggingRecordError(error, nil); + FIRCLSUserLoggingRecordError(error, nil, 0); XCTAssertEqual([[self errorAContents] count], 8, @""); XCTAssertEqual([[self errorBContents] count], 2, @""); @@ -432,7 +432,7 @@ - (void)testWritingMaximumNumberOfLoggedErrors { - (void)testLoggedErrorWithNullsInAdditionalInfo { NSError* error = [NSError errorWithDomain:@"Domain" code:-1 userInfo:nil]; - FIRCLSUserLoggingRecordError(error, @{@"null-key" : [NSNull null]}); + FIRCLSUserLoggingRecordError(error, @{@"null-key" : [NSNull null]}, 0); NSArray* errors = [self errorAContents]; @@ -455,4 +455,25 @@ - (void)testLoggedErrorWithNullsInAdditionalInfo { XCTAssertEqualObjects(additionalEntries[0], entryOne, @""); } +- (void)testSkippingFramesInStackTrace { + NSError* error = [NSError errorWithDomain:@"Domain" code:-1 userInfo:nil]; + FIRCLSUserLoggingRecordError(error, @{}, 0); + + NSUInteger numberOfStacksToSkip = 2; + FIRCLSUserLoggingRecordError(error, @{}, numberOfStacksToSkip); + + NSArray* errors = [self errorAContents]; + + NSArray* firstTrace = [errors[0] valueForKeyPath:@"error.stacktrace"]; + NSArray* secondTrace = [errors[1] valueForKeyPath:@"error.stacktrace"]; + + XCTAssertEqual([secondTrace count], [firstTrace count] - 2, + @"second error should have have 2 frames less"); + XCTAssertEqual(secondTrace[0], firstTrace[2], @"should have same stack traces starting with 2"); + XCTAssertEqual(secondTrace[1], firstTrace[3], @"should have same stack traces starting with 2"); + XCTAssertEqualObjects(secondTrace, + [firstTrace subarrayWithRange:NSMakeRange(2, [secondTrace count])], + @"should have same stack traces with first 2 removed"); +} + @end