Browse Source

feat(starfish) Finish hooking the span summary panel to production data (#50663)

Major caveat is that the sample list lost the fast/slow/median sections
for now, I'll come back to this soon! I just need to get this thing
production-ready.
George Gritsouk 1 year ago
parent
commit
9f7c706b88

+ 14 - 15
static/app/views/starfish/components/samplesTable/spanSamplesTable.tsx

@@ -32,17 +32,18 @@ const COLUMN_ORDER: TableColumnHeader[] = [
 ];
 
 type SpanTableRow = {
-  exclusive_time: number;
-  p95Comparison: number;
-  'project.name': string;
-  spanDuration: number;
-  spanOp: string;
+  description: string;
+  duration: number;
+  op: string;
   span_id: string;
   timestamp: string;
-  transaction: string;
-  transactionDuration: number;
+  transaction: {
+    id: string;
+    'project.name': string;
+    timestamp: string;
+    'transaction.duration': number;
+  };
   transaction_id: string;
-  user: string;
 };
 
 type Props = {
@@ -70,9 +71,7 @@ export function SpanSamplesTable({isLoading, data, p95}: Props) {
     if (column.key === 'transaction_id') {
       return (
         <Link
-          to={`/performance/${row['project.name']}:${
-            row.transaction_id
-          }#span-${row.span_id.slice(19).replace('-', '')}`}
+          to={`/performance/${row.transaction['project.name']}:${row.transaction_id}#span-${row.span_id}`}
         >
           {row.transaction_id.slice(0, 8)}
         </Link>
@@ -82,15 +81,15 @@ export function SpanSamplesTable({isLoading, data, p95}: Props) {
     if (column.key === 'duration') {
       return (
         <SpanDurationBar
-          spanOp={row.spanOp}
-          spanDuration={row.spanDuration}
-          transactionDuration={row.transactionDuration}
+          spanOp={row.op}
+          spanDuration={row.duration}
+          transactionDuration={row.transaction['transaction.duration']}
         />
       );
     }
 
     if (column.key === 'p95_comparison') {
-      return <DurationComparisonCell duration={row.spanDuration} p95={p95} />;
+      return <DurationComparisonCell duration={row.duration} p95={p95} />;
     }
 
     if (column.key === 'timestamp') {

+ 3 - 0
static/app/views/starfish/queries/types.tsx

@@ -12,8 +12,11 @@ export type IndexedSpan = {
   action: string;
   description: string;
   domain: string;
+  duration: number;
   group: string;
   module: string;
   op: string;
   span_id: string;
+  timestamp: string;
+  transaction_id: string;
 };

+ 58 - 0
static/app/views/starfish/queries/useSpanSamples.tsx

@@ -0,0 +1,58 @@
+import {useDiscoverQuery} from 'sentry/utils/discover/discoverQuery';
+import EventView from 'sentry/utils/discover/eventView';
+import {DiscoverDatasets} from 'sentry/utils/discover/types';
+import {useLocation} from 'sentry/utils/useLocation';
+import useOrganization from 'sentry/utils/useOrganization';
+import type {IndexedSpan} from 'sentry/views/starfish/queries/types';
+
+const DEFAULT_LIMIT = 10;
+const DEFAULT_ORDER_BY = '-duration';
+
+export function useSpanSamples(
+  groupId?: string,
+  transaction?: string,
+  limit?: number,
+  orderBy?: string,
+  referrer: string = 'use-span-samples'
+) {
+  const location = useLocation();
+  const organization = useOrganization();
+
+  const eventView = EventView.fromNewQueryWithLocation(
+    {
+      name: 'Span Samples',
+      query: `${groupId ? ` group:${groupId}` : ''} ${
+        transaction ? ` transaction:${transaction}` : ''
+      }`,
+      fields: [
+        'span_id',
+        'group',
+        'action',
+        'description',
+        'domain',
+        'module',
+        'duration',
+        'op',
+        'transaction_id',
+        'timestamp',
+      ],
+      dataset: DiscoverDatasets.SPANS_INDEXED,
+      orderby: orderBy ?? DEFAULT_ORDER_BY,
+      projects: [1],
+      version: 2,
+    },
+    location
+  );
+
+  const response = useDiscoverQuery({
+    eventView,
+    orgSlug: organization.slug,
+    location,
+    referrer,
+    limit: limit ?? DEFAULT_LIMIT,
+  });
+
+  const data = (response.data?.data ?? []) as unknown as IndexedSpan[];
+
+  return {...response, data};
+}

+ 35 - 0
static/app/views/starfish/queries/useTransactions.tsx

@@ -0,0 +1,35 @@
+import {useDiscoverQuery} from 'sentry/utils/discover/discoverQuery';
+import EventView from 'sentry/utils/discover/eventView';
+import {useLocation} from 'sentry/utils/useLocation';
+import useOrganization from 'sentry/utils/useOrganization';
+
+type Transaction = {
+  id: string;
+  'project.name': string;
+  timestamp: string;
+  'transaction.duration': number;
+};
+
+export function useTransactions(eventIDs: string[], referrer = 'use-transactions') {
+  const location = useLocation();
+  const {slug} = useOrganization();
+
+  const eventView = EventView.fromNewQueryWithLocation(
+    {
+      fields: ['id', 'timestamp', 'project.name', 'transaction.duration'],
+      name: 'Transactions',
+      projects: [1],
+      version: 2,
+      query: `id:[${eventIDs.join(',')}]`,
+    },
+    location
+  );
+
+  const response = useDiscoverQuery({eventView, location, orgSlug: slug, referrer});
+  const data = (response.data?.data ?? []) as unknown as Transaction[];
+
+  return {
+    ...response,
+    data,
+  };
+}

+ 1 - 1
static/app/views/starfish/views/spanSummaryPage/index.tsx

@@ -17,7 +17,7 @@ import ThroughputCell from 'sentry/views/starfish/components/tableCells/throughp
 import {TimeSpentCell} from 'sentry/views/starfish/components/tableCells/timeSpentCell';
 import {useIndexedSpan} from 'sentry/views/starfish/queries/useIndexedSpan';
 import {useSpanMetrics} from 'sentry/views/starfish/queries/useSpanMetrics';
-import SampleList from 'sentry/views/starfish/views/spanSummaryPage/sampleList';
+import {SampleList} from 'sentry/views/starfish/views/spanSummaryPage/sampleList';
 import {SpanBaselineTable} from 'sentry/views/starfish/views/spanSummaryPage/spanBaselineTable';
 import {SpanTransactionsTable} from 'sentry/views/starfish/views/spanSummaryPage/spanTransactionsTable';
 

+ 32 - 24
static/app/views/starfish/views/spanSummaryPage/sampleList/durationChart/index.tsx

@@ -1,10 +1,13 @@
+import {Fragment} from 'react';
 import {useTheme} from '@emotion/react';
+import moment from 'moment';
 
 import {Series} from 'sentry/types/echarts';
 import {P95_COLOR} from 'sentry/views/starfish/colours';
 import Chart from 'sentry/views/starfish/components/chart';
 import {useSpanMetricsSeries} from 'sentry/views/starfish/queries/useSpanMetricsSeries';
-import {useQueryGetSpanTransactionSamples} from 'sentry/views/starfish/views/spanSummaryPage/sampleList/queries';
+import {useSpanSamples} from 'sentry/views/starfish/queries/useSpanSamples';
+import {DataTitles} from 'sentry/views/starfish/views/spans/types';
 
 type Props = {
   groupId: string;
@@ -22,41 +25,46 @@ function DurationChart({groupId, transactionName}: Props) {
     'sidebar-span-metrics'
   );
 
-  const {data: sampleListData, isLoading: isSamplesLoading} =
-    useQueryGetSpanTransactionSamples({
-      groupId,
-      transactionName,
-    });
+  const {data: spans, isLoading: areSpanSamplesLoading} = useSpanSamples(
+    groupId,
+    transactionName,
+    undefined,
+    '-duration',
+    'span-summary-panel-samples-table-spans'
+  );
 
-  const sampledSpanDataSeries: Series[] = sampleListData.map(
-    ({timestamp, spanDuration, transaction_id}) => ({
+  const sampledSpanDataSeries: Series[] = spans.map(
+    ({timestamp, duration, transaction_id}) => ({
       data: [
         {
-          name: timestamp,
-          value: spanDuration,
+          name: moment(timestamp).unix(),
+          value: duration,
         },
       ],
       symbol: 'path://M -1 -1 V -5 H 0 V -1 H 4 V 0 H 0 V 4 H -1 V 0 H -5 V -1 H -1',
       color: theme.gray400,
       symbolSize: 15,
-      seriesName: transaction_id.split('-')[0],
+      seriesName: transaction_id,
     })
   );
 
   return (
-    <Chart
-      statsPeriod="24h"
-      height={140}
-      data={[spanMetricsSeriesData?.['p95(span.duration)']]}
-      start=""
-      end=""
-      loading={isLoading}
-      scatterPlot={isSamplesLoading ? undefined : sampledSpanDataSeries}
-      utc={false}
-      chartColors={[P95_COLOR]}
-      isLineChart
-      definedAxisTicks={4}
-    />
+    <Fragment>
+      <h5>{DataTitles.p95}</h5>
+      <Chart
+        statsPeriod="24h"
+        height={140}
+        data={[spanMetricsSeriesData?.['p95(span.duration)']]}
+        start=""
+        end=""
+        loading={isLoading}
+        scatterPlot={areSpanSamplesLoading ? undefined : sampledSpanDataSeries}
+        utc={false}
+        chartColors={[P95_COLOR]}
+        isLineChart
+        definedAxisTicks={4}
+      />
+    </Fragment>
   );
 }
 

+ 5 - 11
static/app/views/starfish/views/spanSummaryPage/sampleList/index.tsx

@@ -2,7 +2,6 @@ import omit from 'lodash/omit';
 
 import useRouter from 'sentry/utils/useRouter';
 import DetailPanel from 'sentry/views/starfish/components/detailPanel';
-import {DataTitles} from 'sentry/views/starfish/views/spans/types';
 import DurationChart from 'sentry/views/starfish/views/spanSummaryPage/sampleList/durationChart';
 import SampleInfo from 'sentry/views/starfish/views/spanSummaryPage/sampleList/sampleInfo';
 import SampleTable from 'sentry/views/starfish/views/spanSummaryPage/sampleList/sampleTable/sampleTable';
@@ -10,10 +9,9 @@ import SampleTable from 'sentry/views/starfish/views/spanSummaryPage/sampleList/
 type Props = {
   groupId: string;
   transactionName: string;
-  spanDescription?: string;
 };
 
-function SampleList({groupId, transactionName, spanDescription}: Props) {
+export function SampleList({groupId, transactionName}: Props) {
   const router = useRouter();
 
   return (
@@ -27,16 +25,12 @@ function SampleList({groupId, transactionName, spanDescription}: Props) {
       }}
     >
       <h3>{transactionName}</h3>
+
       <SampleInfo groupId={groupId} transactionName={transactionName} />
-      <h5>{DataTitles.p95}</h5>
-      <DurationChart
-        groupId={groupId}
-        transactionName={transactionName}
-        spanDescription={spanDescription}
-      />
+
+      <DurationChart groupId={groupId} transactionName={transactionName} />
+
       <SampleTable groupId={groupId} transactionName={transactionName} />
     </DetailPanel>
   );
 }
-
-export default SampleList;

+ 35 - 9
static/app/views/starfish/views/spanSummaryPage/sampleList/sampleTable/sampleTable.tsx

@@ -1,6 +1,9 @@
+import keyBy from 'lodash/keyBy';
+
 import {SpanSamplesTable} from 'sentry/views/starfish/components/samplesTable/spanSamplesTable';
-import {useQuerySpansInTransaction} from 'sentry/views/starfish/views/spanSummaryPage/queries';
-import {useQueryGetSpanTransactionSamples} from 'sentry/views/starfish/views/spanSummaryPage/sampleList/queries';
+import {useSpanMetrics} from 'sentry/views/starfish/queries/useSpanMetrics';
+import {useSpanSamples} from 'sentry/views/starfish/queries/useSpanSamples';
+import {useTransactions} from 'sentry/views/starfish/queries/useTransactions';
 
 type Props = {
   groupId: string;
@@ -9,17 +12,40 @@ type Props = {
 };
 
 function SampleTable({groupId, transactionName}: Props) {
-  const {data} = useQuerySpansInTransaction({
-    groupId,
-  });
-  const p95 = data[0]?.p95 ?? 0;
+  const {data: spanMetrics} = useSpanMetrics(
+    {group: groupId},
+    {transactionName},
+    ['p95(span.duration)'],
+    'span-summary-panel-samples-table-p95'
+  );
 
-  const {data: sampleListData, isLoading} = useQueryGetSpanTransactionSamples({
+  const {data: spans, isLoading: areSpanSamplesLoading} = useSpanSamples(
     groupId,
     transactionName,
-  });
+    undefined,
+    '-duration',
+    'span-summary-panel-samples-table-spans'
+  );
+
+  const {data: transactions, isLoading: areTransactionsLoading} = useTransactions(
+    spans.map(span => span.transaction_id),
+    'span-summary-panel-samples-table-transactions'
+  );
+
+  const transactionsById = keyBy(transactions, 'id');
 
-  return <SpanSamplesTable data={sampleListData} isLoading={isLoading} p95={p95} />;
+  return (
+    <SpanSamplesTable
+      data={spans.map(sample => {
+        return {
+          ...sample,
+          transaction: transactionsById[sample.transaction_id],
+        };
+      })}
+      isLoading={areSpanSamplesLoading || areTransactionsLoading}
+      p95={spanMetrics?.['p95(span.duration)']}
+    />
+  );
 }
 
 export default SampleTable;