Skip to content

Commit 0559eab

Browse files
Adds profile id, replay id, and user to standalone INP spans if they exist
1 parent a937852 commit 0559eab

File tree

5 files changed

+54
-5
lines changed

5 files changed

+54
-5
lines changed

packages/core/src/tracing/transaction.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,16 @@ export class Transaction extends SpanClass implements TransactionInterface {
258258
this._hub = hub;
259259
}
260260

261+
/**
262+
* Get the profile id of the transaction.
263+
*/
264+
public getProfileId(): string | undefined {
265+
if (this._contexts !== undefined && this._contexts['profile'] !== undefined) {
266+
return this._contexts['profile'].profile_id as string;
267+
}
268+
return undefined;
269+
}
270+
261271
/**
262272
* Finish the transaction & prepare the event to send to Sentry.
263273
*/

packages/tracing-internal/src/browser/browserTracingIntegration.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/* eslint-disable max-lines */
22
import type { IdleTransaction } from '@sentry/core';
3-
import { getActiveSpan } from '@sentry/core';
3+
import { getActiveSpan, getClient, getCurrentScope } from '@sentry/core';
44
import { getCurrentHub } from '@sentry/core';
55
import {
66
SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,
@@ -12,6 +12,7 @@ import {
1212
} from '@sentry/core';
1313
import type {
1414
Client,
15+
Integration,
1516
IntegrationFn,
1617
StartSpanOptions,
1718
Transaction,
@@ -539,6 +540,15 @@ function registerInpInteractionListener(
539540
},
540541
): void {
541542
addPerformanceInstrumentationHandler('event', ({ entries }) => {
543+
const client = getClient();
544+
// We need to get the replay, user, and activeTransaction from the current scope
545+
// so that we can associate replay id, profile id, and a user display to the span
546+
const replay = client?.getIntegrationByName?.('Replay') as
547+
| (Integration & { getReplayId: () => string })
548+
| undefined;
549+
// eslint-disable-next-line deprecation/deprecation
550+
const activeTransaction = getActiveTransaction();
551+
const user = getCurrentScope()?.getUser();
542552
for (const entry of entries) {
543553
if (isPerformanceEventTiming(entry)) {
544554
const duration = entry.duration;
@@ -564,6 +574,9 @@ function registerInpInteractionListener(
564574
routeName,
565575
duration,
566576
parentContext,
577+
user,
578+
activeTransaction,
579+
replay,
567580
};
568581
}
569582
}

packages/tracing-internal/src/browser/metrics/index.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -214,10 +214,20 @@ function _trackINP(interactionIdtoRouteNameMapping: InteractionRouteNameMapping)
214214
/** Build the INP span, create an envelope from the span, and then send the envelope */
215215
const startTime = msToSec((browserPerformanceTimeOrigin as number) + entry.startTime);
216216
const duration = msToSec(metric.value);
217-
const { routeName, parentContext } =
217+
const { routeName, parentContext, activeTransaction, user, replay } =
218218
entry.interactionId !== undefined
219219
? interactionIdtoRouteNameMapping[entry.interactionId]
220-
: { routeName: undefined, parentContext: undefined };
220+
: {
221+
routeName: undefined,
222+
parentContext: undefined,
223+
activeTransaction: undefined,
224+
user: undefined,
225+
replay: undefined,
226+
};
227+
// eslint-disable-next-line deprecation/deprecation
228+
const userDisplay = user?.email || user?.id || user?.ip_address;
229+
const profileId = activeTransaction?.getProfileId();
230+
const replayId = replay?.getReplayId();
221231
const span = new Span({
222232
startTimestamp: startTime,
223233
endTimestamp: startTime + duration,
@@ -231,6 +241,9 @@ function _trackINP(interactionIdtoRouteNameMapping: InteractionRouteNameMapping)
231241
environment: options.environment,
232242
transaction: routeName,
233243
exclusive_time: metric.value,
244+
...(userDisplay !== undefined && userDisplay !== '' ? { user: userDisplay } : {}),
245+
...(profileId !== undefined ? { profile_id: profileId } : {}),
246+
...(replayId !== undefined ? { replay_id: replayId } : {}),
234247
},
235248
});
236249

packages/tracing-internal/src/browser/web-vitals/types.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
* limitations under the License.
1515
*/
1616

17-
import type { TransactionContext } from '@sentry/types';
17+
import type { Integration, Transaction, TransactionContext, User } from '@sentry/types';
1818
import type { FirstInputPolyfillCallback } from './types/polyfills';
1919

2020
export * from './types/base';
@@ -165,5 +165,12 @@ declare global {
165165
}
166166

167167
export type InteractionRouteNameMapping = {
168-
[key: string]: { routeName: string; duration: number; parentContext: TransactionContext };
168+
[key: string]: {
169+
routeName: string;
170+
duration: number;
171+
parentContext: TransactionContext;
172+
user?: User;
173+
activeTransaction?: Transaction;
174+
replay?: Integration & { getReplayId: () => string };
175+
};
169176
};

packages/types/src/transaction.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,12 @@ export interface Transaction extends TransactionContext, Omit<Span, 'setName' |
152152
* @deprecated Use top-level `getDynamicSamplingContextFromSpan` instead.
153153
*/
154154
getDynamicSamplingContext(): Partial<DynamicSamplingContext>;
155+
156+
/**
157+
* Get the profile id from the transaction
158+
* @deprecated Use `toJSON()` or access the fields directly instead.
159+
*/
160+
getProfileId(): string | undefined;
155161
}
156162

157163
/**

0 commit comments

Comments
 (0)