Skip to content

Commit d053743

Browse files
authored
feat: Adds span thread info (#4579)
* Adds span thread info * Adds changelog * Fix tests * Only set main thread info for app start spans which are fetched from the native SDKs * Update changelog * Removes thead.id * Update changelog
1 parent 5e5c392 commit d053743

File tree

8 files changed

+66
-11
lines changed

8 files changed

+66
-11
lines changed

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88
99
## Unreleased
1010

11+
### Features
12+
13+
- Add thread information to spans ([#4579](https://github.com/getsentry/sentry-react-native/pull/4579))
14+
1115
### Fixes
1216

1317
- Considers the `SENTRY_DISABLE_AUTO_UPLOAD` and `SENTRY_DISABLE_NATIVE_DEBUG_UPLOAD` environment variables in the configuration of the Sentry Android Gradle Plugin for Expo plugin ([#4583](https://github.com/getsentry/sentry-react-native/pull/4583))

packages/core/src/js/tracing/integrations/appStart.ts

+11-8
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* eslint-disable complexity */
1+
/* eslint-disable complexity, max-lines */
22
import type { Client, Event, Integration, SpanJSON, TransactionEvent } from '@sentry/core';
33
import {
44
getCapturedScopesOnSpan,
@@ -26,6 +26,7 @@ import {
2626
} from '../ops';
2727
import { SPAN_ORIGIN_AUTO_APP_START, SPAN_ORIGIN_MANUAL_APP_START } from '../origin';
2828
import { SEMANTIC_ATTRIBUTE_SENTRY_OP } from '../semanticAttributes';
29+
import { setMainThreadInfo } from '../span';
2930
import { createChildSpanJSON, createSpanJSON, getBundleStartTimestampMs } from '../utils';
3031

3132
const INTEGRATION_NAME = 'AppStart';
@@ -384,15 +385,17 @@ function createJSExecutionStartSpan(
384385
function convertNativeSpansToSpanJSON(parentSpan: SpanJSON, nativeSpans: NativeAppStartResponse['spans']): SpanJSON[] {
385386
return nativeSpans.map(span => {
386387
if (span.description === 'UIKit init') {
387-
return createUIKitSpan(parentSpan, span);
388+
return setMainThreadInfo(createUIKitSpan(parentSpan, span));
388389
}
389390

390-
return createChildSpanJSON(parentSpan, {
391-
description: span.description,
392-
start_timestamp: span.start_timestamp_ms / 1000,
393-
timestamp: span.end_timestamp_ms / 1000,
394-
origin: SPAN_ORIGIN_AUTO_APP_START,
395-
});
391+
return setMainThreadInfo(
392+
createChildSpanJSON(parentSpan, {
393+
description: span.description,
394+
start_timestamp: span.start_timestamp_ms / 1000,
395+
timestamp: span.end_timestamp_ms / 1000,
396+
origin: SPAN_ORIGIN_AUTO_APP_START,
397+
}),
398+
);
396399
});
397400
}
398401

packages/core/src/js/tracing/reactnativetracing.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { getClient } from '@sentry/core';
55

66
import { isWeb } from '../utils/environment';
77
import { getDevServer } from './../integrations/debugsymbolicatorutils';
8-
import { addDefaultOpForSpanFrom, defaultIdleOptions } from './span';
8+
import { addDefaultOpForSpanFrom, addThreadInfoToSpan, defaultIdleOptions } from './span';
99

1010
export const INTEGRATION_NAME = 'ReactNativeTracing';
1111

@@ -119,6 +119,7 @@ export const reactNativeTracingIntegration = (
119119

120120
const setup = (client: Client): void => {
121121
addDefaultOpForSpanFrom(client);
122+
addThreadInfoToSpan(client);
122123

123124
instrumentOutgoingRequests(client, {
124125
traceFetch: finalOptions.traceFetch,

packages/core/src/js/tracing/span.ts

+26-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { Client, Scope, Span, StartSpanOptions } from '@sentry/core';
1+
import type { Client, Scope, Span, SpanJSON, StartSpanOptions } from '@sentry/core';
22
import {
33
generatePropagationContext,
44
getActiveSpan,
@@ -154,3 +154,28 @@ export function addDefaultOpForSpanFrom(client: Client): void {
154154
}
155155
});
156156
}
157+
158+
export const SPAN_THREAD_NAME = 'thread.name';
159+
export const SPAN_THREAD_NAME_MAIN = 'main';
160+
export const SPAN_THREAD_NAME_JAVASCRIPT = 'javascript';
161+
162+
/**
163+
* Adds Javascript thread info to spans.
164+
* Ref: https://reactnative.dev/architecture/threading-model
165+
*/
166+
export function addThreadInfoToSpan(client: Client): void {
167+
client.on('spanStart', (span: Span) => {
168+
if (!spanToJSON(span).data?.[SPAN_THREAD_NAME]) {
169+
span.setAttribute(SPAN_THREAD_NAME, SPAN_THREAD_NAME_JAVASCRIPT);
170+
}
171+
});
172+
}
173+
174+
/**
175+
* Sets the Main thread info to the span.
176+
*/
177+
export function setMainThreadInfo(spanJSON: SpanJSON): SpanJSON {
178+
spanJSON.data = spanJSON.data || {};
179+
spanJSON.data[SPAN_THREAD_NAME] = SPAN_THREAD_NAME_MAIN;
180+
return spanJSON;
181+
}

packages/core/test/tracing/integrations/appStart.test.ts

+3
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import {
2727
setRootComponentCreationTimestampMs,
2828
} from '../../../src/js/tracing/integrations/appStart';
2929
import { SPAN_ORIGIN_AUTO_APP_START, SPAN_ORIGIN_MANUAL_APP_START } from '../../../src/js/tracing/origin';
30+
import { SPAN_THREAD_NAME, SPAN_THREAD_NAME_MAIN } from '../../../src/js/tracing/span';
3031
import { getTimeOriginMilliseconds } from '../../../src/js/tracing/utils';
3132
import { RN_GLOBAL_OBJ } from '../../../src/js/utils/worldwide';
3233
import { NATIVE } from '../../../src/js/wrapper';
@@ -252,6 +253,7 @@ describe('App Start Integration', () => {
252253
data: {
253254
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: appStartRootSpan!.op,
254255
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: SPAN_ORIGIN_AUTO_APP_START,
256+
[SPAN_THREAD_NAME]: SPAN_THREAD_NAME_MAIN,
255257
},
256258
}),
257259
);
@@ -612,6 +614,7 @@ describe('App Start Integration', () => {
612614
data: {
613615
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: appStartRootSpan!.op,
614616
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: SPAN_ORIGIN_AUTO_APP_START,
617+
[SPAN_THREAD_NAME]: SPAN_THREAD_NAME_MAIN,
615618
},
616619
}),
617620
);

packages/core/test/tracing/reactnativenavigation.test.ts

+6
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import {
3232
SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE,
3333
SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,
3434
} from '../../src/js/tracing/semanticAttributes';
35+
import { SPAN_THREAD_NAME, SPAN_THREAD_NAME_JAVASCRIPT } from '../../src/js/tracing/span';
3536
import { getDefaultTestClientOptions, TestClient } from '../mocks/client';
3637

3738
interface MockEventsRegistry extends EventsRegistry {
@@ -87,6 +88,7 @@ describe('React Native Navigation Instrumentation', () => {
8788
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'navigation',
8889
[SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE]: 1,
8990
[SEMANTIC_ATTRIBUTE_SENTRY_IDLE_SPAN_FINISH_REASON]: 'idleTimeout',
91+
[SPAN_THREAD_NAME]: SPAN_THREAD_NAME_JAVASCRIPT,
9092
},
9193
}),
9294
}),
@@ -131,6 +133,7 @@ describe('React Native Navigation Instrumentation', () => {
131133
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'navigation',
132134
[SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE]: 1,
133135
[SEMANTIC_ATTRIBUTE_SENTRY_IDLE_SPAN_FINISH_REASON]: 'idleTimeout',
136+
[SPAN_THREAD_NAME]: SPAN_THREAD_NAME_JAVASCRIPT,
134137
},
135138
}),
136139
}),
@@ -206,6 +209,7 @@ describe('React Native Navigation Instrumentation', () => {
206209
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'navigation',
207210
[SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE]: 1,
208211
[SEMANTIC_ATTRIBUTE_SENTRY_IDLE_SPAN_FINISH_REASON]: 'idleTimeout',
212+
[SPAN_THREAD_NAME]: SPAN_THREAD_NAME_JAVASCRIPT,
209213
},
210214
}),
211215
}),
@@ -294,6 +298,7 @@ describe('React Native Navigation Instrumentation', () => {
294298
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'navigation',
295299
[SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE]: 1,
296300
[SEMANTIC_ATTRIBUTE_SENTRY_IDLE_SPAN_FINISH_REASON]: 'idleTimeout',
301+
[SPAN_THREAD_NAME]: SPAN_THREAD_NAME_JAVASCRIPT,
297302
},
298303
}),
299304
}),
@@ -342,6 +347,7 @@ describe('React Native Navigation Instrumentation', () => {
342347
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'navigation',
343348
[SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE]: 1,
344349
[SEMANTIC_ATTRIBUTE_SENTRY_IDLE_SPAN_FINISH_REASON]: 'idleTimeout',
350+
[SPAN_THREAD_NAME]: SPAN_THREAD_NAME_JAVASCRIPT,
345351
},
346352
}),
347353
}),

