Skip to content

Commit 5ea7b5a

Browse files
authored
refactor: Replace calls useSpan with callback to direct span accessor (#4896)
1 parent 2aacc32 commit 5ea7b5a

File tree

9 files changed

+105
-81
lines changed

9 files changed

+105
-81
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
- Log message when setting user before starting the SDK (#4882)
1212
- Add experimental flag to disable swizzling of `NSData` individually (#4859)
13+
- Replace calls of `SentryScope.useSpan` with callback to direct span accessor (#4896)
1314

1415
### Fixes
1516

Sources/Sentry/Public/SentryDefines.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,8 @@ typedef NSNumber *_Nullable (^SentryTracesSamplerCallback)(
157157
* Function pointer for span manipulation.
158158
* @param span The span to be used.
159159
*/
160-
typedef void (^SentrySpanCallback)(id<SentrySpan> _Nullable span);
160+
typedef void (^SentrySpanCallback)(id<SentrySpan> _Nullable span DEPRECATED_MSG_ATTRIBUTE(
161+
"See `SentryScope.useSpan` for reasoning of deprecation."));
161162

162163
/**
163164
* Log level.

Sources/Sentry/Public/SentryScope.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,16 @@ NS_SWIFT_NAME(Scope)
158158
* Mutates the current transaction atomically.
159159
* @param callback the SentrySpanCallback.
160160
*/
161-
- (void)useSpan:(SentrySpanCallback)callback;
161+
- (void)useSpan:(SentrySpanCallback)callback
162+
DEPRECATED_MSG_ATTRIBUTE(
163+
"This method was used to create an atomic block that could be used to mutate the current "
164+
"span. It is not atomic anymore and due to issues with memory safety in `NSBlock` it is "
165+
"now considered unsafe and deprecated. Use `span` instead.");
166+
167+
/**
168+
* Returns the current span.
169+
*/
170+
- (id<SentrySpan> _Nullable)span;
162171

163172
@end
164173

Sources/Sentry/SentryCoreDataTracker.m

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -36,17 +36,20 @@ - (NSArray *)managedObjectContext:(NSManagedObjectContext *)context
3636
error:(NSError **)error
3737
originalImp:(NSArray *(NS_NOESCAPE ^)(NSFetchRequest *, NSError **))original
3838
{
39-
__block id<SentrySpan> fetchSpan;
40-
[SentrySDK.currentHub.scope useSpan:^(id<SentrySpan> _Nullable span) {
41-
fetchSpan = [span startChildWithOperation:SentrySpanOperation.coredataFetchOperation
42-
description:[self descriptionFromRequest:request]];
43-
fetchSpan.origin = SentryTraceOrigin.autoDBCoreData;
44-
}];
39+
id<SentrySpan> _Nullable currentSpan = [SentrySDK.currentHub.scope span];
40+
id<SentrySpan> _Nullable fetchSpan;
41+
if (currentSpan) {
42+
NSString *spanDescription = [self descriptionFromRequest:request];
43+
fetchSpan = [currentSpan startChildWithOperation:SentrySpanOperation.coredataFetchOperation
44+
description:spanDescription];
45+
}
4546

4647
if (fetchSpan) {
48+
fetchSpan.origin = SentryTraceOrigin.autoDBCoreData;
49+
4750
SENTRY_LOG_DEBUG(@"SentryCoreDataTracker automatically started a new span with "
48-
@"description: %@, operation: %@",
49-
fetchSpan.description, fetchSpan.operation);
51+
@"description: %@, operation: %@, origin: %@",
52+
fetchSpan.description, fetchSpan.operation, fetchSpan.origin);
5053
}
5154

5255
NSArray *result = original(request, error);
@@ -70,22 +73,26 @@ - (BOOL)managedObjectContext:(NSManagedObjectContext *)context
7073
originalImp:(BOOL(NS_NOESCAPE ^)(NSError **))original
7174
{
7275

73-
__block id<SentrySpan> saveSpan = nil;
76+
__block id<SentrySpan> _Nullable saveSpan = nil;
7477
if (context.hasChanges) {
7578
__block NSDictionary<NSString *, NSDictionary *> *operations =
7679
[self groupEntitiesOperations:context];
7780

78-
[SentrySDK.currentHub.scope useSpan:^(id<SentrySpan> _Nullable span) {
79-
saveSpan = [span startChildWithOperation:SentrySpanOperation.coredataSaveOperation
80-
description:[self descriptionForOperations:operations
81-
inContext:context]];
82-
saveSpan.origin = SentryTraceOrigin.autoDBCoreData;
83-
}];
81+
id<SentrySpan> _Nullable currentSpan = [SentrySDK.currentHub.scope span];
82+
if (currentSpan) {
83+
NSString *spanDescription = [self descriptionForOperations:operations
84+
inContext:context];
85+
saveSpan =
86+
[currentSpan startChildWithOperation:SentrySpanOperation.coredataSaveOperation
87+
description:spanDescription];
88+
}
8489

8590
if (saveSpan) {
91+
saveSpan.origin = SentryTraceOrigin.autoDBCoreData;
92+
8693
SENTRY_LOG_DEBUG(@"SentryCoreDataTracker automatically started a new span with "
87-
@"description: %@, operation: %@",
88-
saveSpan.description, saveSpan.operation);
94+
@"description: %@, operation: %@, origin: %@",
95+
saveSpan.description, saveSpan.operation, saveSpan.origin);
8996

9097
[saveSpan setDataValue:operations forKey:@"operations"];
9198
} else {

Sources/Sentry/SentryFileIOTracker.m

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -193,25 +193,27 @@ - (BOOL)measureNSFileManagerCreateFileAtPath:(NSString *)path
193193
return nil;
194194
}
195195

196-
__block id<SentrySpan> ioSpan;
197196
NSString *spanDescription = [self transactionDescriptionForFile:path fileSize:size];
198-
[SentrySDK.currentHub.scope useSpan:^(id<SentrySpan> _Nullable span) {
199-
// Keep the logic inside the `useSpan` block to a minimum, as we have noticed memory issues
200-
// See: https://github.com/getsentry/sentry-cocoa/issues/4887
201-
ioSpan = [span startChildWithOperation:operation description:spanDescription];
202-
}];
197+
id<SentrySpan> _Nullable currentSpan = [SentrySDK.currentHub.scope span];
198+
if (currentSpan == NULL) {
199+
SENTRY_LOG_DEBUG(@"No transaction bound to scope. Won't track file IO operation.");
200+
return nil;
201+
}
203202

203+
id<SentrySpan> _Nullable ioSpan = [currentSpan startChildWithOperation:operation
204+
description:spanDescription];
204205
if (ioSpan == nil) {
205206
SENTRY_LOG_DEBUG(@"No transaction bound to scope. Won't track file IO operation.");
206207
return nil;
207208
}
208209

209-
SENTRY_LOG_DEBUG(@"Automatically started a new span with description: %@, operation: %@",
210-
ioSpan.description, operation);
211-
212210
ioSpan.origin = origin;
213211
[ioSpan setDataValue:path forKey:SentrySpanDataKey.filePath];
214212

213+
SENTRY_LOG_DEBUG(
214+
@"Automatically started a new span with description: %@, operation: %@, origin: %@",
215+
ioSpan.description, operation, origin);
216+
215217
[self mainThreadExtraInfo:ioSpan];
216218

217219
return ioSpan;

Sources/Sentry/SentryNetworkTracker.m

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -174,37 +174,36 @@ - (void)urlSessionTaskResume:(NSURLSessionTask *)sessionTask
174174

175175
UrlSanitized *safeUrl = [[UrlSanitized alloc] initWithURL:url];
176176
@synchronized(sessionTask) {
177-
__block id<SentrySpan> span;
178-
__block id<SentrySpan> netSpan;
177+
__block id<SentrySpan> _Nullable span;
178+
__block id<SentrySpan> _Nullable netSpan;
179179
netSpan = objc_getAssociatedObject(sessionTask, &SENTRY_NETWORK_REQUEST_TRACKER_SPAN);
180180

181181
// The task already has a span. Nothing to do.
182182
if (netSpan != nil) {
183183
return;
184184
}
185185

186-
[SentrySDK.currentHub.scope useSpan:^(id<SentrySpan> _Nullable innerSpan) {
187-
if (innerSpan != nil) {
188-
span = innerSpan;
189-
netSpan = [span startChildWithOperation:SentrySpanOperation.networkRequestOperation
190-
description:[NSString stringWithFormat:@"%@ %@",
191-
sessionTask.currentRequest.HTTPMethod,
192-
safeUrl.sanitizedUrl]];
193-
netSpan.origin = SentryTraceOrigin.autoHttpNSURLSession;
194-
195-
[netSpan setDataValue:sessionTask.currentRequest.HTTPMethod
196-
forKey:@"http.request.method"];
197-
[netSpan setDataValue:safeUrl.sanitizedUrl forKey:@"url"];
198-
[netSpan setDataValue:@"fetch" forKey:@"type"];
199-
200-
if (safeUrl.queryItems && safeUrl.queryItems.count > 0) {
201-
[netSpan setDataValue:safeUrl.query forKey:@"http.query"];
202-
}
203-
if (safeUrl.fragment != nil) {
204-
[netSpan setDataValue:safeUrl.fragment forKey:@"http.fragment"];
205-
}
186+
id<SentrySpan> _Nullable currentSpan = [SentrySDK.currentHub.scope span];
187+
if (currentSpan != nil) {
188+
span = currentSpan;
189+
netSpan = [span startChildWithOperation:SentrySpanOperation.networkRequestOperation
190+
description:[NSString stringWithFormat:@"%@ %@",
191+
sessionTask.currentRequest.HTTPMethod,
192+
safeUrl.sanitizedUrl]];
193+
netSpan.origin = SentryTraceOrigin.autoHttpNSURLSession;
194+
195+
[netSpan setDataValue:sessionTask.currentRequest.HTTPMethod
196+
forKey:@"http.request.method"];
197+
[netSpan setDataValue:safeUrl.sanitizedUrl forKey:@"url"];
198+
[netSpan setDataValue:@"fetch" forKey:@"type"];
199+
200+
if (safeUrl.queryItems && safeUrl.queryItems.count > 0) {
201+
[netSpan setDataValue:safeUrl.query forKey:@"http.query"];
206202
}
207-
}];
203+
if (safeUrl.fragment != nil) {
204+
[netSpan setDataValue:safeUrl.fragment forKey:@"http.fragment"];
205+
}
206+
}
208207

209208
// We only create a span if there is a transaction in the scope,
210209
// otherwise we have nothing else to do here.

Sources/Sentry/SentryTracer.m

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -635,11 +635,10 @@ - (BOOL)finishTracer:(SentrySpanStatus)unfinishedSpansFinishStatus shouldCleanUp
635635
}
636636

637637
if (shouldCleanUp) {
638-
[_hub.scope useSpan:^(id<SentrySpan> _Nullable span) {
639-
if (span == self) {
640-
[self->_hub.scope setSpan:nil];
641-
}
642-
}];
638+
id<SentrySpan> _Nullable currentSpan = [_hub.scope span];
639+
if (currentSpan == self) {
640+
[_hub.scope setSpan:nil];
641+
}
643642
}
644643

645644
if (self.configuration.finishMustBeCalled && !self.wasFinishCalled) {

Sources/Sentry/SentryUIEventTrackerTransactionMode.m

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -67,30 +67,31 @@ - (void)handleUIEvent:(NSString *)action
6767
operation:operation
6868
origin:SentryTraceOrigin.autoUiEventTracker];
6969

70-
__block SentryTracer *transaction;
71-
[SentrySDK.currentHub.scope useSpan:^(id<SentrySpan> _Nullable span) {
72-
BOOL ongoingScreenLoadTransaction
73-
= span != nil && [span.operation isEqualToString:SentrySpanOperation.uiLoad];
74-
BOOL ongoingManualTransaction = span != nil
75-
&& ![span.operation isEqualToString:SentrySpanOperation.uiLoad]
76-
&& ![span.operation containsString:SentrySpanOperation.uiAction];
77-
78-
BOOL bindToScope = !ongoingScreenLoadTransaction && !ongoingManualTransaction;
79-
80-
transaction = [SentrySDK.currentHub
81-
startTransactionWithContext:context
82-
bindToScope:bindToScope
83-
customSamplingContext:@{}
84-
configuration:[SentryTracerConfiguration configurationWithBlock:^(
85-
SentryTracerConfiguration *config) {
86-
config.idleTimeout = self.idleTimeout;
87-
config.waitForChildren = YES;
88-
}]];
89-
90-
SENTRY_LOG_DEBUG(@"Automatically started a new transaction with name: "
91-
@"%@, bindToScope: %@",
92-
action, bindToScope ? @"YES" : @"NO");
93-
}];
70+
id<SentrySpan> _Nullable currentSpan = [SentrySDK.currentHub.scope span];
71+
BOOL ongoingScreenLoadTransaction = false;
72+
BOOL ongoingManualTransaction = false;
73+
if (currentSpan != nil) {
74+
ongoingScreenLoadTransaction =
75+
[currentSpan.operation isEqualToString:SentrySpanOperation.uiLoad];
76+
ongoingManualTransaction
77+
= ![currentSpan.operation isEqualToString:SentrySpanOperation.uiLoad]
78+
&& ![currentSpan.operation containsString:SentrySpanOperation.uiAction];
79+
}
80+
BOOL bindToScope = !ongoingScreenLoadTransaction && !ongoingManualTransaction;
81+
82+
__block SentryTracer *transaction = [SentrySDK.currentHub
83+
startTransactionWithContext:context
84+
bindToScope:bindToScope
85+
customSamplingContext:@{}
86+
configuration:[SentryTracerConfiguration configurationWithBlock:^(
87+
SentryTracerConfiguration *config) {
88+
config.idleTimeout = self.idleTimeout;
89+
config.waitForChildren = YES;
90+
}]];
91+
92+
SENTRY_LOG_DEBUG(@"Automatically started a new transaction with name: "
93+
@"%@, bindToScope: %@",
94+
action, bindToScope ? @"YES" : @"NO");
9495

9596
if (accessibilityIdentifier) {
9697
[transaction setTagValue:accessibilityIdentifier forKey:@"accessibilityIdentifier"];

Tests/SentryTests/SentryScopeSwiftTests.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,14 +271,16 @@ class SentryScopeSwiftTests: XCTestCase {
271271

272272
XCTAssertEqual(event.environment, actual?.environment)
273273
}
274-
274+
275+
@available(*, deprecated, message: "The test is marked as deprecated to silence the deprecation warning of useSpan")
275276
func testUseSpan() {
276277
fixture.scope.span = fixture.transaction
277278
fixture.scope.useSpan { (span) in
278279
XCTAssert(span === self.fixture.transaction)
279280
}
280281
}
281282

283+
@available(*, deprecated, message: "The test is marked as deprecated to silence the deprecation warning of useSpan")
282284
func testUseSpanLock_DoesNotBlock_WithBlockingCallback() {
283285
let scope = fixture.scope
284286
scope.span = fixture.transaction
@@ -311,6 +313,7 @@ class SentryScopeSwiftTests: XCTestCase {
311313
wait(for: [expect], timeout: 0.1)
312314
}
313315

316+
@available(*, deprecated, message: "The test is marked as deprecated to silence the deprecation warning of useSpan")
314317
func testUseSpanLock_IsReentrant() {
315318
let expect = expectation(description: "finish on time")
316319
let scope = fixture.scope
@@ -324,6 +327,7 @@ class SentryScopeSwiftTests: XCTestCase {
324327
wait(for: [expect], timeout: 0.1)
325328
}
326329

330+
@available(*, deprecated, message: "The test is marked as deprecated to silence the deprecation warning of useSpan")
327331
func testSpan_FromMultipleThreads() {
328332
let scope = fixture.scope
329333

@@ -358,6 +362,7 @@ class SentryScopeSwiftTests: XCTestCase {
358362
XCTAssertNil(serialized["breadcrumbs"])
359363
}
360364

365+
@available(*, deprecated, message: "The test is marked as deprecated to silence the deprecation warning of useSpan")
361366
func testUseSpanForClear() {
362367
fixture.scope.span = fixture.transaction
363368
fixture.scope.useSpan { (_) in

0 commit comments

Comments
 (0)