Skip to content

Commit 14014ce

Browse files
author
Robert Bartoszewski
committed
Merge branch 'next' into robert/plat-15338_sync_v1_into_v2
# Conflicts: # BugsnagPerformance.xcodeproj/project.pbxproj # Sources/BugsnagPerformance/Private/BugsnagPerformanceImpl.mm # Sources/BugsnagPerformance/Private/Instrumentation/NetworkInstrumentation.mm # Sources/BugsnagPerformance/Private/Instrumentation/ViewLoadInstrumentation.mm # Sources/BugsnagPerformance/Private/Tracer.mm # features/default/manual_spans.feature # features/default/network.feature
2 parents b848220 + ac8d49d commit 14014ce

File tree

20 files changed

+293
-21
lines changed

20 files changed

+293
-21
lines changed

.github/workflows/pull_request.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@ jobs:
1010
runs-on: macos-latest
1111
steps:
1212
- name: Checkout target branch
13-
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
13+
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
1414
with:
1515
ref: ${{ github.base_ref }}
1616
- name: Build
1717
run: xcodebuild -scheme BugsnagPerformance-iOS -destination generic/platform=iOS -configuration Release -quiet -derivedDataPath $PWD/DerivedData.old VALID_ARCHS=arm64
1818
- name: Checkout pull request merge branch
19-
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
19+
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
2020
with:
2121
clean: false
2222
fetch-depth: 100

.github/workflows/scorecard.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ jobs:
3232

3333
steps:
3434
- name: "Checkout code"
35-
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
35+
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
3636
with:
3737
persist-credentials: false
3838

@@ -68,6 +68,6 @@ jobs:
6868
# Upload the results to GitHub's code scanning dashboard (optional).
6969
# Commenting out will disable upload of results to your repo's Code Scanning dashboard
7070
- name: "Upload to code-scanning"
71-
uses: github/codeql-action/upload-sarif@fe4161a26a8629af62121b670040955b330f9af2 # v4.31.6
71+
uses: github/codeql-action/upload-sarif@cf1bb45a277cb3c205638b2cd5c984db1c46a412 # v4.31.7
7272
with:
7373
sarif_file: results.sarif