packages/core/test/tracing/reactnavigation.test.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import {
2020
SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE,
2121
SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,
2222
} from '../../src/js/tracing/semanticAttributes';
23-
import { DEFAULT_NAVIGATION_SPAN_NAME } from '../../src/js/tracing/span';
23+
import { DEFAULT_NAVIGATION_SPAN_NAME, SPAN_THREAD_NAME, SPAN_THREAD_NAME_JAVASCRIPT } from '../../src/js/tracing/span';
2424
import { RN_GLOBAL_OBJ } from '../../src/js/utils/worldwide';
2525
import { getDefaultTestClientOptions, TestClient } from '../mocks/client';
2626
import { NATIVE } from '../mockWrapper';
@@ -83,6 +83,7 @@ describe('ReactNavigationInstrumentation', () => {
8383
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'navigation',
8484
[SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE]: 1,
8585
[SEMANTIC_ATTRIBUTE_SENTRY_IDLE_SPAN_FINISH_REASON]: 'idleTimeout',
86+
[SPAN_THREAD_NAME]: SPAN_THREAD_NAME_JAVASCRIPT,
8687
},
8788
}),
8889
}),
@@ -192,6 +193,7 @@ describe('ReactNavigationInstrumentation', () => {
192193
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'navigation',
193194
[SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE]: 1,
194195
[SEMANTIC_ATTRIBUTE_SENTRY_IDLE_SPAN_FINISH_REASON]: 'idleTimeout',
196+
[SPAN_THREAD_NAME]: SPAN_THREAD_NAME_JAVASCRIPT,
195197
},
196198
}),
197199
}),
@@ -229,6 +231,7 @@ describe('ReactNavigationInstrumentation', () => {
229231
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'navigation',
230232
[SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE]: 1,
231233
[SEMANTIC_ATTRIBUTE_SENTRY_IDLE_SPAN_FINISH_REASON]: 'idleTimeout',
234+
[SPAN_THREAD_NAME]: SPAN_THREAD_NAME_JAVASCRIPT,
232235
},
233236
}),
234237
}),
@@ -268,6 +271,7 @@ describe('ReactNavigationInstrumentation', () => {
268271
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'navigation',
269272
[SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE]: 1,
270273
[SEMANTIC_ATTRIBUTE_SENTRY_IDLE_SPAN_FINISH_REASON]: 'idleTimeout',
274+
[SPAN_THREAD_NAME]: SPAN_THREAD_NAME_JAVASCRIPT,
271275
},
272276
}),
273277
}),

