Skip to content

Commit 252a8c2

Browse files
feat: Add extra app start span (#1952)
Add __mod_init_func hook which gets called before main. With this info we can add one more app start span.
1 parent db38c00 commit 252a8c2

File tree

13 files changed

+203
-79
lines changed

13 files changed

+203
-79
lines changed

CHANGELOG.md

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

55
### Features
66

7+
- feat: Add extra app start span (#1952)
78
- Add enableAutoBreadcrumbTracking option (#1958)
89

910
### Fixes
@@ -40,7 +41,7 @@
4041
## 7.18.0
4142

4243
### Features
43-
44+
4445
- Replace tracestate header with baggage (#1867)
4546

4647
### Fixes

Samples/tvOS-Swift/tvOS-Swift/ContentView.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ struct ContentView: View {
8585
Button(action: captureMessageAction) {
8686
Text("Capture Message")
8787
}
88+
.accessibility(identifier: "captureMessageButton")
8889

8990
Button(action: captureUserFeedbackAction) {
9091
Text("Capture User Feedback")
Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,30 @@
11
import XCTest
22

33
class LaunchUITests: XCTestCase {
4+
5+
private let app: XCUIApplication = XCUIApplication()
46

57
override func setUpWithError() throws {
68
try super.setUpWithError()
79
continueAfterFailure = false
10+
11+
app.launch()
12+
}
13+
14+
override func tearDown() {
15+
app.terminate()
16+
super.tearDown()
817
}
918

1019
func testLaunch() throws {
11-
let app = XCUIApplication()
12-
app.launch()
20+
XCTAssertTrue(app.buttons["captureMessageButton"].waitForExistence(), "Home Screen doesn't exist.")
21+
}
22+
}
23+
24+
extension XCUIElement {
25+
26+
@discardableResult
27+
func waitForExistence() -> Bool {
28+
self.waitForExistence(timeout: TimeInterval(10))
1329
}
1430
}

Sources/Sentry/Public/SentryAppStartMeasurement.h

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,20 @@ SENTRY_NO_INIT
1818
appStartTimestamp:(NSDate *)appStartTimestamp
1919
duration:(NSTimeInterval)duration
2020
runtimeInitTimestamp:(NSDate *)runtimeInitTimestamp
21-
didFinishLaunchingTimestamp:(NSDate *)didFinishLaunchingTimestamp;
21+
didFinishLaunchingTimestamp:(NSDate *)didFinishLaunchingTimestamp
22+
DEPRECATED_MSG_ATTRIBUTE("Use "
23+
"initWithType:appStartTimestamp:duration:mainTimestamp:"
24+
"runtimeInitTimestamp:didFinishLaunchingTimestamp instead.");
25+
26+
/**
27+
* Initializes SentryAppStartMeasurement with the given parameters.
28+
*/
29+
- (instancetype)initWithType:(SentryAppStartType)type
30+
appStartTimestamp:(NSDate *)appStartTimestamp
31+
duration:(NSTimeInterval)duration
32+
runtimeInitTimestamp:(NSDate *)runtimeInitTimestamp
33+
moduleInitializationTimestamp:(NSDate *)moduleInitializationTimestamp
34+
didFinishLaunchingTimestamp:(NSDate *)didFinishLaunchingTimestamp;
2235

2336
/**
2437
* The type of the app start.
@@ -41,6 +54,11 @@ SENTRY_NO_INIT
4154
*/
4255
@property (readonly, nonatomic, strong) NSDate *runtimeInitTimestamp;
4356

57+
/**
58+
* When application main function is called.
59+
*/
60+
@property (readonly, nonatomic, strong) NSDate *moduleInitializationTimestamp;
61+
4462
/**
4563
* When OS posts UIApplicationDidFinishLaunchingNotification.
4664
*/

Sources/Sentry/SentryAppStartMeasurement.m

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#import "SentryAppStartMeasurement.h"
2+
#import "NSDate+SentryExtras.h"
23
#import <Foundation/Foundation.h>
34

45
@implementation SentryAppStartMeasurement
@@ -8,12 +9,28 @@ - (instancetype)initWithType:(SentryAppStartType)type
89
duration:(NSTimeInterval)duration
910
runtimeInitTimestamp:(NSDate *)runtimeInitTimestamp
1011
didFinishLaunchingTimestamp:(NSDate *)didFinishLaunchingTimestamp
12+
{
13+
return [self initWithType:type
14+
appStartTimestamp:appStartTimestamp
15+
duration:duration
16+
runtimeInitTimestamp:runtimeInitTimestamp
17+
moduleInitializationTimestamp:[NSDate dateWithTimeIntervalSince1970:0]
18+
didFinishLaunchingTimestamp:didFinishLaunchingTimestamp];
19+
}
20+
21+
- (instancetype)initWithType:(SentryAppStartType)type
22+
appStartTimestamp:(NSDate *)appStartTimestamp
23+
duration:(NSTimeInterval)duration
24+
runtimeInitTimestamp:(NSDate *)runtimeInitTimestamp
25+
moduleInitializationTimestamp:(NSDate *)moduleInitializationTimestamp
26+
didFinishLaunchingTimestamp:(NSDate *)didFinishLaunchingTimestamp
1127
{
1228
if (self = [super init]) {
1329
_type = type;
1430
_appStartTimestamp = appStartTimestamp;
1531
_duration = duration;
1632
_runtimeInitTimestamp = runtimeInitTimestamp;
33+
_moduleInitializationTimestamp = moduleInitializationTimestamp;
1734
_didFinishLaunchingTimestamp = didFinishLaunchingTimestamp;
1835
}
1936

Sources/Sentry/SentryAppStartTracker.m

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -176,12 +176,13 @@ - (void)buildAppStartMeasurement
176176
appStartDuration = 0;
177177
}
178178

179-
SentryAppStartMeasurement *appStartMeasurement =
180-
[[SentryAppStartMeasurement alloc] initWithType:appStartType
181-
appStartTimestamp:self.sysctl.processStartTimestamp
182-
duration:appStartDuration
183-
runtimeInitTimestamp:runtimeInit
184-
didFinishLaunchingTimestamp:self.didFinishLaunchingTimestamp];
179+
SentryAppStartMeasurement *appStartMeasurement = [[SentryAppStartMeasurement alloc]
180+
initWithType:appStartType
181+
appStartTimestamp:self.sysctl.processStartTimestamp
182+
duration:appStartDuration
183+
runtimeInitTimestamp:runtimeInit
184+
moduleInitializationTimestamp:self.sysctl.moduleInitializationTimestamp
185+
didFinishLaunchingTimestamp:self.didFinishLaunchingTimestamp];
185186

186187
SentrySDK.appStartMeasurement = appStartMeasurement;
187188
};

Sources/Sentry/SentrySysctl.m

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,37 @@
11
#import "SentrySysctl.h"
22
#import "SentryCrashSysCtl.h"
3+
#include <stdio.h>
4+
#include <time.h>
5+
6+
static NSDate *moduleInitializationTimestamp;
7+
static NSDate *runtimeInit = nil;
8+
9+
void
10+
sentryModuleInitializationHook(int argc, char **argv, char **envp)
11+
{
12+
moduleInitializationTimestamp = [NSDate date];
13+
}
14+
/**
15+
* Module initialization functions. The C++ compiler places static constructors here. For more info
16+
* visit:
17+
* https://github.com/aidansteele/osx-abi-macho-file-format-reference#table-2-the-sections-of-a__datasegment
18+
*/
19+
__attribute__((section("__DATA,__mod_init_func"))) typeof(sentryModuleInitializationHook) *__init
20+
= sentryModuleInitializationHook;
321

422
@implementation SentrySysctl
523

24+
+ (void)load
25+
{
26+
// Invoked whenever this class is added to the Objective-C runtime.
27+
runtimeInit = [NSDate date];
28+
}
29+
30+
- (NSDate *)runtimeInitTimestamp
31+
{
32+
return runtimeInit;
33+
}
34+
635
- (NSDate *)systemBootTimestamp
736
{
837
struct timeval value = sentrycrashsysctl_timeval(CTL_KERN, KERN_BOOTTIME);
@@ -15,4 +44,9 @@ - (NSDate *)processStartTimestamp
1544
return [NSDate dateWithTimeIntervalSince1970:startTime.tv_sec + startTime.tv_usec / 1E6];
1645
}
1746

47+
- (NSDate *)moduleInitializationTimestamp
48+
{
49+
return moduleInitializationTimestamp;
50+
}
51+
1852
@end

Sources/Sentry/SentryTracer.m

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -588,16 +588,22 @@ - (nullable SentryAppStartMeasurement *)getAppStartMeasurement
588588
description:type];
589589
[appStartSpan setStartTimestamp:appStartMeasurement.appStartTimestamp];
590590

591+
SentrySpan *premainSpan = [self buildSpan:appStartSpan.context.spanId
592+
operation:operation
593+
description:@"Pre Runtime Init"];
594+
[premainSpan setStartTimestamp:appStartMeasurement.appStartTimestamp];
595+
[premainSpan setTimestamp:appStartMeasurement.runtimeInitTimestamp];
596+
591597
SentrySpan *runtimeInitSpan = [self buildSpan:appStartSpan.context.spanId
592598
operation:operation
593-
description:@"Pre main"];
594-
[runtimeInitSpan setStartTimestamp:appStartMeasurement.appStartTimestamp];
595-
[runtimeInitSpan setTimestamp:appStartMeasurement.runtimeInitTimestamp];
599+
description:@"Runtime Init to Pre Main Initializers"];
600+
[runtimeInitSpan setStartTimestamp:appStartMeasurement.runtimeInitTimestamp];
601+
[runtimeInitSpan setTimestamp:appStartMeasurement.moduleInitializationTimestamp];
596602

597603
SentrySpan *appInitSpan = [self buildSpan:appStartSpan.context.spanId
598604
operation:operation
599605
description:@"UIKit and Application Init"];
600-
[appInitSpan setStartTimestamp:appStartMeasurement.runtimeInitTimestamp];
606+
[appInitSpan setStartTimestamp:appStartMeasurement.moduleInitializationTimestamp];
601607
[appInitSpan setTimestamp:appStartMeasurement.didFinishLaunchingTimestamp];
602608

603609
SentrySpan *frameRenderSpan = [self buildSpan:appStartSpan.context.spanId
@@ -608,7 +614,7 @@ - (nullable SentryAppStartMeasurement *)getAppStartMeasurement
608614

609615
[appStartSpan setTimestamp:appStartEndTimestamp];
610616

611-
return @[ appStartSpan, runtimeInitSpan, appInitSpan, frameRenderSpan ];
617+
return @[ appStartSpan, premainSpan, runtimeInitSpan, appInitSpan, frameRenderSpan ];
612618
}
613619

614620
- (void)addMeasurements:(SentryTransaction *)transaction

Sources/Sentry/include/SentrySysctl.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ NS_ASSUME_NONNULL_BEGIN
1414

1515
@property (readonly) NSDate *processStartTimestamp;
1616

17+
@property (readonly) NSDate *runtimeInitTimestamp;
18+
19+
@property (readonly) NSDate *moduleInitializationTimestamp;
20+
1721
@end
1822

1923
NS_ASSUME_NONNULL_END

Tests/SentryTests/Helper/SentrySysctlTests.swift

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,34 @@ class SentrySysctlTests: XCTestCase {
2020

2121
XCTAssertGreaterThan(distance, 0)
2222
}
23+
24+
func testMainTimestamp_IsInThePast() {
25+
let distance = Date().timeIntervalSince(sut.moduleInitializationTimestamp)
26+
27+
XCTAssertGreaterThan(distance, 0)
28+
}
29+
30+
func testMainTimestamp_IsBiggerThan_ProcessStartTime() {
31+
let distance = sut.moduleInitializationTimestamp.timeIntervalSince(sut.processStartTimestamp)
32+
33+
XCTAssertGreaterThan(distance, 0)
34+
}
35+
36+
func testMainTimestamp_IsBiggerThan_RuntimeInitTimestamp() {
37+
let distance = sut.moduleInitializationTimestamp.timeIntervalSince(sut.runtimeInitTimestamp)
38+
39+
XCTAssertGreaterThan(distance, 0)
40+
}
41+
42+
func testRuntimeInitTimestamp_IsBiggerThan_ProcessStartTimestamp() {
43+
let distance = sut.runtimeInitTimestamp.timeIntervalSince(sut.processStartTimestamp)
44+
45+
XCTAssertGreaterThan(distance, 0)
46+
}
47+
48+
func testRuntimeInitTimestamp_IsInThePast() {
49+
let distance = Date().timeIntervalSince(sut.runtimeInitTimestamp)
50+
51+
XCTAssertGreaterThan(distance, 0)
52+
}
2353
}

0 commit comments

Comments
 (0)