From 5d6d365905d0e87bff00c0ae96f9402a35155851 Mon Sep 17 00:00:00 2001 From: Abdullah Khan Date: Fri, 1 Aug 2025 13:27:24 -0400 Subject: [PATCH 1/3] feat(trace-eap-waterfall): Fixing link to profile from trace drawer --- .../details/missingInstrumentation.tsx | 44 ++++++++++++++----- .../details/profiling/profilePreview.tsx | 31 ++++++------- 2 files changed, 49 insertions(+), 26 deletions(-) diff --git a/static/app/views/performance/newTraceDetails/traceDrawer/details/missingInstrumentation.tsx b/static/app/views/performance/newTraceDetails/traceDrawer/details/missingInstrumentation.tsx index 140df3974b9168..ae10d061385459 100644 --- a/static/app/views/performance/newTraceDetails/traceDrawer/details/missingInstrumentation.tsx +++ b/static/app/views/performance/newTraceDetails/traceDrawer/details/missingInstrumentation.tsx @@ -1,8 +1,13 @@ +import {useMemo} from 'react'; + import {ExternalLink} from 'sentry/components/core/link'; +import LoadingError from 'sentry/components/loadingError'; +import LoadingIndicator from 'sentry/components/loadingIndicator'; import {t, tct} from 'sentry/locale'; import type {EventTransaction} from 'sentry/types/event'; import type {Project} from 'sentry/types/project'; import useProjects from 'sentry/utils/useProjects'; +import {useTransaction} from 'sentry/views/performance/newTraceDetails/traceApi/useTransaction'; import {getCustomInstrumentationLink} from 'sentry/views/performance/newTraceDetails/traceConfigurations'; import {ProfilePreview} from 'sentry/views/performance/newTraceDetails/traceDrawer/details/profiling/profilePreview'; import type {TraceTreeNodeDetailsProps} from 'sentry/views/performance/newTraceDetails/traceDrawer/tabs/traceTreeNodeDetails'; @@ -59,22 +64,39 @@ function EAPMissingInstrumentationNodeDetails({ }) { const {node} = props; const previous = node.previous as TraceTreeNode; - const parentEAPTransaction = TraceTree.ParentEAPTransaction(previous); - const project = parentEAPTransaction - ? projects.find(proj => proj.slug === parentEAPTransaction.value.project_slug) - : undefined; - const profileId = parentEAPTransaction?.value.profile_id || ''; - const profilerId = parentEAPTransaction?.value.profiler_id || ''; + const { + data: eventTransaction, + isLoading: isEventTransactionLoading, + isError: isEventTransactionError, + } = useTransaction({ + event_id: previous.value.transaction_id, + organization: props.organization, + project_slug: previous.value.project_slug, + }); + + const event = eventTransaction ?? null; + const profileMeta = useMemo(() => getProfileMeta(event) || '', [event]); + + if (isEventTransactionLoading) { + return ; + } + + if (isEventTransactionError) { + return ; + } + + const project = projects.find(proj => proj.slug === event?.projectSlug); + const profileContext = event?.contexts?.profile ?? {}; return ( ); } @@ -137,7 +159,7 @@ function BaseMissingInstrumentationNodeDetails({ profileID={profileId} profilerID={profilerId} event={event} - node={node} + missingInstrumentationNode={node} /> )} diff --git a/static/app/views/performance/newTraceDetails/traceDrawer/details/profiling/profilePreview.tsx b/static/app/views/performance/newTraceDetails/traceDrawer/details/profiling/profilePreview.tsx index c4227accb35501..c518584566a5bc 100644 --- a/static/app/views/performance/newTraceDetails/traceDrawer/details/profiling/profilePreview.tsx +++ b/static/app/views/performance/newTraceDetails/traceDrawer/details/profiling/profilePreview.tsx @@ -36,7 +36,7 @@ import {useProfiles} from 'sentry/views/profiling/profilesProvider'; interface SpanProfileProps { event: Readonly | null; - node: MissingInstrumentationNode; + missingInstrumentationNode: MissingInstrumentationNode; profileID: string | undefined; profilerID: string | undefined; project: Project | undefined; @@ -47,7 +47,7 @@ export function ProfilePreview({ profileID, profilerID, event, - node, + missingInstrumentationNode, }: SpanProfileProps) { const profiles = useProfiles(); const profileGroup = useProfileGroup(); @@ -56,9 +56,8 @@ export function ProfilePreview({ const [canvasView, setCanvasView] = useState | null>(null); const spanThreadId = useMemo(() => { - const value = node.previous.value ?? node.next.value ?? null; - return 'data' in value ? value.data?.['thread.id'] : null; - }, [node]); + return event?.contexts.trace?.data?.['thread.id'] ?? null; + }, [event]); const profile = useMemo(() => { if (defined(spanThreadId)) { @@ -75,10 +74,12 @@ export function ProfilePreview({ }, [profileGroup.profiles, profileGroup.activeProfileIndex, spanThreadId]); const transactionHasProfile = useMemo(() => { - return isEAPSpanNode(node.previous) - ? (TraceTree.ParentEAPTransaction(node)?.profiles?.length ?? 0) > 0 - : (TraceTree.ParentTransaction(node)?.profiles?.length ?? 0) > 0; - }, [node]); + return isEAPSpanNode(missingInstrumentationNode.previous) + ? (TraceTree.ParentEAPTransaction(missingInstrumentationNode)?.profiles?.length ?? + 0) > 0 + : (TraceTree.ParentTransaction(missingInstrumentationNode)?.profiles?.length ?? 0) > + 0; + }, [missingInstrumentationNode]); const flamegraph = useMemo(() => { if (!transactionHasProfile || !profile) { @@ -89,8 +90,8 @@ export function ProfilePreview({ }, [transactionHasProfile, profile]); const target = useMemo(() => { - if (defined(project?.slug)) { - if (defined(profileID)) { + if (project?.slug) { + if (profileID) { // we want to try to go straight to the same config view as the preview const query = canvasView?.configView ? { @@ -110,7 +111,7 @@ export function ProfilePreview({ }); } - if (defined(event) && defined(profilerID)) { + if (event && profilerID) { const query = { eventId: event.id, tid: spanThreadId, @@ -149,11 +150,11 @@ export function ProfilePreview({ const startTimestamp = profile?.timestamp ?? event?.startTimestamp; const relativeStartTimestamp = transactionHasProfile && defined(startTimestamp) - ? node.value.start_timestamp - startTimestamp + ? missingInstrumentationNode.value.start_timestamp - startTimestamp : 0; const relativeStopTimestamp = transactionHasProfile && defined(startTimestamp) - ? node.value.timestamp - startTimestamp + ? missingInstrumentationNode.value.timestamp - startTimestamp : flamegraph.configSpace.width; function handleGoToProfile() { @@ -167,7 +168,7 @@ export function ProfilePreview({ {t('Or, see if profiling can provide more context on this:')} ); - if (defined(target) && transactionHasProfile) { + if (target && transactionHasProfile) { return ( {message} From a6d452567bdfffe7834efa1893a1ccf20b33bfa1 Mon Sep 17 00:00:00 2001 From: Abdullah Khan Date: Mon, 4 Aug 2025 13:25:06 -0400 Subject: [PATCH 2/3] feat(trace-eap-waterfall): Addressing PR suggestions --- .../traceDrawer/details/missingInstrumentation.tsx | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/static/app/views/performance/newTraceDetails/traceDrawer/details/missingInstrumentation.tsx b/static/app/views/performance/newTraceDetails/traceDrawer/details/missingInstrumentation.tsx index ae10d061385459..10e2d94eb0517b 100644 --- a/static/app/views/performance/newTraceDetails/traceDrawer/details/missingInstrumentation.tsx +++ b/static/app/views/performance/newTraceDetails/traceDrawer/details/missingInstrumentation.tsx @@ -66,7 +66,7 @@ function EAPMissingInstrumentationNodeDetails({ const previous = node.previous as TraceTreeNode; const { - data: eventTransaction, + data: eventTransaction = null, isLoading: isEventTransactionLoading, isError: isEventTransactionError, } = useTransaction({ @@ -75,8 +75,10 @@ function EAPMissingInstrumentationNodeDetails({ project_slug: previous.value.project_slug, }); - const event = eventTransaction ?? null; - const profileMeta = useMemo(() => getProfileMeta(event) || '', [event]); + const profileMeta = useMemo( + () => getProfileMeta(eventTransaction) || '', + [eventTransaction] + ); if (isEventTransactionLoading) { return ; @@ -86,15 +88,15 @@ function EAPMissingInstrumentationNodeDetails({ return ; } - const project = projects.find(proj => proj.slug === event?.projectSlug); - const profileContext = event?.contexts?.profile ?? {}; + const project = projects.find(proj => proj.slug === eventTransaction?.projectSlug); + const profileContext = eventTransaction?.contexts?.profile ?? {}; return ( From f959558d9172c0b22864a422f1ee284a4a862216 Mon Sep 17 00:00:00 2001 From: Abdullah Khan Date: Tue, 5 Aug 2025 13:21:24 -0400 Subject: [PATCH 3/3] feat(trace-eap-waterfall): Addressing cursor comments --- .../traceDrawer/details/profiling/profilePreview.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/app/views/performance/newTraceDetails/traceDrawer/details/profiling/profilePreview.tsx b/static/app/views/performance/newTraceDetails/traceDrawer/details/profiling/profilePreview.tsx index c518584566a5bc..5f011e363cfaeb 100644 --- a/static/app/views/performance/newTraceDetails/traceDrawer/details/profiling/profilePreview.tsx +++ b/static/app/views/performance/newTraceDetails/traceDrawer/details/profiling/profilePreview.tsx @@ -56,7 +56,7 @@ export function ProfilePreview({ const [canvasView, setCanvasView] = useState | null>(null); const spanThreadId = useMemo(() => { - return event?.contexts.trace?.data?.['thread.id'] ?? null; + return event?.contexts?.trace?.data?.['thread.id'] ?? null; }, [event]); const profile = useMemo(() => {