Skip to content

Commit

Permalink
feat(issues): Make new trace view available to issues ui users (#81646)
Browse files Browse the repository at this point in the history
  • Loading branch information
scttcper authored Dec 10, 2024
1 parent fff0b74 commit 91ce436
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ window.ResizeObserver = ResizeObserver;
describe('EventTraceView', () => {
const traceId = 'this-is-a-good-trace-id';
const {organization, project} = initializeData({
features: ['profiling', 'issue-details-always-show-trace'],
features: ['profiling'],
});
const group = GroupFixture();
const event = EventFixture({
Expand Down Expand Up @@ -103,6 +103,32 @@ describe('EventTraceView', () => {
});

it('still renders trace link for performance issues', async () => {
const oneOtherIssueEvent: TraceEventResponse = {
data: [
{
// In issuePlatform, the message contains the title and the transaction
message: '/api/slow/ Slow DB Query SELECT "sentry_monitorcheckin"."monitor_id"',
timestamp: '2024-01-24T09:09:03+00:00',
'issue.id': 1000,
project: project.slug,
'project.name': project.name,
title: 'Slow DB Query',
id: 'abc',
transaction: 'n/a',
culprit: '/api/slow/',
'event.type': '',
},
],
meta: {fields: {}, units: {}},
};
MockApiClient.addMockResponse({
url: `/organizations/${organization.slug}/events/`,
body: oneOtherIssueEvent,
});
MockApiClient.addMockResponse({
url: `/organizations/${organization.slug}/projects/`,
body: [],
});
const perfGroup = GroupFixture({issueCategory: IssueCategory.PERFORMANCE});
const perfEvent = EventFixture({
occurrence: {
Expand All @@ -129,6 +155,9 @@ describe('EventTraceView', () => {
expect(
await screen.findByRole('link', {name: 'View Full Trace'})
).toBeInTheDocument();
expect(
screen.getByText('One other issue appears in the same trace.')
).toBeInTheDocument();
});

it('does not render the trace preview if it has no transactions', async () => {
Expand All @@ -154,8 +183,5 @@ describe('EventTraceView', () => {
render(<EventTraceView group={group} event={event} organization={organization} />);

expect(await screen.findByText('Trace')).toBeInTheDocument();
expect(
await screen.findByRole('link', {name: 'View Full Trace'})
).toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
import {useMemo} from 'react';
import {Fragment, useMemo} from 'react';
import styled from '@emotion/styled';

import {LinkButton} from 'sentry/components/button';
import Link from 'sentry/components/links/link';
import {generateTraceTarget} from 'sentry/components/quickTrace/utils';
import {IconOpen} from 'sentry/icons';
import {t} from 'sentry/locale';
import {space} from 'sentry/styles/space';
import type {Event} from 'sentry/types/event';
import {type Group, IssueCategory} from 'sentry/types/group';
import type {Organization} from 'sentry/types/organization';
import useRouteAnalyticsParams from 'sentry/utils/routeAnalytics/useRouteAnalyticsParams';
import {useLocation} from 'sentry/utils/useLocation';
import useOrganization from 'sentry/utils/useOrganization';
import {SectionKey} from 'sentry/views/issueDetails/streamline/context';
import {InterimSection} from 'sentry/views/issueDetails/streamline/interimSection';
import {TraceDataSection} from 'sentry/views/issueDetails/traceDataSection';
import {TraceIssueEvent} from 'sentry/views/issueDetails/traceTimeline/traceIssue';
import {useTraceTimelineEvents} from 'sentry/views/issueDetails/traceTimeline/useTraceTimelineEvents';
import {IssuesTraceWaterfall} from 'sentry/views/performance/newTraceDetails/issuesTraceWaterfall';
import {useIssuesTraceTree} from 'sentry/views/performance/newTraceDetails/traceApi/useIssuesTraceTree';
import {useTrace} from 'sentry/views/performance/newTraceDetails/traceApi/useTrace';
Expand Down Expand Up @@ -128,16 +131,47 @@ function IssuesTraceOverlay({event}: {event: Event}) {

return (
<IssuesTraceOverlayContainer>
<LinkButton
size="sm"
icon={<IconOpen />}
aria-label={t('Open Trace')}
to={traceTarget}
/>
<LinkButton size="sm" icon={<IconOpen />} to={traceTarget}>
{t('View Full Trace')}
</LinkButton>
</IssuesTraceOverlayContainer>
);
}

function OneOtherIssueEvent({event}: {event: Event}) {
const location = useLocation();
const organization = useOrganization();
const {isLoading, oneOtherIssueEvent} = useTraceTimelineEvents({event});
useRouteAnalyticsParams(oneOtherIssueEvent ? {has_related_trace_issue: true} : {});

if (isLoading || !oneOtherIssueEvent) {
return null;
}

const traceTarget = generateTraceTarget(
event,
organization,
{
...location,
query: {
...location.query,
groupId: event.groupID,
},
},
TraceViewSources.ISSUE_DETAILS
);

return (
<Fragment>
<span>
{t('One other issue appears in the same trace. ')}
<Link to={traceTarget}>{t('View Full Trace')}</Link>
</span>
<TraceIssueEvent event={oneOtherIssueEvent} />
</Fragment>
);
}

const IssuesTraceContainer = styled('div')`
position: relative;
`;
Expand Down Expand Up @@ -165,18 +199,14 @@ export function EventTraceView({group, event, organization}: EventTraceViewProps
}

const hasProfilingFeature = organization.features.includes('profiling');
const hasIssueDetailsTrace = organization.features.includes(
'issue-details-always-show-trace'
);
const hasTracePreviewFeature =
hasProfilingFeature &&
hasIssueDetailsTrace &&
// Only display this for error or default events since performance events are handled elsewhere
group.issueCategory !== IssueCategory.PERFORMANCE;

return (
<InterimSection type={SectionKey.TRACE} title={t('Trace')}>
<TraceDataSection event={event} />
<OneOtherIssueEvent event={event} />
{hasTracePreviewFeature && (
<EventTraceViewInner
event={event}
Expand Down
9 changes: 8 additions & 1 deletion static/app/views/issueDetails/traceDataSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,17 @@ import {t} from 'sentry/locale';
import {space} from 'sentry/styles/space';
import type {Event} from 'sentry/types/event';
import useRouteAnalyticsParams from 'sentry/utils/routeAnalytics/useRouteAnalyticsParams';
import {useHasStreamlinedUI} from 'sentry/views/issueDetails/utils';

import {TraceIssueEvent} from './traceTimeline/traceIssue';
import {TraceLink} from './traceTimeline/traceLink';
import {TraceTimeline} from './traceTimeline/traceTimeline';
import {useTraceTimelineEvents} from './traceTimeline/useTraceTimelineEvents';

export function TraceDataSection({event}: {event: Event}) {
const hasStreamlinedUI = useHasStreamlinedUI();
// This is also called within the TraceTimeline component but caching will save a second call
const {isLoading, oneOtherIssueEvent} = useTraceTimelineEvents({
const {isLoading, oneOtherIssueEvent, traceEvents} = useTraceTimelineEvents({
event,
});
let params: Record<string, boolean> = {};
Expand All @@ -28,6 +30,11 @@ export function TraceDataSection({event}: {event: Event}) {
return null;
}

const noEvents = !isLoading && traceEvents.length === 0;
if (hasStreamlinedUI && (!oneOtherIssueEvent || noEvents)) {
return null;
}

return (
<Fragment>
<StyledTraceLink>
Expand Down

0 comments on commit 91ce436

Please sign in to comment.