Skip to content

feat(tracing-without-performance): Replay compatibility and ui improvements. #54700

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Aug 15, 2023
Merged
Show file tree
Hide file tree
Changes from 4 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
19 changes: 5 additions & 14 deletions static/app/views/performance/traceDetails/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,16 @@ import {QueryError} from 'sentry/utils/discover/genericDiscoverQuery';
import {TraceFullDetailedQuery} from 'sentry/utils/performance/quickTrace/traceFullQuery';
import TraceMetaQuery from 'sentry/utils/performance/quickTrace/traceMetaQuery';
import {
TraceError,
TraceFullDetailed,
TraceMeta,
TraceSplitResults,
} from 'sentry/utils/performance/quickTrace/types';
import {isTraceSplitResult} from 'sentry/utils/performance/quickTrace/utils';
import {decodeScalar} from 'sentry/utils/queryString';
import withApi from 'sentry/utils/withApi';
import withOrganization from 'sentry/utils/withOrganization';

import TraceDetailsContent from './content';
import {getTraceSplitResults} from './utils';

type Props = RouteComponentProps<{traceSlug: string}, {}> & {
api: Client;
Expand Down Expand Up @@ -87,18 +86,10 @@ class TraceSummary extends Component<Props> {
meta: TraceMeta | null;
traces: (TraceFullDetailed[] | TraceSplitResults<TraceFullDetailed>) | null;
}) => {
let transactions: TraceFullDetailed[] | undefined;
let orphanErrors: TraceError[] | undefined;
if (
traces &&
organization.features.includes('performance-tracing-without-performance') &&
isTraceSplitResult<TraceSplitResults<TraceFullDetailed>, TraceFullDetailed[]>(
traces
)
) {
orphanErrors = traces.orphan_errors;
transactions = traces.transactions;
}
const {transactions, orphanErrors} = getTraceSplitResults<TraceFullDetailed>(
traces ?? [],
organization
);

return (
<TraceDetailsContent
Expand Down
119 changes: 84 additions & 35 deletions static/app/views/performance/traceDetails/traceView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
boundsGenerator,
getMeasurements,
} from 'sentry/components/events/interfaces/spans/utils';
import Panel from 'sentry/components/panels/panel';
import {MessageRow} from 'sentry/components/performance/waterfall/messageRow';
import {
DividerSpacer,
Expand All @@ -18,7 +19,7 @@ import {
VirtualScrollbarGrip,
} from 'sentry/components/performance/waterfall/miniHeader';
import {pickBarColor, toPercent} from 'sentry/components/performance/waterfall/utils';
import {tct} from 'sentry/locale';
import {t, tct} from 'sentry/locale';
import {Organization} from 'sentry/types';
import {trackAnalytics} from 'sentry/utils/analytics';
import EventView from 'sentry/utils/discover/eventView';
Expand All @@ -29,7 +30,6 @@ import {
} from 'sentry/utils/performance/quickTrace/types';
import {
TraceDetailBody,
TracePanel,
TraceViewContainer,
TraceViewHeaderContainer,
} from 'sentry/views/performance/traceDetails/styles';
Expand Down Expand Up @@ -64,24 +64,50 @@ type Props = Pick<RouteComponentProps<{}, {}>, 'location'> & {
function TraceHiddenMessage({
isVisible,
numberOfHiddenTransactionsAbove,
numberOfHiddenErrorsAbove,
}: {
isVisible: boolean;
numberOfHiddenErrorsAbove: number;
numberOfHiddenTransactionsAbove: number;
}) {
if (!isVisible || numberOfHiddenTransactionsAbove < 1) {
if (
!isVisible ||
(numberOfHiddenTransactionsAbove < 1 && numberOfHiddenErrorsAbove < 1)
) {
return null;
}

const numOfTransaction = <strong>{numberOfHiddenTransactionsAbove}</strong>;
const numOfErrors = <strong>{numberOfHiddenErrorsAbove}</strong>;

const hiddenTransactionsMessage =
numberOfHiddenTransactionsAbove < 1
? ''
: numberOfHiddenTransactionsAbove === 1
? tct('[numOfTransaction] hidden transaction', {
numOfTransaction,
})
: tct('[numOfTransaction] hidden transactions', {
numOfTransaction,
});

const hiddenErrorsMessage =
numberOfHiddenErrorsAbove < 1
? ''
: numberOfHiddenErrorsAbove === 1
? tct('[numOfErrors] hidden error', {
numOfErrors,
})
: tct('[numOfErrors] hidden errors', {
numOfErrors,
});

return (
<MessageRow>
<span key="trace-info-message">
{numberOfHiddenTransactionsAbove === 1
? tct('[numOfTransaction] hidden transaction', {
numOfTransaction: <strong>{numberOfHiddenTransactionsAbove}</strong>,
})
: tct('[numOfTransaction] hidden transactions', {
numOfTransaction: <strong>{numberOfHiddenTransactionsAbove}</strong>,
})}
{hiddenTransactionsMessage}
{hiddenErrorsMessage && hiddenTransactionsMessage && t(' and ')}
{hiddenErrorsMessage}
</span>
</MessageRow>
);
Expand Down Expand Up @@ -193,6 +219,7 @@ export default function TraceView({
<TraceHiddenMessage
isVisible={isVisible}
numberOfHiddenTransactionsAbove={numberOfHiddenTransactionsAbove}
numberOfHiddenErrorsAbove={0}
/>
<TransactionGroup
location={location}
Expand Down Expand Up @@ -283,33 +310,53 @@ export default function TraceView({
);

// Build transaction groups for orphan errors
let numOfHiddenErrorsAbove = 0;
let totalNumOfHiddenErrors = 0;
if (hasOrphanErrors) {
orphanErrors.forEach((error, index) => {
const isLastError = index === orphanErrors.length - 1;
const isVisible = isRowVisible(error, filteredEventIds);
const currentHiddenCount = numOfHiddenErrorsAbove;

if (!isVisible) {
numOfHiddenErrorsAbove += 1;
totalNumOfHiddenErrors += 1;
} else {
numOfHiddenErrorsAbove = 0;
}

transactionGroups.push(
<TransactionGroup
key={error.event_id}
location={location}
organization={organization}
traceInfo={traceInfo}
transaction={{
...error,
generation: 1,
}}
generateBounds={generateBounds(traceInfo)}
measurements={
traces && traces.length > 0
? getMeasurements(traces[0], generateBounds(traceInfo))
: undefined
}
continuingDepths={[]}
isOrphan
isLast={isLastError}
index={lastIndex + index + 1}
isVisible={isRowVisible(error, filteredEventIds)}
hasGuideAnchor
renderedChildren={[]}
/>
<React.Fragment key={error.event_id}>
<TraceHiddenMessage
isVisible={isVisible}
numberOfHiddenTransactionsAbove={
index === 0 ? numberOfHiddenTransactionsAbove : 0
}
numberOfHiddenErrorsAbove={index > 0 ? currentHiddenCount : 0}
/>
<TransactionGroup
location={location}
organization={organization}
traceInfo={traceInfo}
transaction={{
...error,
generation: 1,
}}
generateBounds={generateBounds(traceInfo)}
measurements={
traces && traces.length > 0
? getMeasurements(traces[0], generateBounds(traceInfo))
: undefined
}
continuingDepths={[]}
isOrphan
isLast={isLastError}
index={lastIndex + index + 1}
isVisible={isVisible}
hasGuideAnchor
renderedChildren={[]}
/>
</React.Fragment>
);
});
}
Expand Down Expand Up @@ -399,6 +446,7 @@ export default function TraceView({
<TraceHiddenMessage
isVisible
numberOfHiddenTransactionsAbove={numberOfHiddenTransactionsAbove}
numberOfHiddenErrorsAbove={totalNumOfHiddenErrors}
/>
<LimitExceededMessage
traceInfo={traceInfo}
Expand All @@ -420,8 +468,9 @@ export default function TraceView({
return traceView;
}

const StyledTracePanel = styled(TracePanel)`
overflow: visible;
export const StyledTracePanel = styled(Panel)`
height: 100%;
overflow-x: visible;

${TraceViewContainer} {
overflow-x: visible;
Expand Down
31 changes: 27 additions & 4 deletions static/app/views/performance/traceDetails/utils.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import {LocationDescriptor, Query} from 'history';

import {PAGE_URL_PARAM} from 'sentry/constants/pageFilters';
import {OrganizationSummary} from 'sentry/types';
import {TraceError, TraceFullDetailed} from 'sentry/utils/performance/quickTrace/types';
import {reduceTrace} from 'sentry/utils/performance/quickTrace/utils';
import {Organization, OrganizationSummary} from 'sentry/types';
import {
TraceError,
TraceFull,
TraceFullDetailed,
TraceSplitResults,
} from 'sentry/utils/performance/quickTrace/types';
import {isTraceSplitResult, reduceTrace} from 'sentry/utils/performance/quickTrace/utils';

import {TraceInfo} from './types';

Expand Down Expand Up @@ -50,14 +55,32 @@ function transactionVisitor() {
}

export function hasTraceData(
traces: TraceFullDetailed[] | null,
traces: TraceFullDetailed[] | null | undefined,
orphanErrors: TraceError[] | undefined
): boolean {
return Boolean(
(traces && traces.length > 0) || (orphanErrors && orphanErrors.length > 0)
);
}

export function getTraceSplitResults<U extends TraceFullDetailed | TraceFull>(
trace: TraceSplitResults<U> | U[],
organization: Organization
) {
let transactions: U[] | undefined;
let orphanErrors: TraceError[] | undefined;
if (
trace &&
organization.features.includes('performance-tracing-without-performance') &&
isTraceSplitResult<TraceSplitResults<U>, U[]>(trace)
) {
orphanErrors = trace.orphan_errors;
transactions = trace.transactions;
}

return {transactions, orphanErrors};
}

export function getTraceInfo(
traces: TraceFullDetailed[] = [],
orphanErrors: TraceError[] = []
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,18 @@ import type {TableData} from 'sentry/utils/discover/discoverQuery';
import EventView from 'sentry/utils/discover/eventView';
import {doDiscoverQuery} from 'sentry/utils/discover/genericDiscoverQuery';
import parseLinkHeader, {ParsedHeader} from 'sentry/utils/parseLinkHeader';
import {TraceFullDetailed} from 'sentry/utils/performance/quickTrace/types';
import {
TraceError,
TraceFullDetailed,
TraceSplitResults,
} from 'sentry/utils/performance/quickTrace/types';
import {
getTraceRequestPayload,
makeEventView,
} from 'sentry/utils/performance/quickTrace/utils';
import useApi from 'sentry/utils/useApi';
import useOrganization from 'sentry/utils/useOrganization';
import {getTraceSplitResults} from 'sentry/views/performance/traceDetails/utils';
import type {ReplayRecord} from 'sentry/views/replays/types';

type Options = {
Expand All @@ -38,13 +43,15 @@ type InternalState = {
indexError: undefined | Error;
isFetching: boolean;
traces: undefined | TraceFullDetailed[];
orphanErrors?: TraceError[];
};

type ExternalState = {
didInit: boolean;
errors: Error[];
isFetching: boolean;
traces: undefined | TraceFullDetailed[];
orphanErrors?: TraceError[];
};

const INITIAL_STATE: InternalState = {
Expand All @@ -56,6 +63,7 @@ const INITIAL_STATE: InternalState = {
indexError: undefined,
isFetching: false,
traces: undefined,
orphanErrors: undefined,
};

type TxnContextProps = {
Expand Down Expand Up @@ -111,27 +119,36 @@ function ReplayTransactionContext({children, replayRecord}: Options) {
const fetchSingleTraceData = useCallback(
async traceId => {
try {
const [trace, , _traceResp] = await doDiscoverQuery(
api,
`/organizations/${orgSlug}/events-trace/${traceId}/`,
singleTracePayload
const [trace, _traceResp] = await doDiscoverQuery<
TraceSplitResults<TraceFullDetailed> | TraceFullDetailed[]
>(api, `/organizations/${orgSlug}/events-trace/${traceId}/`, singleTracePayload);

const {transactions, orphanErrors} = getTraceSplitResults<TraceFullDetailed>(
trace,
organization
);

setState(prev => ({
...prev,
traces: sortBy(
(prev.traces || []).concat(trace as TraceFullDetailed),
'start_timestamp'
),
}));
setState(prev => {
return {
...prev,
traces: sortBy(
(prev.traces || []).concat(transactions ?? (trace as TraceFullDetailed[])),
'start_timestamp'
),
orphanErrors: sortBy(
(prev.orphanErrors || []).concat(orphanErrors ?? []),
'timestamp'
),
};
});
} catch (error) {
setState(prev => ({
...prev,
detailsErrors: prev.detailsErrors.concat(error),
}));
}
},
[api, orgSlug, singleTracePayload]
[api, orgSlug, singleTracePayload, organization]
);

const fetchTransactionData = useCallback(async () => {
Expand Down Expand Up @@ -229,6 +246,7 @@ function internalToExternalState({
indexComplete,
indexError,
traces,
orphanErrors,
}: InternalState): ExternalState {
const isComplete = indexComplete && detailsRequests === detailsResponses;

Expand All @@ -237,6 +255,7 @@ function internalToExternalState({
errors: indexError ? [indexError] : [], // Ignoring detailsErrors for now
isFetching: !isComplete,
traces,
orphanErrors,
};
}

Expand Down
Loading