Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Add app start to first finished transaction #2252

Merged
merged 9 commits into from
Oct 5, 2022
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

### Fixes

- Add app start to first finished transaction (#2252)
philipphofmann marked this conversation as resolved.
Show resolved Hide resolved
- Return SentryNoOpSpan when starting a child on a finished transaction (#2239)

## 7.27.0
Expand Down
12 changes: 5 additions & 7 deletions Sources/Sentry/SentryTracer.m
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ @implementation SentryTracer {
BOOL _waitForChildren;
SentryTraceContext *_traceContext;
SentryProfilesSamplerDecision *_profilesSamplerDecision;
SentryAppStartMeasurement *appStartMeasurement;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see what you did here 😁👏🏻...

NSMutableDictionary<NSString *, id> *_tags;
NSMutableDictionary<NSString *, id> *_data;
dispatch_block_t _idleTimeoutBlock;
Expand Down Expand Up @@ -162,6 +163,7 @@ - (instancetype)initWithTransactionContext:(SentryTransactionContext *)transacti
self.finishStatus = kSentrySpanStatusUndefined;
self.idleTimeout = idleTimeout;
self.dispatchQueueWrapper = dispatchQueueWrapper;
appStartMeasurement = [self getAppStartMeasurement];

if ([self hasIdleTimeout]) {
[self dispatchIdleTimeout];
Expand Down Expand Up @@ -557,9 +559,7 @@ - (void)trimEndTimestamp

- (SentryTransaction *)toTransaction
{
SentryAppStartMeasurement *appStartMeasurement = [self getAppStartMeasurement];

NSArray<id<SentrySpan>> *appStartSpans = [self buildAppStartSpans:appStartMeasurement];
NSArray<id<SentrySpan>> *appStartSpans = [self buildAppStartSpans];

NSArray<id<SentrySpan>> *spans;
@synchronized(_children) {
Expand All @@ -573,7 +573,7 @@ - (SentryTransaction *)toTransaction

SentryTransaction *transaction = [[SentryTransaction alloc] initWithTrace:self children:spans];
transaction.transaction = self.transactionContext.name;
[self addMeasurements:transaction appStartMeasurement:appStartMeasurement];
[self addMeasurements:transaction];
return transaction;
}

Expand Down Expand Up @@ -626,8 +626,7 @@ - (nullable SentryAppStartMeasurement *)getAppStartMeasurement
return measurement;
}

- (NSArray<SentrySpan *> *)buildAppStartSpans:
(nullable SentryAppStartMeasurement *)appStartMeasurement
- (NSArray<SentrySpan *> *)buildAppStartSpans
{
if (appStartMeasurement == nil) {
return @[];
Expand Down Expand Up @@ -687,7 +686,6 @@ - (nullable SentryAppStartMeasurement *)getAppStartMeasurement
}

- (void)addMeasurements:(SentryTransaction *)transaction
appStartMeasurement:(nullable SentryAppStartMeasurement *)appStartMeasurement
{
NSString *valueKey = @"value";

Expand Down
51 changes: 43 additions & 8 deletions Tests/SentryTests/Performance/SentryTracerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -432,19 +432,41 @@ class SentryTracerTests: XCTestCase {
let appStartMeasurement = fixture.getAppStartMeasurement(type: .warm)
SentrySDK.setAppStartMeasurement(appStartMeasurement)

advanceTime(bySeconds: -(fixture.appStartDuration + 4))

let sut = fixture.getSut()
sut.startTimestamp = fixture.appStartEnd.addingTimeInterval(-5)
advanceTime(bySeconds: 1)
sut.finish()
fixture.hub.group.wait()

XCTAssertEqual(1, fixture.hub.capturedEventsWithScopes.count)
let serializedTransaction = fixture.hub.capturedEventsWithScopes.first!.event.serialize()
let measurements = serializedTransaction["measurements"] as? [String: [String: Int]]

XCTAssertEqual(["app_start_warm": ["value": 500]], measurements)
assertAppStartMeasurementOn(transaction: fixture.hub.capturedEventsWithScopes.first!.event as! Transaction, appStartMeasurement: appStartMeasurement)
}

func testAddColdStartMeasurement_PutOnFirstStartedTransaction() {
let appStartMeasurement = fixture.getAppStartMeasurement(type: .warm)
SentrySDK.setAppStartMeasurement(appStartMeasurement)

let transaction = fixture.hub.capturedEventsWithScopes.first!.event as! Transaction
assertAppStartsSpanAdded(transaction: transaction, startType: "Warm Start", operation: fixture.appStartWarmOperation, appStartMeasurement: appStartMeasurement)
advanceTime(bySeconds: 0.5)

let firstTransaction = fixture.getSut()
advanceTime(bySeconds: 0.5)

let secondTransaction = fixture.getSut()
advanceTime(bySeconds: 0.5)
secondTransaction.finish()

fixture.hub.group.wait()
XCTAssertEqual(1, fixture.hub.capturedEventsWithScopes.count)
let serializedSecondTransaction = fixture.hub.capturedEventsWithScopes.first!.event.serialize()
XCTAssertNil(serializedSecondTransaction["measurements"])

firstTransaction.finish()
fixture.hub.group.wait()

XCTAssertEqual(2, fixture.hub.capturedEventsWithScopes.count)
assertAppStartMeasurementOn(transaction: fixture.hub.capturedEventsWithScopes[1].event as! Transaction, appStartMeasurement: appStartMeasurement)
}

func testAddUnknownAppStartMeasurement_NotPutOnNextTransaction() {
Expand Down Expand Up @@ -488,8 +510,10 @@ class SentryTracerTests: XCTestCase {
let appStartMeasurement = fixture.getAppStartMeasurement(type: .warm)
SentrySDK.setAppStartMeasurement(appStartMeasurement)

advanceTime(bySeconds: fixture.appStartDuration + 5.01)

let sut = fixture.getSut()
sut.startTimestamp = fixture.appStartEnd.addingTimeInterval(5.1)
advanceTime(bySeconds: 1.0)
sut.finish()
fixture.hub.group.wait()

Expand All @@ -500,8 +524,10 @@ class SentryTracerTests: XCTestCase {
let appStartMeasurement = fixture.getAppStartMeasurement(type: .warm)
SentrySDK.setAppStartMeasurement(appStartMeasurement)

advanceTime(bySeconds: -(fixture.appStartDuration + 4.01))

let sut = fixture.getSut()
sut.startTimestamp = fixture.appStartEnd.addingTimeInterval(-5.1)
advanceTime(bySeconds: 1.0)
sut.finish()
fixture.hub.group.wait()

Expand Down Expand Up @@ -821,6 +847,15 @@ class SentryTracerTests: XCTestCase {
assertSpan("Initial Frame Render", appStartMeasurement.didFinishLaunchingTimestamp, fixture.appStartEnd)
}

private func assertAppStartMeasurementOn(transaction: Transaction, appStartMeasurement: SentryAppStartMeasurement) {
let serializedTransaction = transaction.serialize()
let measurements = serializedTransaction["measurements"] as? [String: [String: Int]]

XCTAssertEqual(["app_start_warm": ["value": 500]], measurements)

assertAppStartsSpanAdded(transaction: transaction, startType: "Warm Start", operation: fixture.appStartWarmOperation, appStartMeasurement: appStartMeasurement)
}

private func assertAppStartMeasurementNotPutOnTransaction() {
XCTAssertEqual(1, fixture.hub.capturedEventsWithScopes.count)
let serializedTransaction = fixture.hub.capturedEventsWithScopes.first!.event.serialize()
Expand Down