Skip to content

Commit

Permalink
add file io tracker to dependency container
Browse files Browse the repository at this point in the history
  • Loading branch information
philprime committed Jan 13, 2025
1 parent b03c19a commit 1e4c13e
Show file tree
Hide file tree
Showing 11 changed files with 54 additions and 21 deletions.
8 changes: 4 additions & 4 deletions Sentry.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -789,7 +789,7 @@
A8F17B2E2901765900990B25 /* SentryRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = A8F17B2D2901765900990B25 /* SentryRequest.m */; };
A8F17B342902870300990B25 /* SentryHttpStatusCodeRange.m in Sources */ = {isa = PBXBuildFile; fileRef = A8F17B332902870300990B25 /* SentryHttpStatusCodeRange.m */; };
D4252AE32D119D3F00184F6F /* SentryDataWrapperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4252AE22D119D3B00184F6F /* SentryDataWrapperTests.swift */; };
D48724DB2D352597005DE483 /* SentryTraceOrigins.swift in Sources */ = {isa = PBXBuildFile; fileRef = D48724DA2D352591005DE483 /* SentryTraceOrigins.swift */; };
D48724DB2D352597005DE483 /* SentryTraceOrigin.swift in Sources */ = {isa = PBXBuildFile; fileRef = D48724DA2D352591005DE483 /* SentryTraceOrigin.swift */; };
D4AF00212D2E92FD00F5F3D7 /* SentryNSFileManagerSwizzling.m in Sources */ = {isa = PBXBuildFile; fileRef = D4AF00202D2E92FD00F5F3D7 /* SentryNSFileManagerSwizzling.m */; };
D4AF00232D2E931000F5F3D7 /* SentryNSFileManagerSwizzling.h in Headers */ = {isa = PBXBuildFile; fileRef = D4AF00222D2E931000F5F3D7 /* SentryNSFileManagerSwizzling.h */; };
D4AF00252D2E93C400F5F3D7 /* SentryNSFileManagerSwizzlingTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D4AF00242D2E93C400F5F3D7 /* SentryNSFileManagerSwizzlingTests.m */; };
Expand Down Expand Up @@ -1879,7 +1879,7 @@
A8F17B2D2901765900990B25 /* SentryRequest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentryRequest.m; sourceTree = "<group>"; };
A8F17B332902870300990B25 /* SentryHttpStatusCodeRange.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentryHttpStatusCodeRange.m; sourceTree = "<group>"; };
D4252AE22D119D3B00184F6F /* SentryDataWrapperTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryDataWrapperTests.swift; sourceTree = "<group>"; };
D48724DA2D352591005DE483 /* SentryTraceOrigins.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryTraceOrigins.swift; sourceTree = "<group>"; };
D48724DA2D352591005DE483 /* SentryTraceOrigin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryTraceOrigin.swift; sourceTree = "<group>"; };
D4AF00202D2E92FD00F5F3D7 /* SentryNSFileManagerSwizzling.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentryNSFileManagerSwizzling.m; sourceTree = "<group>"; };
D4AF00222D2E931000F5F3D7 /* SentryNSFileManagerSwizzling.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SentryNSFileManagerSwizzling.h; path = include/SentryNSFileManagerSwizzling.h; sourceTree = "<group>"; };
D4AF00242D2E93C400F5F3D7 /* SentryNSFileManagerSwizzlingTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentryNSFileManagerSwizzlingTests.m; sourceTree = "<group>"; };
Expand Down Expand Up @@ -3665,7 +3665,7 @@
D48724D92D35258A005DE483 /* Transactions */ = {
isa = PBXGroup;
children = (
D48724DA2D352591005DE483 /* SentryTraceOrigins.swift */,
D48724DA2D352591005DE483 /* SentryTraceOrigin.swift */,
);
path = Transactions;
sourceTree = "<group>";
Expand Down Expand Up @@ -4910,7 +4910,7 @@
7BC9A20628F41781001E7C4C /* SentryMeasurementUnit.m in Sources */,
63FE71A020DA4C1100CDBAE8 /* SentryCrashInstallation.m in Sources */,
63FE713520DA4C1100CDBAE8 /* SentryCrashMemory.c in Sources */,
D48724DB2D352597005DE483 /* SentryTraceOrigins.swift in Sources */,
D48724DB2D352597005DE483 /* SentryTraceOrigin.swift in Sources */,
63FE714520DA4C1100CDBAE8 /* SentryCrashObjC.c in Sources */,
63FE710520DA4C1000CDBAE8 /* SentryAsyncSafeLog.c in Sources */,
0A2D8D5B289815C0008720F6 /* SentryBaseIntegration.m in Sources */,
Expand Down
16 changes: 16 additions & 0 deletions Sources/Sentry/SentryDependencyContainer.m
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#import "SentryDispatchQueueWrapper.h"
#import "SentryDisplayLinkWrapper.h"
#import "SentryExtraContextProvider.h"
#import "SentryFileIOTracker.h"
#import "SentryFileManager.h"
#import "SentryInternalCDefines.h"
#import "SentryLog.h"
Expand Down Expand Up @@ -186,6 +187,21 @@ - (SentryThreadInspector *)threadInspector SENTRY_DISABLE_THREAD_SANITIZER(
return _threadInspector;
}

- (SentryFileIOTracker *)fileIOTracker SENTRY_DISABLE_THREAD_SANITIZER(
"double-checked lock produce false alarms")
{
if (_fileIOTracker == nil) {
@synchronized(sentryDependencyContainerLock) {
if (_fileIOTracker == nil) {
_fileIOTracker =
[[SentryFileIOTracker alloc] initWithThreadInspector:[self threadInspector]
processInfoWrapper:[self processInfoWrapper]];
}
}
}
return _fileIOTracker;
}

- (SentryDebugImageProvider *)debugImageProvider
{
@synchronized(sentryDependencyContainerLock) {
Expand Down
5 changes: 1 addition & 4 deletions Sources/Sentry/SentryFileIOTracker.m
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,7 @@ @implementation SentryFileIOTracker

+ (instancetype)sharedInstance
{
SentryFileIOTracker *tracker = [[SentryFileIOTracker alloc]
initWithThreadInspector:SentryDependencyContainer.sharedInstance.threadInspector
processInfoWrapper:SentryDependencyContainer.sharedInstance.processInfoWrapper];
return tracker;
return SentryDependencyContainer.sharedInstance.fileIOTracker;
}

- (instancetype)initWithThreadInspector:(SentryThreadInspector *)threadInspector
Expand Down
4 changes: 1 addition & 3 deletions Sources/Sentry/SentryFileIOTrackingIntegration.m
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,7 @@ - (BOOL)installWithOptions:(SentryOptions *)options
return NO;
}

self.tracker = [[SentryFileIOTracker alloc]
initWithThreadInspector:[[SentryThreadInspector alloc] initWithOptions:options]
processInfoWrapper:[SentryDependencyContainer.sharedInstance processInfoWrapper]];
self.tracker = [[SentryDependencyContainer sharedInstance] fileIOTracker];
[self.tracker enable];

[SentryNSDataSwizzling.shared startWithOptions:options tracker:self.tracker];
Expand Down
10 changes: 5 additions & 5 deletions Sources/Sentry/SentryNSDataSwizzling.m
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ + (void)swizzle
measureNSData:self
writeToFile:path
atomically:useAuxiliaryFile
origin:SentryTraceOriginAutoNSData
origin:[SentryTraceOrigin autoNSData]
method:^BOOL(NSString *_Nonnull filePath, BOOL isAtomically) {
return SentrySWCallOriginal(filePath, isAtomically);
}];
Expand All @@ -62,7 +62,7 @@ + (void)swizzle
measureNSData:self
writeToFile:path
options:writeOptionsMask
origin:SentryTraceOriginAutoNSData
origin:[SentryTraceOrigin autoNSData]
error:error
method:^BOOL(
NSString *filePath, NSDataWritingOptions options, NSError **outError) {
Expand All @@ -80,7 +80,7 @@ + (void)swizzle
return [SentryNSDataSwizzling.shared.tracker
measureNSDataFromFile:path
options:options
origin:SentryTraceOriginAutoNSData
origin:[SentryTraceOrigin autoNSData]
error:error
method:^NSData *(NSString *filePath, NSDataReadingOptions options,
NSError **outError) {
Expand All @@ -95,7 +95,7 @@ + (void)swizzle
SentrySWReturnType(NSData *), SentrySWArguments(NSString * path), SentrySWReplacement({
return [SentryNSDataSwizzling.shared.tracker
measureNSDataFromFile:path
origin:SentryTraceOriginAutoNSData
origin:[SentryTraceOrigin autoNSData]
method:^NSData *(
NSString *filePath) { return SentrySWCallOriginal(filePath); }];
}),
Expand All @@ -110,7 +110,7 @@ + (void)swizzle
return [SentryNSDataSwizzling.shared.tracker
measureNSDataFromURL:url
options:options
origin:SentryTraceOriginAutoNSData
origin:[SentryTraceOrigin autoNSData]
error:error
method:^NSData *(NSURL *fileUrl, NSDataReadingOptions options,
NSError **outError) {
Expand Down
2 changes: 1 addition & 1 deletion Sources/Sentry/SentryNSFileManagerSwizzling.m
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ + (void)swizzle
measureNSFileManagerCreateFileAtPath:path
data:data
attributes:attributes
origin:SentryTraceOriginAutoNSData
origin:[SentryTraceOrigin autoNSData]
method:^BOOL(NSString *path, NSData *data,
NSDictionary<NSFileAttributeKey, id>
*attributes) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
@class SentrySystemWrapper;
@class SentryThreadWrapper;
@class SentryThreadInspector;
@class SentryFileIOTracker;
@protocol SentryRandom;
@protocol SentryCurrentDateProvider;
@protocol SentryRateLimits;
Expand Down Expand Up @@ -77,6 +78,7 @@ SENTRY_NO_INIT
@property (nonatomic, strong) SentrySysctl *sysctlWrapper;
@property (nonatomic, strong) SentryThreadInspector *threadInspector;
@property (nonatomic, strong) id<SentryRateLimits> rateLimits;
@property (nonatomic, strong) SentryFileIOTracker *fileIOTracker;

#if SENTRY_UIKIT_AVAILABLE
@property (nonatomic, strong) SentryFramesTracker *framesTracker;
Expand Down
7 changes: 7 additions & 0 deletions Sources/Sentry/include/SentryFileIOTracker.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@ NS_ASSUME_NONNULL_BEGIN
@interface SentryFileIOTracker : NSObject
SENTRY_NO_INIT

/**
* Convenience accessor to the shared instance of the tracker in the dependency container.
*
* @note Can be used from Swift without import the entire dependency container.
*
* @return The shared instance of the tracker.
*/
+ (instancetype)sharedInstance;

- (instancetype)initWithThreadInspector:(SentryThreadInspector *)threadInspector
Expand Down
1 change: 0 additions & 1 deletion Sources/Sentry/include/SentryTraceOrigins.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ static NSString *const SentryTraceOriginUIEventTracker = @"auto.ui.event_tracker

static NSString *const SentryTraceOriginAutoAppStart = @"auto.app.start";
static NSString *const SentryTraceOriginAutoAppStartProfile = @"auto.app.start.profile";
static NSString *const SentryTraceOriginAutoNSData = @"auto.file.ns_data";
static NSString *const SentryTraceOriginAutoDBCoreData = @"auto.db.core_data";
static NSString *const SentryTraceOriginAutoHttpNSURLSession = @"auto.http.ns_url_session";
static NSString *const SentryTraceOriginAutoUIViewController = @"auto.ui.view_controller";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// This file is the Swift addition for `SentryTraceOrigins.h` in the `Sentry` module.

@objcMembers
public class SentryTraceOrigin {
public class SentryTraceOrigin: NSObject {
static let autoNSData = "auto.file.ns_data"
static let manualData = "manual.file.data"
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@ class SentryFileIOTrackingIntegrationTests: XCTestCase {
fileURL = fileDirectory.appendingPathComponent("TestFile")
filePath = fileURL?.path
}

func assertDataWritten(toUrl url: URL, file: StaticString = #file, line: UInt = #line) {
guard let data = try? Data(contentsOf: url) else {
XCTFail("Could not load written resource file", file: file, line: line)
return

Check warning on line 34 in Tests/SentryTests/Integrations/Performance/IO/SentryFileIOTrackingIntegrationTests.swift

View check run for this annotation

Codecov / codecov/patch

Tests/SentryTests/Integrations/Performance/IO/SentryFileIOTrackingIntegrationTests.swift#L33-L34

Added lines #L33 - L34 were not covered by tests
}
XCTAssertEqual(self.data, data, file: file, line: line)
}
}

private var fixture: Fixture!
Expand Down Expand Up @@ -111,15 +119,19 @@ class SentryFileIOTrackingIntegrationTests: XCTestCase {
}

func testDataExtension_Writing_Tracking() throws {
// -- Arrange --
// Automatic tracking of Swift.Data is not available starting with iOS 18, macOS 15, tvOS 15.
// Therefore, the extension method is only tested with these OS versions.
guard #available(iOS 18, macOS 15, tvOS 18, *) else {
throw XCTSkip("Data+SentryTracing is not tested on this OS version")
}
SentrySDK.start(options: fixture.getOptions())

// -- Act & Assert --
assertSpans(1, "file.write") {
try? fixture.data.writeWithSentryTracing(to: fixture.fileURL)
}
fixture.assertDataWritten(toUrl: fixture.fileURL)
}

func testDataExtension_WritingWithOption_Tracking() throws {
Expand All @@ -133,6 +145,7 @@ class SentryFileIOTrackingIntegrationTests: XCTestCase {
try? fixture.data
.writeWithSentryTracing(to: fixture.fileURL, options: .atomic)
}
fixture.assertDataWritten(toUrl: fixture.fileURL)
}

func test_ReadingTrackingDisabled_forIOOption() {
Expand Down Expand Up @@ -329,9 +342,9 @@ class SentryFileIOTrackingIntegrationTests: XCTestCase {
return
}

XCTAssertEqual(children.count, spansCount, file: file, line: line)
XCTAssertEqual(children.count, spansCount, "Actual span count is not equal to expected count", file: file, line: line)
if let first = children.first {
XCTAssertEqual(first.operation, operation, file: file, line: line)
XCTAssertEqual(first.operation, operation, "Operation for span is not equal to expected operation", file: file, line: line)
}
}
}

0 comments on commit 1e4c13e

Please sign in to comment.