BugsnagPerformance.xcodeproj/project.pbxproj

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,8 @@
236236
96F129312DCD325E00A6FB2B /* BugsnagPerformanceSpanTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 96F129302DCD325E00A6FB2B /* BugsnagPerformanceSpanTests.mm */; };
237237
96F417152E3B8E7000EABD8E /* BugsnagPerformanceNamedSpans.h in Headers */ = {isa = PBXBuildFile; fileRef = 96F417122E3B8E7000EABD8E /* BugsnagPerformanceNamedSpans.h */; };
238238
96F417162E3B8E7000EABD8E /* BugsnagPerformanceNamedSpans.docc in Sources */ = {isa = PBXBuildFile; fileRef = 96F417132E3B8E7000EABD8E /* BugsnagPerformanceNamedSpans.docc */; };
239+
96F9010F2EE817620026F5B9 /* NSTimer+MainThread.h in Headers */ = {isa = PBXBuildFile; fileRef = 96F9010E2EE8175B0026F5B9 /* NSTimer+MainThread.h */; };
240+
96F901112EE817700026F5B9 /* NSTimer+MainThread.m in Sources */ = {isa = PBXBuildFile; fileRef = 96F901102EE817690026F5B9 /* NSTimer+MainThread.m */; };
239241
CB04969729150D860097E526 /* OtlpPackage.h in Headers */ = {isa = PBXBuildFile; fileRef = CB04969529150D860097E526 /* OtlpPackage.h */; };
240242
CB04969829150D860097E526 /* OtlpPackage.mm in Sources */ = {isa = PBXBuildFile; fileRef = CB04969629150D860097E526 /* OtlpPackage.mm */; };
241243
CB04969B2915194E0097E526 /* OtlpUploader.h in Headers */ = {isa = PBXBuildFile; fileRef = CB0496992915194E0097E526 /* OtlpUploader.h */; };
@@ -660,6 +662,8 @@
660662
96F129302DCD325E00A6FB2B /* BugsnagPerformanceSpanTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = BugsnagPerformanceSpanTests.mm; sourceTree = "<group>"; };
661663
96F417122E3B8E7000EABD8E /* BugsnagPerformanceNamedSpans.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BugsnagPerformanceNamedSpans.h; sourceTree = "<group>"; };
662664
96F417132E3B8E7000EABD8E /* BugsnagPerformanceNamedSpans.docc */ = {isa = PBXFileReference; lastKnownFileType = folder.documentationcatalog; path = BugsnagPerformanceNamedSpans.docc; sourceTree = "<group>"; };
665+
96F9010E2EE8175B0026F5B9 /* NSTimer+MainThread.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSTimer+MainThread.h"; sourceTree = "<group>"; };
666+
96F901102EE817690026F5B9 /* NSTimer+MainThread.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = "NSTimer+MainThread.m"; sourceTree = "<group>"; };
663667
CB04969529150D860097E526 /* OtlpPackage.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OtlpPackage.h; sourceTree = "<group>"; };
664668
CB04969629150D860097E526 /* OtlpPackage.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = OtlpPackage.mm; sourceTree = "<group>"; };
665669
CB0496992915194E0097E526 /* OtlpUploader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OtlpUploader.h; sourceTree = "<group>"; };
@@ -896,8 +900,6 @@
896900
0122C21F29019770002D243C /* Private */ = {
897901
isa = PBXGroup;
898902
children = (
899-
1C7852A32E5F697D00BB8E2D /* SpanContext.mm */,
900-
1C7852A12E5F5B2E00BB8E2D /* SpanContext.h */,
901903
CB572EA829BB783200FD7A2A /* AppStateTracker.h */,
902904
CB572EA929BB783200FD7A2A /* AppStateTracker.m */,
903905
CBE8EA1C294B5E1500702950 /* Batch.h */,
@@ -945,6 +947,8 @@
945947
CBEC51BF296DB311009C0CE3 /* JSON.mm */,
946948
965FBD142DF24D3100D6BACB /* Logging.h */,
947949
098FC8772D3E8D43001B627D /* Metrics.h */,
950+
96F9010E2EE8175B0026F5B9 /* NSTimer+MainThread.h */,
951+
96F901102EE817690026F5B9 /* NSTimer+MainThread.m */,
948952
CBB48A3A295EE1E10044E9AC /* ObjCUtils.h */,
949953
CBB48A3B295EE1E10044E9AC /* ObjCUtils.mm */,
950954
CB04969529150D860097E526 /* OtlpPackage.h */,
@@ -972,6 +976,8 @@
972976
01A414CC2913C0F0003152A4 /* SpanAttributes.mm */,
973977
96D4160D29F276FE00AEE435 /* SpanAttributesProvider.h */,
974978
96D4160B29F276E400AEE435 /* SpanAttributesProvider.mm */,
979+
1C7852A12E5F5B2E00BB8E2D /* SpanContext.h */,
980+
1C7852A32E5F697D00BB8E2D /* SpanContext.mm */,
975981
963726C42DEAB14D00C739E6 /* SpanControl */,
976982
969EE0EE2E7872A600600F63 /* SpanFactory */,
977983
0122C22329019770002D243C /* SpanKind.h */,
@@ -1645,6 +1651,7 @@
16451651
CBEBE59329F2783C00BF0B4F /* Swizzle.h in Headers */,
16461652
962CE8082E651A0100380522 /* NetworkInstrumentationStateRepository.h in Headers */,
16471653
969EE0FE2E794A0700600F63 /* ViewLoadSpanFactoryCallbacks.h in Headers */,
1654+
96F9010F2EE817620026F5B9 /* NSTimer+MainThread.h in Headers */,
16481655
CBEC51BC296D9EEE009C0CE3 /* PersistentState.h in Headers */,
16491656
0122C23829019770002D243C /* BugsnagPerformanceSpan.h in Headers */,
16501657
962CE8212E66D24200380522 /* NetworkInstrumentationSystemUtilsImpl.h in Headers */,
@@ -2121,6 +2128,7 @@
21212128
CBE8EA1B294B5AB800702950 /* Worker.mm in Sources */,
21222129
CB78819C29E587CE00A58906 /* BugsnagPerformanceLibrary.mm in Sources */,
21232130
963726E02DF0B4AD00C739E6 /* BugsnagPerformancePluginContext.m in Sources */,
2131+
96F901112EE817700026F5B9 /* NSTimer+MainThread.m in Sources */,
21242132
098FC8552D37A08D001B627D /* SystemInfoSampler.mm in Sources */,
21252133
1C68DBA12E535D06002621D1 /* BugsnagPerformanceAppStartSpanQuery.mm in Sources */,
21262134
963726C82DEAB1FC00C739E6 /* BugsnagPerformancePriority.m in Sources */,

Sources/BugsnagPerformance/Private/BugsnagPerformanceImpl.mm

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#import "ConditionTimeoutExecutor.h"
2020
#import "BugsnagPerformanceSpan+Private.h"
2121
#import "BugsnagPerformanceAppStartTypePlugin.h"
22+
#import "NSTimer+MainThread.h"
2223

2324
using namespace bugsnag;
2425

@@ -262,9 +263,9 @@
262263
[worker_ start];
263264
[frameMetricsCollector_ start];
264265

265-
workerTimer_ = [NSTimer scheduledTimerWithTimeInterval:performWorkInterval_
266-
repeats:YES
267-
block:^(__unused NSTimer * _Nonnull timer) {
266+
workerTimer_ = [NSTimer mainThreadTimerWithTimeInterval:performWorkInterval_
267+
repeats:YES
268+
block:^(__unused NSTimer * _Nonnull timer) {
268269
blockThis->onWorkInterval();
269270
}];
270271

Sources/BugsnagPerformance/Private/ConditionTimeoutExecutor.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
#import <Foundation/Foundation.h>
1212
#import "BugsnagPerformanceSpanCondition+Private.h"
13+
#import "NSTimer+MainThread.h"
1314
#import <map>
1415
#import <mutex>
1516

@@ -21,7 +22,7 @@ class ConditionTimeoutExecutor {
2122

2223
void scheduleTimeout(BugsnagPerformanceSpanCondition *condition, NSTimeInterval timeout) noexcept {
2324
std::lock_guard<std::mutex> guard(mutex_);
24-
this->conditionIdToTimer_[condition.conditionId] = [NSTimer scheduledTimerWithTimeInterval:timeout repeats:NO block:^(NSTimer *) {
25+
this->conditionIdToTimer_[condition.conditionId] = [NSTimer mainThreadTimerWithTimeInterval:timeout repeats:NO block:^(NSTimer *) {
2526
[condition didTimeout];
2627
}];
2728
}

Sources/BugsnagPerformance/Private/Instrumentation/NetworkInstrumentation/Lifecycle/NetworkEarlyPhaseHandlerImpl.mm

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,10 @@
4747
callback(state);
4848
if (state.hasBeenVetoed) {
4949
[state.overallSpan cancel];
50+
return;
5051
}
51-
[state.overallSpan internalSetMultipleAttributes:spanAttributesProvider_->networkSpanUrlAttributes(state.url, nil)];
52+
[state.overallSpan forceMutate:^{
53+
[state.overallSpan internalSetMultipleAttributes:spanAttributesProvider_->networkSpanUrlAttributes(state.url, nil)];
54+
}];
5255
}
5356
}

Sources/BugsnagPerformance/Private/Instrumentation/ViewLoadInstrumentation/Lifecycle/ViewLoadLifecycleHandlerImpl.mm

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,9 @@
7171
originalImplementation();
7272
return;
7373
}
74-
adjustSpanIfPreloaded(overallSpan, state, [NSDate new], viewController);
74+
[overallSpan forceMutate:^{
75+
adjustSpanIfPreloaded(overallSpan, state, [NSDate new], viewController);
76+
}];
7577
state.viewWillAppearSpan = spanFactory_->startViewWillAppearSpan(viewController,
7678
state.overallSpan);
7779
originalImplementation();
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//
2+
// NSTimer+MainThread.h
3+
// BugsnagPerformance
4+
//
5+
// Created by Robert Bartoszewski on 09/12/2025.
6+
// Copyright © 2025 Bugsnag. All rights reserved.
7+
//
8+
9+
#import <Foundation/Foundation.h>
10+
11+
@interface NSTimer (MainThread)
12+
13+
/// Creates and returns a new NSTimer object initialized with the specified block object and schedules it on the main run loop in the default mode.
14+
/// - parameter: ti The number of seconds between firings of the timer. If seconds is less than or equal to 0.0, this method chooses the nonnegative value of 0.1 milliseconds instead
15+
/// - parameter: repeats If YES, the timer will repeatedly reschedule itself until invalidated. If NO, the timer will be invalidated after it fires.
16+
/// - parameter: block The execution body of the timer; the timer itself is passed as the parameter to this block when executed to aid in avoiding cyclical references
17+
+ (NSTimer *)mainThreadTimerWithTimeInterval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void (NS_SWIFT_SENDABLE ^)(NSTimer *timer))block API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));
18+
19+
@end
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//
2+
// NSTimer+MainThread.m
3+
// BugsnagPerformance
4+
//
5+
// Created by Robert Bartoszewski on 09/12/2025.
6+
// Copyright © 2025 Bugsnag. All rights reserved.
7+
//
8+
9+
#import "NSTimer+MainThread.h"
10+
11+
@implementation NSTimer (MainThread)
12+
13+
+ (NSTimer *)mainThreadTimerWithTimeInterval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void (NS_SWIFT_SENDABLE ^)(NSTimer *timer))block {
14+
NSTimer *timer = [self timerWithTimeInterval:interval repeats:repeats block:block];
15+
if ([NSThread isMainThread]) {
16+
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
17+
} else {
18+
dispatch_async(dispatch_get_main_queue(), ^{
19+
if ([timer isValid]) {
20+
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
21+
}
22+
});
23+
}
24+
return timer;
25+
}
26+
27+
@end

Sources/BugsnagPerformance/Private/SpanLifecycle/SpanLifecycleHandlerImpl.mm

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,9 @@
246246
}
247247

248248
if (span != nil && span.state == SpanStateEnded) {
249-
callOnSpanEndCallbacks(span);
249+
[span forceMutate:^{
250+
callOnSpanEndCallbacks(span);
251+
}];
250252
if (span.state == SpanStateAborted) {
251253
return;
252254
}

0 commit comments

Comments
 (0)