packages/core/test/tracing/reactnavigation.ttid.test.tsx

+9
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { startSpanManual } from '../../src/js';
1616
import { TimeToFullDisplay, TimeToInitialDisplay } from '../../src/js/tracing';
1717
import { _setAppStartEndTimestampMs } from '../../src/js/tracing/integrations/appStart';
1818
import { SPAN_ORIGIN_AUTO_NAVIGATION_REACT_NAVIGATION, SPAN_ORIGIN_AUTO_UI_TIME_TO_DISPLAY, SPAN_ORIGIN_MANUAL_UI_TIME_TO_DISPLAY } from '../../src/js/tracing/origin';
19+
import { SPAN_THREAD_NAME, SPAN_THREAD_NAME_JAVASCRIPT } from '../../src/js/tracing/span';
1920
import { isHermesEnabled, notWeb } from '../../src/js/utils/environment';
2021
import { createSentryFallbackEventEmitter } from '../../src/js/utils/sentryeventemitterfallback';
2122
import { RN_GLOBAL_OBJ } from '../../src/js/utils/worldwide';
@@ -80,6 +81,7 @@ describe('React Navigation - TTID', () => {
8081
data: {
8182
'sentry.op': 'ui.load.initial_display',
8283
'sentry.origin': SPAN_ORIGIN_AUTO_UI_TIME_TO_DISPLAY,
84+
[SPAN_THREAD_NAME]: SPAN_THREAD_NAME_JAVASCRIPT,
8385
},
8486
description: 'New Screen initial display',
8587
op: 'ui.load.initial_display',
@@ -110,6 +112,7 @@ describe('React Navigation - TTID', () => {
110112
data: {
111113
'sentry.op': 'ui.load.initial_display',
112114
'sentry.origin': SPAN_ORIGIN_AUTO_UI_TIME_TO_DISPLAY,
115+
[SPAN_THREAD_NAME]: SPAN_THREAD_NAME_JAVASCRIPT,
113116
},
114117
description: 'New Screen initial display',
115118
op: 'ui.load.initial_display',
@@ -146,6 +149,7 @@ describe('React Navigation - TTID', () => {
146149
data: {
147150
'sentry.op': 'ui.load.initial_display',
148151
'sentry.origin': SPAN_ORIGIN_AUTO_UI_TIME_TO_DISPLAY,
152+
[SPAN_THREAD_NAME]: SPAN_THREAD_NAME_JAVASCRIPT,
149153
},
150154
description: 'New Screen initial display',
151155
op: 'ui.load.initial_display',
@@ -203,6 +207,7 @@ describe('React Navigation - TTID', () => {
203207
'sentry.op': 'navigation.processing',
204208
'sentry.origin': SPAN_ORIGIN_AUTO_NAVIGATION_REACT_NAVIGATION,
205209
'sentry.source': 'custom',
210+
[SPAN_THREAD_NAME]: SPAN_THREAD_NAME_JAVASCRIPT,
206211
},
207212
description: 'Navigation dispatch to screen New Screen mounted',
208213
op: 'navigation.processing',
@@ -231,6 +236,7 @@ describe('React Navigation - TTID', () => {
231236
'sentry.op': 'navigation.processing',
232237
'sentry.origin': SPAN_ORIGIN_AUTO_NAVIGATION_REACT_NAVIGATION,
233238
'sentry.source': 'custom',
239+
[SPAN_THREAD_NAME]: SPAN_THREAD_NAME_JAVASCRIPT,
234240
},
235241
description: 'Navigation dispatch to screen Initial Screen mounted',
236242
op: 'navigation.processing',
@@ -261,6 +267,7 @@ describe('React Navigation - TTID', () => {
261267
data: {
262268
'sentry.op': 'ui.load.initial_display',
263269
'sentry.origin': SPAN_ORIGIN_AUTO_UI_TIME_TO_DISPLAY,
270+
[SPAN_THREAD_NAME]: SPAN_THREAD_NAME_JAVASCRIPT,
264271
},
265272
description: 'Initial Screen initial display',
266273
op: 'ui.load.initial_display',
@@ -295,6 +302,7 @@ describe('React Navigation - TTID', () => {
295302
data: {
296303
'sentry.op': 'ui.load.full_display',
297304
'sentry.origin': SPAN_ORIGIN_MANUAL_UI_TIME_TO_DISPLAY,
305+
[SPAN_THREAD_NAME]: SPAN_THREAD_NAME_JAVASCRIPT,
298306
},
299307
description: 'Time To Full Display',
300308
op: 'ui.load.full_display',
@@ -371,6 +379,7 @@ describe('React Navigation - TTID', () => {
371379
data: {
372380
'sentry.op': 'ui.load.initial_display',
373381
'sentry.origin': SPAN_ORIGIN_AUTO_UI_TIME_TO_DISPLAY,
382+
[SPAN_THREAD_NAME]: SPAN_THREAD_NAME_JAVASCRIPT,
374383
},
375384
description: 'New Screen initial display',
376385
op: 'ui.load.initial_display',

0 commit comments

Comments
 (0)