diff --git a/Sentry.xcodeproj/project.pbxproj b/Sentry.xcodeproj/project.pbxproj index 9963785277..ca19980c21 100644 --- a/Sentry.xcodeproj/project.pbxproj +++ b/Sentry.xcodeproj/project.pbxproj @@ -811,6 +811,8 @@ A8F17B2E2901765900990B25 /* SentryRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = A8F17B2D2901765900990B25 /* SentryRequest.m */; }; A8F17B342902870300990B25 /* SentryHttpStatusCodeRange.m in Sources */ = {isa = PBXBuildFile; fileRef = A8F17B332902870300990B25 /* SentryHttpStatusCodeRange.m */; }; D42E48572D48DF1600D251BC /* SentryBuildAppStartSpansTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D42E48562D48DF1600D251BC /* SentryBuildAppStartSpansTests.swift */; }; + D43647EF2D5CF9E3001468E0 /* SentrySpanKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = D43647EE2D5CF9DC001468E0 /* SentrySpanKey.swift */; }; + D43647F12D5CFB71001468E0 /* SentrySpanKeyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D43647F02D5CFB71001468E0 /* SentrySpanKeyTests.swift */; }; D48724DB2D352597005DE483 /* SentryTraceOrigin.swift in Sources */ = {isa = PBXBuildFile; fileRef = D48724DA2D352591005DE483 /* SentryTraceOrigin.swift */; }; D48724DD2D354939005DE483 /* SentrySpanOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D48724DC2D354934005DE483 /* SentrySpanOperation.swift */; }; D48724E02D3549CA005DE483 /* SentrySpanOperationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D48724DF2D3549C6005DE483 /* SentrySpanOperationTests.swift */; }; @@ -1949,6 +1951,8 @@ D41909942D490006002B83D0 /* SentryNSDictionarySanitize+Tests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "SentryNSDictionarySanitize+Tests.m"; sourceTree = ""; }; D42E48562D48DF1600D251BC /* SentryBuildAppStartSpansTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryBuildAppStartSpansTests.swift; sourceTree = ""; }; D42E48582D48FC8F00D251BC /* SentryNSDictionarySanitizeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryNSDictionarySanitizeTests.swift; sourceTree = ""; }; + D43647EE2D5CF9DC001468E0 /* SentrySpanKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentrySpanKey.swift; sourceTree = ""; }; + D43647F02D5CFB71001468E0 /* SentrySpanKeyTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SentrySpanKeyTests.swift; sourceTree = ""; }; D48724DA2D352591005DE483 /* SentryTraceOrigin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryTraceOrigin.swift; sourceTree = ""; }; D48724DC2D354934005DE483 /* SentrySpanOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentrySpanOperation.swift; sourceTree = ""; }; D48724DF2D3549C6005DE483 /* SentrySpanOperationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentrySpanOperationTests.swift; sourceTree = ""; }; @@ -3785,6 +3789,7 @@ children = ( D48724DA2D352591005DE483 /* SentryTraceOrigin.swift */, D48724DC2D354934005DE483 /* SentrySpanOperation.swift */, + D43647EE2D5CF9DC001468E0 /* SentrySpanKey.swift */, ); path = Transactions; sourceTree = ""; @@ -3794,6 +3799,7 @@ children = ( D48724E12D354D16005DE483 /* SentryTraceOriginTests.swift */, D48724DF2D3549C6005DE483 /* SentrySpanOperationTests.swift */, + D43647F02D5CFB71001468E0 /* SentrySpanKeyTests.swift */, ); path = Transactions; sourceTree = ""; @@ -4957,6 +4963,7 @@ D82859432C3E753C009A28AA /* SentrySessionReplaySyncC.c in Sources */, D833D57C2D10784800961E7A /* SentryRRWebOptionsEvent.swift in Sources */, 84A8891D28DBD28900C51DFD /* SentryDevice.mm in Sources */, + D43647EF2D5CF9E3001468E0 /* SentrySpanKey.swift in Sources */, 7B56D73324616D9500B842DA /* SentryConcurrentRateLimitsDictionary.m in Sources */, 8ECC674825C23A20000E2BF6 /* SentryTransaction.m in Sources */, 0A80E433291017C300095219 /* SentryWatchdogTerminationScopeObserver.m in Sources */, @@ -5392,6 +5399,7 @@ 7BF9EF7A2722B58900B5BBEF /* SentrySubClassFinderTests.swift in Sources */, D48724E02D3549CA005DE483 /* SentrySpanOperationTests.swift in Sources */, 7B59398224AB47650003AAD2 /* SentrySessionTrackerTests.swift in Sources */, + D43647F12D5CFB71001468E0 /* SentrySpanKeyTests.swift in Sources */, 7B05A61824A4D14A00EF211D /* SentrySessionGeneratorTests.swift in Sources */, D8CB742B294B1DD000A5F964 /* SentryUIApplicationTests.swift in Sources */, 63FE720920DA66EC00CDBAE8 /* XCTestCase+SentryCrash.m in Sources */, diff --git a/Sources/Sentry/SentryFileIOTracker.m b/Sources/Sentry/SentryFileIOTracker.m index 1c6d412e5e..1cb5cf12d4 100644 --- a/Sources/Sentry/SentryFileIOTracker.m +++ b/Sources/Sentry/SentryFileIOTracker.m @@ -59,9 +59,10 @@ - (void)disable - (BOOL)measureNSData:(NSData *)data writeToFile:(NSString *)path atomically:(BOOL)useAuxiliaryFile + origin:(NSString *)origin method:(BOOL (^)(NSString *, BOOL))method { - id span = [self startTrackingWritingNSData:data filePath:path]; + id span = [self startTrackingWritingNSData:data filePath:path origin:origin]; BOOL result = method(path, useAuxiliaryFile); @@ -74,10 +75,11 @@ - (BOOL)measureNSData:(NSData *)data - (BOOL)measureNSData:(NSData *)data writeToFile:(NSString *)path options:(NSDataWritingOptions)writeOptionsMask + origin:(NSString *)origin error:(NSError **)error method:(BOOL (^)(NSString *, NSDataWritingOptions, NSError **))method { - id span = [self startTrackingWritingNSData:data filePath:path]; + id span = [self startTrackingWritingNSData:data filePath:path origin:origin]; BOOL result = method(path, writeOptionsMask, error); @@ -88,9 +90,13 @@ - (BOOL)measureNSData:(NSData *)data return result; } -- (NSData *)measureNSDataFromFile:(NSString *)path method:(NSData * (^)(NSString *))method +- (NSData *)measureNSDataFromFile:(NSString *)path + origin:(NSString *)origin + method:(NSData * (^)(NSString *))method { - id span = [self startTrackingReadingFilePath:path]; + id span = [self startTrackingReadingFilePath:path + origin:origin + operation:SentrySpanOperation.fileRead]; NSData *result = method(path); @@ -104,10 +110,13 @@ - (NSData *)measureNSDataFromFile:(NSString *)path method:(NSData * (^)(NSString - (NSData *)measureNSDataFromFile:(NSString *)path options:(NSDataReadingOptions)readOptionsMask + origin:(NSString *)origin error:(NSError **)error method:(NSData * (^)(NSString *, NSDataReadingOptions, NSError **))method { - id span = [self startTrackingReadingFilePath:path]; + id span = [self startTrackingReadingFilePath:path + origin:origin + operation:SentrySpanOperation.fileRead]; NSData *result = method(path, readOptionsMask, error); @@ -121,6 +130,7 @@ - (NSData *)measureNSDataFromFile:(NSString *)path - (NSData *)measureNSDataFromURL:(NSURL *)url options:(NSDataReadingOptions)readOptionsMask + origin:(NSString *)origin error:(NSError **)error method:(NSData * (^)(NSURL *, NSDataReadingOptions, NSError **))method { @@ -131,7 +141,9 @@ - (NSData *)measureNSDataFromURL:(NSURL *)url if (![url.scheme isEqualToString:NSURLFileScheme]) return method(url, readOptionsMask, error); - id span = [self startTrackingReadingFilePath:url.path]; + id span = [self startTrackingReadingFilePath:url.path + origin:origin + operation:SentrySpanOperation.fileRead]; NSData *result = method(url, readOptionsMask, error); @@ -146,11 +158,12 @@ - (NSData *)measureNSDataFromURL:(NSURL *)url - (BOOL)measureNSFileManagerCreateFileAtPath:(NSString *)path data:(NSData *)data attributes:(NSDictionary *)attributes + origin:(NSString *)origin method: (BOOL (^)(NSString *_Nonnull, NSData *_Nonnull, NSDictionary *_Nonnull))method { - id span = [self startTrackingWritingNSData:data filePath:path]; + id span = [self startTrackingWritingNSData:data filePath:path origin:origin]; BOOL result = method(path, data, attributes); @@ -161,6 +174,7 @@ - (BOOL)measureNSFileManagerCreateFileAtPath:(NSString *)path } - (nullable id)spanForPath:(NSString *)path + origin:(NSString *)origin operation:(NSString *)operation size:(NSUInteger)size { @@ -179,7 +193,7 @@ - (BOOL)measureNSFileManagerCreateFileAtPath:(NSString *)path ioSpan = [span startChildWithOperation:operation description:[self transactionDescriptionForFile:path fileSize:size]]; - ioSpan.origin = SentryTraceOrigin.autoNSData; + ioSpan.origin = origin; }]; if (ioSpan == nil) { @@ -187,11 +201,10 @@ - (BOOL)measureNSFileManagerCreateFileAtPath:(NSString *)path return nil; } - SENTRY_LOG_DEBUG( - @"SentryNSDataTracker automatically started a new span with description: %@, operation: %@", + SENTRY_LOG_DEBUG(@"Automatically started a new span with description: %@, operation: %@", ioSpan.description, operation); - [ioSpan setDataValue:path forKey:@"file.path"]; + [ioSpan setDataValue:path forKey:SentrySpanKey.filePath]; [self mainThreadExtraInfo:ioSpan]; @@ -228,12 +241,19 @@ - (void)mainThreadExtraInfo:(id)span } } -- (nullable id)startTrackingWritingNSData:(NSData *)data filePath:(NSString *)path +- (nullable id)startTrackingWritingNSData:(NSData *)data + filePath:(NSString *)path + origin:(NSString *)origin { - return [self spanForPath:path operation:SentrySpanOperation.fileWrite size:data.length]; + return [self spanForPath:path + origin:origin + operation:SentrySpanOperation.fileWrite + size:data.length]; } - (nullable id)startTrackingReadingFilePath:(NSString *)path + origin:(NSString *)origin + operation:(NSString *)operation { // Some iOS versions nest constructors calls. This counter help us avoid create more than one // span for the same operation. @@ -245,7 +265,7 @@ - (void)mainThreadExtraInfo:(id)span if (count) return nil; - return [self spanForPath:path operation:SentrySpanOperation.fileRead size:0]; + return [self spanForPath:path origin:origin operation:operation size:0]; } - (void)endTrackingFile @@ -266,10 +286,11 @@ - (void)endTrackingFile - (void)finishTrackingNSData:(NSData *)data span:(id)span { - [span setDataValue:[NSNumber numberWithUnsignedInteger:data.length] forKey:@"file.size"]; + [span setDataValue:[NSNumber numberWithUnsignedInteger:data.length] + forKey:SentrySpanKey.fileSize]; [span finish]; - SENTRY_LOG_DEBUG(@"SentryNSDataTracker automatically finished span %@", span.description); + SENTRY_LOG_DEBUG(@"Automatically finished span %@", span.description); } - (BOOL)ignoreFile:(NSString *)path diff --git a/Sources/Sentry/SentryNSDataSwizzling.m b/Sources/Sentry/SentryNSDataSwizzling.m index c3b7a52ed8..3ec1b0a83b 100644 --- a/Sources/Sentry/SentryNSDataSwizzling.m +++ b/Sources/Sentry/SentryNSDataSwizzling.m @@ -45,6 +45,7 @@ + (void)swizzle measureNSData:self writeToFile:path atomically:useAuxiliaryFile + origin:SentryTraceOrigin.autoNSData method:^BOOL(NSString *_Nonnull filePath, BOOL isAtomically) { return SentrySWCallOriginal(filePath, isAtomically); }]; @@ -60,6 +61,7 @@ + (void)swizzle measureNSData:self writeToFile:path options:writeOptionsMask + origin:SentryTraceOrigin.autoNSData error:error method:^BOOL( NSString *filePath, NSDataWritingOptions options, NSError **outError) { @@ -77,6 +79,7 @@ + (void)swizzle return [SentryNSDataSwizzling.shared.tracker measureNSDataFromFile:path options:options + origin:SentryTraceOrigin.autoNSData error:error method:^NSData *(NSString *filePath, NSDataReadingOptions options, NSError **outError) { @@ -91,6 +94,7 @@ + (void)swizzle SentrySWReturnType(NSData *), SentrySWArguments(NSString * path), SentrySWReplacement({ return [SentryNSDataSwizzling.shared.tracker measureNSDataFromFile:path + origin:SentryTraceOrigin.autoNSData method:^NSData *( NSString *filePath) { return SentrySWCallOriginal(filePath); }]; }), @@ -105,6 +109,7 @@ + (void)swizzle return [SentryNSDataSwizzling.shared.tracker measureNSDataFromURL:url options:options + origin:SentryTraceOrigin.autoNSData error:error method:^NSData *(NSURL *fileUrl, NSDataReadingOptions options, NSError **outError) { diff --git a/Sources/Sentry/SentryNSFileManagerSwizzling.m b/Sources/Sentry/SentryNSFileManagerSwizzling.m index dea214238a..234c27f94b 100644 --- a/Sources/Sentry/SentryNSFileManagerSwizzling.m +++ b/Sources/Sentry/SentryNSFileManagerSwizzling.m @@ -59,6 +59,7 @@ + (void)swizzle measureNSFileManagerCreateFileAtPath:path data:data attributes:attributes + origin:SentryTraceOrigin.autoNSData method:^BOOL(NSString *path, NSData *data, NSDictionary *attributes) { diff --git a/Sources/Sentry/include/SentryFileIOTracker.h b/Sources/Sentry/include/SentryFileIOTracker.h index fd5316bfe7..d45f437122 100644 --- a/Sources/Sentry/include/SentryFileIOTracker.h +++ b/Sources/Sentry/include/SentryFileIOTracker.h @@ -21,6 +21,7 @@ SENTRY_NO_INIT - (BOOL)measureNSData:(NSData *)data writeToFile:(NSString *)path atomically:(BOOL)useAuxiliaryFile + origin:(NSString *)origin method:(BOOL (^)(NSString *, BOOL))method; /** @@ -29,6 +30,7 @@ SENTRY_NO_INIT - (BOOL)measureNSData:(NSData *)data writeToFile:(NSString *)path options:(NSDataWritingOptions)writeOptionsMask + origin:(NSString *)origin error:(NSError **)error method:(BOOL (^)(NSString *, NSDataWritingOptions, NSError **))method; @@ -36,6 +38,7 @@ SENTRY_NO_INIT * Measure NSData 'initWithContentsOfFile:' method. */ - (nullable NSData *)measureNSDataFromFile:(NSString *)path + origin:(NSString *)origin method:(NSData *_Nullable (^)(NSString *))method; /** @@ -43,6 +46,7 @@ SENTRY_NO_INIT */ - (nullable NSData *)measureNSDataFromFile:(NSString *)path options:(NSDataReadingOptions)readOptionsMask + origin:(NSString *)origin error:(NSError **)error method:(NSData *_Nullable (^)( NSString *, NSDataReadingOptions, NSError **))method; @@ -52,6 +56,7 @@ SENTRY_NO_INIT */ - (nullable NSData *)measureNSDataFromURL:(NSURL *)url options:(NSDataReadingOptions)readOptionsMask + origin:(NSString *)origin error:(NSError **)error method:(NSData *_Nullable (^)( NSURL *, NSDataReadingOptions, NSError **))method; @@ -62,6 +67,7 @@ SENTRY_NO_INIT - (BOOL)measureNSFileManagerCreateFileAtPath:(NSString *)path data:(NSData *)data attributes:(NSDictionary *)attributes + origin:(NSString *)origin method:(BOOL (^)(NSString *, NSData *, NSDictionary *))method; diff --git a/Sources/Swift/Transactions/SentrySpanKey.swift b/Sources/Swift/Transactions/SentrySpanKey.swift new file mode 100644 index 0000000000..7535d0d5d2 --- /dev/null +++ b/Sources/Swift/Transactions/SentrySpanKey.swift @@ -0,0 +1,10 @@ +import Foundation + +@objcMembers @objc(SentrySpanKey) +class SentrySpanKey: NSObject { + /// Used to set the number of bytes processed in a file span operation + static let fileSize = "file.size" + + /// Used to set the path of the file in a file span operation + static let filePath = "file.path" +} diff --git a/Sources/Swift/Transactions/SentrySpanOperation.swift b/Sources/Swift/Transactions/SentrySpanOperation.swift index 30ccf342ea..d2c24e6c2f 100644 --- a/Sources/Swift/Transactions/SentrySpanOperation.swift +++ b/Sources/Swift/Transactions/SentrySpanOperation.swift @@ -9,6 +9,9 @@ class SentrySpanOperation: NSObject { static let fileRead = "file.read" static let fileWrite = "file.write" + static let fileCopy = "file.copy" + static let fileRename = "file.rename" + static let fileDelete = "file.delete" static let networkRequestOperation = "http.client" diff --git a/Sources/Swift/Transactions/SentryTraceOrigin.swift b/Sources/Swift/Transactions/SentryTraceOrigin.swift index 34725f51a1..3a8661bdc7 100644 --- a/Sources/Swift/Transactions/SentryTraceOrigin.swift +++ b/Sources/Swift/Transactions/SentryTraceOrigin.swift @@ -11,5 +11,6 @@ class SentryTraceOrigin: NSObject { static let autoUITimeToDisplay = "auto.ui.time_to_display" static let autoUIViewController = "auto.ui.view_controller" static let manual = "manual" + static let manualFileData = "manual.file.data" static let manualUITimeToDisplay = "manual.ui.time_to_display" } diff --git a/Tests/SentryTests/Transactions/SentrySpanKeyTests.swift b/Tests/SentryTests/Transactions/SentrySpanKeyTests.swift new file mode 100644 index 0000000000..4ab1f9487a --- /dev/null +++ b/Tests/SentryTests/Transactions/SentrySpanKeyTests.swift @@ -0,0 +1,12 @@ +@testable import Sentry +import XCTest + +class SentrySpanKeyTests: XCTestCase { + func testFileSize_shouldBeExpectedValue() { + XCTAssertEqual(SentrySpanKey.fileSize, "file.size") + } + + func testFilePath_shouldBeExpectedValue() { + XCTAssertEqual(SentrySpanKey.filePath, "file.path") + } +} diff --git a/Tests/SentryTests/Transactions/SentrySpanOperationTests.swift b/Tests/SentryTests/Transactions/SentrySpanOperationTests.swift index f6e45bb3c4..2832175170 100644 --- a/Tests/SentryTests/Transactions/SentrySpanOperationTests.swift +++ b/Tests/SentryTests/Transactions/SentrySpanOperationTests.swift @@ -22,6 +22,18 @@ class SentrySpanOperationTests: XCTestCase { XCTAssertEqual(SentrySpanOperation.fileWrite, "file.write") } + func testFileCopy_shouldBeExpectedValue() { + XCTAssertEqual(SentrySpanOperation.fileCopy, "file.copy") + } + + func testFileRename_shouldBeExpectedValue() { + XCTAssertEqual(SentrySpanOperation.fileRename, "file.rename") + } + + func testFileDelete_shouldBeExpectedValue() { + XCTAssertEqual(SentrySpanOperation.fileDelete, "file.delete") + } + func testNetworkRequestOperation_shouldBeExpectedValue() { XCTAssertEqual(SentrySpanOperation.networkRequestOperation, "http.client") } diff --git a/Tests/SentryTests/Transactions/SentryTraceOriginTests.swift b/Tests/SentryTests/Transactions/SentryTraceOriginTests.swift index 1d50c02034..57702751bf 100644 --- a/Tests/SentryTests/Transactions/SentryTraceOriginTests.swift +++ b/Tests/SentryTests/Transactions/SentryTraceOriginTests.swift @@ -38,6 +38,10 @@ class SentryTraceOriginTestsTests: XCTestCase { XCTAssertEqual(SentryTraceOrigin.manual, "manual") } + func testManualFileData_shouldBeExpectedValue() { + XCTAssertEqual(SentryTraceOrigin.manualFileData, "manual.file.data") + } + func testManualUITimeToDisplay_shouldBeExpectedValue() { XCTAssertEqual(SentryTraceOrigin.manualUITimeToDisplay, "manual.ui.time_to_display") }