Browse Source

ref(trace-view): Add additional details to trace view response (#24636)

The trace view endpoint supports adding additional details to the response. This
change adds support for it in the frontend.
Tony 4 years ago
parent
commit
1fd8ea4ad5

+ 1 - 1
src/sentry/static/sentry/app/utils/performance/quickTrace/quickTraceQuery.tsx

@@ -2,7 +2,7 @@ import React from 'react';
 
 import {Event} from 'app/types/event';
 import {DiscoverQueryProps} from 'app/utils/discover/genericDiscoverQuery';
-import TraceFullQuery from 'app/utils/performance/quickTrace/traceFullQuery';
+import {TraceFullQuery} from 'app/utils/performance/quickTrace/traceFullQuery';
 import TraceLiteQuery from 'app/utils/performance/quickTrace/traceLiteQuery';
 import {QuickTraceQueryChildrenProps} from 'app/utils/performance/quickTrace/types';
 import {

+ 50 - 14
src/sentry/static/sentry/app/utils/performance/quickTrace/traceFullQuery.tsx

@@ -1,9 +1,13 @@
 import React from 'react';
 
-import GenericDiscoverQuery from 'app/utils/discover/genericDiscoverQuery';
+import GenericDiscoverQuery, {
+  DiscoverQueryProps,
+} from 'app/utils/discover/genericDiscoverQuery';
 import {
+  BaseTraceChildrenProps,
+  FullQuickTrace,
   TraceFull,
-  TraceFullQueryChildrenProps,
+  TraceFullDetailed,
   TraceRequestProps,
 } from 'app/utils/performance/quickTrace/types';
 import {
@@ -13,11 +17,34 @@ import {
 } from 'app/utils/performance/quickTrace/utils';
 import withApi from 'app/utils/withApi';
 
-type QueryProps = Omit<TraceRequestProps, 'eventId' | 'eventView'> & {
-  children: (props: TraceFullQueryChildrenProps) => React.ReactNode;
+type AdditionalQueryProps = {
+  detailed?: boolean;
 };
 
-function EmptyTrace({children}: Pick<QueryProps, 'children'>) {
+type TraceFullQueryChildrenProps<T> = BaseTraceChildrenProps &
+  Omit<FullQuickTrace, 'trace'> & {
+    /**
+     * The `event-trace` endpoint returns a full trace with the parent-child
+     * relationships. It can be flattened into a `QuickTraceEvent` if necessary.
+     */
+    trace: T | null;
+  };
+
+type QueryProps<T> = Omit<TraceRequestProps, 'eventView'> &
+  AdditionalQueryProps & {
+    children: (props: TraceFullQueryChildrenProps<T>) => React.ReactNode;
+  };
+
+function getTraceFullRequestPayload({
+  detailed,
+  ...props
+}: DiscoverQueryProps & AdditionalQueryProps) {
+  const additionalApiPayload: any = getQuickTraceRequestPayload(props);
+  additionalApiPayload.detailed = detailed ? '1' : '0';
+  return additionalApiPayload;
+}
+
+function EmptyTrace<T>({children}: Pick<QueryProps<T>, 'children'>) {
   return (
     <React.Fragment>
       {children({
@@ -30,24 +57,24 @@ function EmptyTrace({children}: Pick<QueryProps, 'children'>) {
   );
 }
 
-function TraceFullQuery({
+function GenericTraceFullQuery<T>({
   traceId,
   start,
   end,
   statsPeriod,
   children,
   ...props
-}: QueryProps) {
+}: QueryProps<T>) {
   if (!traceId) {
-    return <EmptyTrace>{children}</EmptyTrace>;
+    return <EmptyTrace<T>>{children}</EmptyTrace>;
   }
 
   const eventView = makeEventView({start, end, statsPeriod});
 
   return (
-    <GenericDiscoverQuery<TraceFull, {}>
+    <GenericDiscoverQuery<T, AdditionalQueryProps>
       route={`events-trace/${traceId}`}
-      getRequestPayload={getQuickTraceRequestPayload}
+      getRequestPayload={getTraceFullRequestPayload}
       beforeFetch={beforeFetch}
       eventView={eventView}
       {...props}
@@ -58,9 +85,8 @@ function TraceFullQuery({
           // the client returns a empty string when the response
           // is 204. And we want the empty string, undefined and
           // null to be converted to null.
-          // TODO(wmak): replace once the backend starts returning arrays
-          // `(tableData || null)?.[0] ?? null,`
-          trace: (tableData || null)?.[0] ?? (tableData || null),
+          // TODO(tonyx): update to return the entire array
+          trace: (tableData || null)?.[0] ?? null,
           type: 'full',
           ...rest,
         })
@@ -69,4 +95,14 @@ function TraceFullQuery({
   );
 }
 
-export default withApi(TraceFullQuery);
+export const TraceFullQuery = withApi(
+  (props: Omit<QueryProps<TraceFull>, 'detailed'>) => (
+    <GenericTraceFullQuery<TraceFull> {...props} detailed={false} />
+  )
+);
+
+export const TraceFullDetailedQuery = withApi(
+  (props: Omit<QueryProps<TraceFullDetailed>, 'detailed'>) => (
+    <GenericTraceFullQuery<TraceFullDetailed> {...props} detailed />
+  )
+);

+ 19 - 8
src/sentry/static/sentry/app/utils/performance/quickTrace/traceLiteQuery.tsx

@@ -4,8 +4,9 @@ import GenericDiscoverQuery, {
   DiscoverQueryProps,
 } from 'app/utils/discover/genericDiscoverQuery';
 import {
+  BaseTraceChildrenProps,
+  PartialQuickTrace,
   TraceLite,
-  TraceLiteQueryChildrenProps,
   TraceRequestProps,
 } from 'app/utils/performance/quickTrace/types';
 import {
@@ -15,15 +16,25 @@ import {
 } from 'app/utils/performance/quickTrace/utils';
 import withApi from 'app/utils/withApi';
 
-type QueryProps = Omit<TraceRequestProps, 'eventView'> & {
-  children: (props: TraceLiteQueryChildrenProps) => React.ReactNode;
-  shouldSkipQuery: boolean;
+type AdditionalQueryProps = {
+  eventId: string;
 };
 
-function getQuickTraceLiteRequestPayload({
+type TraceLiteQueryChildrenProps = BaseTraceChildrenProps &
+  Omit<PartialQuickTrace, 'trace'> & {
+    trace: TraceLite | null;
+  };
+
+type QueryProps = Omit<TraceRequestProps, 'eventView'> &
+  AdditionalQueryProps & {
+    children: (props: TraceLiteQueryChildrenProps) => React.ReactNode;
+    shouldSkipQuery: boolean;
+  };
+
+function getTraceLiteRequestPayload({
   eventId,
   ...props
-}: DiscoverQueryProps & Pick<TraceRequestProps, 'eventId'>) {
+}: DiscoverQueryProps & AdditionalQueryProps) {
   const additionalApiPayload = getQuickTraceRequestPayload(props);
   return Object.assign({event_id: eventId}, additionalApiPayload);
 }
@@ -57,9 +68,9 @@ function TraceLiteQuery({
   const eventView = makeEventView({start, end, statsPeriod});
 
   return (
-    <GenericDiscoverQuery<TraceLite, {eventId: string}>
+    <GenericDiscoverQuery<TraceLite, AdditionalQueryProps>
       route={`events-trace-light/${traceId}`}
-      getRequestPayload={getQuickTraceLiteRequestPayload}
+      getRequestPayload={getTraceLiteRequestPayload}
       beforeFetch={beforeFetch}
       eventView={eventView}
       {...props}

+ 16 - 17
src/sentry/static/sentry/app/utils/performance/quickTrace/types.tsx

@@ -13,7 +13,6 @@ export type EventLite = {
   span_id: string;
   transaction: string;
   'transaction.duration': number;
-  'transaction.op': string;
   project_id: number;
   project_slug: string;
   parent_event_id: string | null;
@@ -38,6 +37,8 @@ export type QuickTraceEvent = EventLite & {
 /**
  * The `events-trace` endpoint returns a tree structure that gives
  * the parent-child relationships between events.
+ *
+ * This is the type returned with `detailed=0`
  */
 export type TraceFull = Omit<QuickTraceEvent, 'generation' | 'errors'> & {
   /**
@@ -46,12 +47,21 @@ export type TraceFull = Omit<QuickTraceEvent, 'generation' | 'errors'> & {
   children: TraceFull[];
   errors: TraceError[];
   generation: number;
+};
+
+/**
+ * The `events-trace` endpoint has a parameter to get
+ * additional information by setting `detailed=1`.
+ */
+export type TraceFullDetailed = Omit<TraceFull, 'children'> & {
+  children: TraceFullDetailed[];
   start_timestamp: number;
   timestamp: number;
+  'transaction.op': string;
+  'transaction.status': string;
 };
 
 export type TraceProps = {
-  eventId: string;
   traceId: string;
   start?: string;
   end?: string;
@@ -60,37 +70,26 @@ export type TraceProps = {
 
 export type TraceRequestProps = DiscoverQueryProps & TraceProps;
 
-type EmptyQuickTrace = {
+export type EmptyQuickTrace = {
   type: 'empty';
   trace: QuickTraceEvent[];
 };
 
-type PartialQuickTrace = {
+export type PartialQuickTrace = {
   type: 'partial';
   trace: QuickTraceEvent[] | null;
 };
 
-type FullQuickTrace = {
+export type FullQuickTrace = {
   type: 'full';
   trace: QuickTraceEvent[] | null;
 };
 
-type BaseTraceChildrenProps = Omit<
+export type BaseTraceChildrenProps = Omit<
   GenericChildrenProps<TraceProps>,
   'tableData' | 'pageLinks'
 >;
 
-export type TraceLiteQueryChildrenProps = BaseTraceChildrenProps & PartialQuickTrace;
-
-export type TraceFullQueryChildrenProps = BaseTraceChildrenProps &
-  Omit<FullQuickTrace, 'trace'> & {
-    /**
-     * The `event-trace` endpoint returns a full trace with the parent-child
-     * relationships. It can be flattened into a `QuickTraceEvent` if necessary.
-     */
-    trace: TraceFull | null;
-  };
-
 export type QuickTrace = EmptyQuickTrace | PartialQuickTrace | FullQuickTrace;
 
 export type QuickTraceQueryChildrenProps = BaseTraceChildrenProps & QuickTrace;

+ 8 - 7
src/sentry/static/sentry/app/utils/performance/quickTrace/utils.tsx

@@ -10,6 +10,7 @@ import {
   QuickTrace,
   QuickTraceEvent,
   TraceFull,
+  TraceFullDetailed,
   TraceLite,
 } from 'app/utils/performance/quickTrace/types';
 
@@ -98,7 +99,7 @@ export function flattenRelevantPaths(
 }
 
 function simplifyEvent(event: TraceFull): QuickTraceEvent {
-  return omit(event, ['children', 'start_timestamp', 'timestamp']);
+  return omit(event, ['children']);
 }
 
 type ParsedQuickTrace = {
@@ -254,8 +255,8 @@ export function makeEventView({
 }
 
 export function reduceTrace<T>(
-  trace: TraceFull,
-  visitor: (acc: T, e: TraceFull) => T,
+  trace: TraceFullDetailed,
+  visitor: (acc: T, e: TraceFullDetailed) => T,
   initialValue: T
 ): T {
   let result = initialValue;
@@ -281,10 +282,10 @@ export function getTraceTimeRangeFromEvent(event: Event): {start: string; end: s
 }
 
 export function filterTrace(
-  trace: TraceFull,
-  predicate: (transaction: TraceFull) => boolean
-): TraceFull[] {
-  return reduceTrace<TraceFull[]>(
+  trace: TraceFullDetailed,
+  predicate: (transaction: TraceFullDetailed) => boolean
+): TraceFullDetailed[] {
+  return reduceTrace<TraceFullDetailed[]>(
     trace,
     (transactions, transaction) => {
       if (predicate(transaction)) {

+ 5 - 5
src/sentry/static/sentry/app/views/performance/traceDetails/content.tsx

@@ -8,7 +8,7 @@ import LoadingError from 'app/components/loadingError';
 import LoadingIndicator from 'app/components/loadingIndicator';
 import {t, tct, tn} from 'app/locale';
 import {Organization} from 'app/types';
-import {TraceFull} from 'app/utils/performance/quickTrace/types';
+import {TraceFullDetailed} from 'app/utils/performance/quickTrace/types';
 import {filterTrace} from 'app/utils/performance/quickTrace/utils';
 import Breadcrumb from 'app/views/performance/breadcrumb';
 import {MetaData} from 'app/views/performance/transactionDetails/styles';
@@ -42,7 +42,7 @@ type Props = {
   statsPeriod: string | undefined;
   isLoading: boolean;
   error: string | null;
-  trace: TraceFull | null;
+  trace: TraceFullDetailed | null;
 };
 
 type State = {
@@ -115,7 +115,7 @@ class TraceDetailsContent extends React.Component<Props, State> {
     );
   }
 
-  isTransactionVisible = (transaction: TraceFull): boolean => {
+  isTransactionVisible = (transaction: TraceFullDetailed): boolean => {
     const {filteredTransactionIds} = this.state;
     return filteredTransactionIds
       ? filteredTransactionIds.has(transaction.event_id)
@@ -190,7 +190,7 @@ class TraceDetailsContent extends React.Component<Props, State> {
   }
 
   renderTransaction(
-    transaction: TraceFull,
+    transaction: TraceFullDetailed,
     {
       continuingDepths,
       isLast,
@@ -210,7 +210,7 @@ class TraceDetailsContent extends React.Component<Props, State> {
     const isVisible = this.isTransactionVisible(transaction);
 
     const accumulated: AccType = transaction.children.reduce(
-      (acc: AccType, child: TraceFull, idx: number) => {
+      (acc: AccType, child: TraceFullDetailed, idx: number) => {
         const isLastChild = idx === transaction.children.length - 1;
         const hasChildren = child.children.length > 0;
 

+ 13 - 4
src/sentry/static/sentry/app/views/performance/traceDetails/index.tsx

@@ -9,7 +9,8 @@ import SentryDocumentTitle from 'app/components/sentryDocumentTitle';
 import {t} from 'app/locale';
 import {PageContent} from 'app/styles/organization';
 import {Organization} from 'app/types';
-import TraceFullQuery from 'app/utils/performance/quickTrace/traceFullQuery';
+import {TraceFullDetailedQuery} from 'app/utils/performance/quickTrace/traceFullQuery';
+import {TraceFullDetailed} from 'app/utils/performance/quickTrace/types';
 import {decodeScalar} from 'app/utils/queryString';
 import withOrganization from 'app/utils/withOrganization';
 
@@ -39,7 +40,15 @@ class TraceSummary extends React.Component<Props> {
     const end = decodeScalar(queryParams.end);
     const statsPeriod = decodeScalar(queryParams.statsPeriod);
 
-    const content = ({isLoading, error, trace}) => (
+    const content = ({
+      isLoading,
+      error,
+      trace,
+    }: {
+      isLoading: boolean;
+      error: string | null;
+      trace: TraceFullDetailed | null;
+    }) => (
       <TraceDetailsContent
         location={location}
         organization={organization}
@@ -63,7 +72,7 @@ class TraceSummary extends React.Component<Props> {
     }
 
     return (
-      <TraceFullQuery
+      <TraceFullDetailedQuery
         location={location}
         orgSlug={organization.slug}
         traceId={traceSlug}
@@ -72,7 +81,7 @@ class TraceSummary extends React.Component<Props> {
         statsPeriod={statsPeriod}
       >
         {content}
-      </TraceFullQuery>
+      </TraceFullDetailedQuery>
     );
   }
 

+ 2 - 2
src/sentry/static/sentry/app/views/performance/traceDetails/transactionBar.tsx

@@ -6,7 +6,7 @@ import Count from 'app/components/count';
 import * as DividerHandlerManager from 'app/components/events/interfaces/spans/dividerHandlerManager';
 import ProjectBadge from 'app/components/idBadge/projectBadge';
 import {Organization} from 'app/types';
-import {TraceFull} from 'app/utils/performance/quickTrace/types';
+import {TraceFullDetailed} from 'app/utils/performance/quickTrace/types';
 import Projects from 'app/utils/projects';
 import {Theme} from 'app/utils/theme';
 
@@ -42,7 +42,7 @@ type Props = {
   location: Location;
   organization: Organization;
   index: number;
-  transaction: TraceFull;
+  transaction: TraceFullDetailed;
   traceInfo: TraceInfo;
   isLast: boolean;
   continuingDepths: Array<number>;

+ 2 - 2
src/sentry/static/sentry/app/views/performance/traceDetails/transactionDetail.tsx

@@ -15,7 +15,7 @@ import {Organization} from 'app/types';
 import EventView from 'app/utils/discover/eventView';
 import {eventDetailsRoute, generateEventSlug} from 'app/utils/discover/urls';
 import getDynamicText from 'app/utils/getDynamicText';
-import {TraceError, TraceFull} from 'app/utils/performance/quickTrace/types';
+import {TraceError, TraceFullDetailed} from 'app/utils/performance/quickTrace/types';
 import {QueryResults, stringifyQueryObject} from 'app/utils/tokenizeSearch';
 import {getTransactionDetailsUrl} from 'app/views/performance/utils';
 
@@ -24,7 +24,7 @@ import {Row, TransactionDetails, TransactionDetailsContainer} from './styles';
 type Props = {
   location: Location;
   organization: Organization;
-  transaction: TraceFull;
+  transaction: TraceFullDetailed;
 };
 
 class TransactionDetail extends React.Component<Props> {

+ 2 - 2
src/sentry/static/sentry/app/views/performance/traceDetails/transactionGroup.tsx

@@ -2,7 +2,7 @@ import React from 'react';
 import {Location} from 'history';
 
 import {Organization} from 'app/types';
-import {TraceFull} from 'app/utils/performance/quickTrace/types';
+import {TraceFullDetailed} from 'app/utils/performance/quickTrace/types';
 
 import TransactionBar from './transactionBar';
 import {TraceInfo} from './types';
@@ -10,7 +10,7 @@ import {TraceInfo} from './types';
 type Props = {
   location: Location;
   organization: Organization;
-  transaction: TraceFull;
+  transaction: TraceFullDetailed;
   traceInfo: TraceInfo;
   continuingDepths: Array<number>;
   isLast: boolean;

Some files were not shown because too many files changed in this diff