Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@

### Fixes

- App start data not attached to sampled transactions when preceded by unsampled transactions ([#5756](https://github.com/getsentry/sentry-react-native/pull/5756))
- Resolve relative `SOURCEMAP_FILE` paths against the project root in the Xcode build script ([#5730](https://github.com/getsentry/sentry-react-native/pull/5730))
- Fixes the issue with unit mismatch in `adjustTransactionDuration` ([#5740](https://github.com/getsentry/sentry-react-native/pull/5740))
- Handle `inactive` state for spans ([#5742](https://github.com/getsentry/sentry-react-native/pull/5742))
Expand Down
5 changes: 5 additions & 0 deletions packages/core/src/js/tracing/integrations/appStart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
getCurrentScope,
SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,
SentryNonRecordingSpan,
spanIsSampled,
startInactiveSpan,
timestampInSeconds,
} from '@sentry/core';
Expand Down Expand Up @@ -241,6 +242,10 @@ export const appStartIntegration = ({
return;
}

if (!spanIsSampled(rootSpan)) {
return;
}

setFirstStartedActiveRootSpanId(rootSpan.spanContext().spanId);
};

Expand Down
45 changes: 45 additions & 0 deletions packages/core/test/tracing/integrations/appStart.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
getIsolationScope,
SEMANTIC_ATTRIBUTE_SENTRY_OP,
SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,
SentryNonRecordingSpan,
setCurrentClient,
startInactiveSpan,
timestampInSeconds,
Expand Down Expand Up @@ -463,6 +464,50 @@ describe('App Start Integration', () => {
});
});

it('Does not lock firstStartedActiveRootSpanId to unsampled root span', async () => {
mockAppStart({ cold: true });

const integration = appStartIntegration();
const client = new TestClient({
...getDefaultTestClientOptions(),
enableAppStartTracking: true,
tracesSampleRate: 1.0,
});
setCurrentClient(client);
integration.setup(client);
integration.afterAllSetup(client);

// Simulate an unsampled root span starting first
const unsampledSpan = new SentryNonRecordingSpan();
client.emit('spanStart', unsampledSpan);

// Then a sampled root span starts
const sampledSpan = startInactiveSpan({
name: 'Sampled Root Span',
forceTransaction: true,
});
const sampledSpanId = sampledSpan.spanContext().spanId;

// Process a transaction event matching the sampled span
const event = getMinimalTransactionEvent();
event.contexts!.trace!.span_id = sampledSpanId;

const actualEvent = await processEventWithIntegration(integration, event);

// App start should be attached to the sampled transaction
const appStartSpan = (actualEvent as TransactionEvent)?.spans?.find(
({ description }) => description === 'Cold Start',
);
expect(appStartSpan).toBeDefined();
expect(appStartSpan).toEqual(
expect.objectContaining({
description: 'Cold Start',
op: APP_START_COLD_OP,
}),
);
expect((actualEvent as TransactionEvent)?.measurements?.[APP_START_COLD_MEASUREMENT]).toBeDefined();
});

it('Adds Cold App Start Span to Active Span', async () => {
const [timeOriginMilliseconds, appStartTimeMilliseconds] = mockAppStart({ cold: true });

Expand Down
Loading