Browse Source

feat(starfish) Add span summary page charts (#50666)

- Dump span baseline table
- Add throughput and duration charts
George Gritsouk 1 year ago
parent
commit
3983c234c2

+ 6 - 4
static/app/views/starfish/components/chartPanel.tsx

@@ -14,10 +14,12 @@ export default function ChartPanel({title, children, button}: Props) {
   return (
     <Panel>
       <PanelBody withPadding>
-        <Header>
-          {title && <ChartLabel>{title}</ChartLabel>}
-          {button}
-        </Header>
+        {title && (
+          <Header>
+            {title && <ChartLabel>{title}</ChartLabel>}
+            {button}
+          </Header>
+        )}
         {children}
       </PanelBody>
     </Panel>

+ 1 - 2
static/app/views/starfish/components/formattedCode.tsx

@@ -4,8 +4,7 @@ import {space} from 'sentry/styles/space';
 
 export const FormattedCode = styled('div')`
   padding: ${space(1)};
-  margin-bottom: ${space(3)};
   border-radius: ${p => p.theme.borderRadius};
   overflow-x: auto;
-  white-space: pre;
+  white-space: pre-wrap;
 `;

+ 71 - 3
static/app/views/starfish/views/spanSummaryPage/index.tsx

@@ -4,6 +4,7 @@ import styled from '@emotion/styled';
 import DatePageFilter from 'sentry/components/datePageFilter';
 import * as Layout from 'sentry/components/layouts/thirds';
 import PageFiltersContainer from 'sentry/components/organizations/pageFilters/container';
+import {Panel, PanelBody} from 'sentry/components/panels';
 import QuestionTooltip from 'sentry/components/questionTooltip';
 import {t} from 'sentry/locale';
 import {space} from 'sentry/styles/space';
@@ -12,13 +13,18 @@ import {
   PageErrorAlert,
   PageErrorProvider,
 } from 'sentry/utils/performance/contexts/pageError';
+import {P95_COLOR, THROUGHPUT_COLOR} from 'sentry/views/starfish/colours';
+import Chart, {useSynchronizeCharts} from 'sentry/views/starfish/components/chart';
+import ChartPanel from 'sentry/views/starfish/components/chartPanel';
+import {SpanDescription} from 'sentry/views/starfish/components/spanDescription';
 import DurationCell from 'sentry/views/starfish/components/tableCells/durationCell';
 import ThroughputCell from 'sentry/views/starfish/components/tableCells/throughputCell';
 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 {useSpanMetricsSeries} from 'sentry/views/starfish/queries/useSpanMetricsSeries';
+import {DataTitles} from 'sentry/views/starfish/views/spans/types';
 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';
 
 type Props = {
@@ -37,6 +43,16 @@ function SpanSummaryPage({params, location}: Props) {
     'span-summary-page-metrics'
   );
 
+  const {isLoading: areSpanMetricsSeriesLoading, data: spanMetricsSeriesData} =
+    useSpanMetricsSeries(
+      {group: groupId},
+      undefined,
+      ['p95(span.duration)', 'sps()'],
+      'sidebar-span-metrics'
+    );
+
+  useSynchronizeCharts([!areSpanMetricsSeriesLoading]);
+
   return (
     <Layout.Page>
       <PageFiltersContainer>
@@ -78,7 +94,54 @@ function SpanSummaryPage({params, location}: Props) {
                 </Block>
               </BlockContainer>
 
-              {span && <SpanBaselineTable span={span} />}
+              {span?.description && (
+                <BlockContainer>
+                  <Block>
+                    <Panel>
+                      <PanelBody>
+                        <DescriptionContainer>
+                          <SpanDescription span={span} />
+                        </DescriptionContainer>
+                      </PanelBody>
+                    </Panel>
+                  </Block>
+
+                  <Block>
+                    <ChartPanel title={DataTitles.throughput}>
+                      <Chart
+                        statsPeriod="24h"
+                        height={140}
+                        data={[spanMetricsSeriesData?.['sps()']]}
+                        start=""
+                        end=""
+                        loading={areSpanMetricsSeriesLoading}
+                        utc={false}
+                        chartColors={[THROUGHPUT_COLOR]}
+                        isLineChart
+                        definedAxisTicks={4}
+                      />
+                    </ChartPanel>
+                  </Block>
+
+                  <Block>
+                    <ChartPanel title={DataTitles.p95}>
+                      <Chart
+                        statsPeriod="24h"
+                        height={140}
+                        data={[spanMetricsSeriesData?.['p95(span.duration)']]}
+                        start=""
+                        end=""
+                        loading={areSpanMetricsSeriesLoading}
+                        utc={false}
+                        chartColors={[P95_COLOR]}
+                        isLineChart
+                        definedAxisTicks={4}
+                      />
+                    </ChartPanel>
+                  </Block>
+                </BlockContainer>
+              )}
+
               {span && <SpanTransactionsTable span={span} />}
 
               {transaction && span?.group && (
@@ -102,8 +165,8 @@ const FilterOptionsContainer = styled('div')`
 
 type BlockProps = {
   children: React.ReactNode;
-  title: React.ReactNode;
   description?: React.ReactNode;
+  title?: React.ReactNode;
 };
 
 export function Block({title, description, children}: BlockProps) {
@@ -146,6 +209,11 @@ export const BlockContainer = styled('div')`
   padding-bottom: ${space(2)};
 `;
 
+const DescriptionContainer = styled('div')`
+  width: 100%;
+  padding: ${space(1)};
+`;
+
 const BlockWrapper = styled('div')`
   padding-right: ${space(4)};
   flex: 1;

+ 0 - 141
static/app/views/starfish/views/spanSummaryPage/spanBaselineTable.tsx

@@ -1,141 +0,0 @@
-import GridEditable, {
-  COL_WIDTH_UNDEFINED,
-  GridColumnHeader,
-} from 'sentry/components/gridEditable';
-import {formatPercentage} from 'sentry/utils/formatters';
-import {useLocation} from 'sentry/utils/useLocation';
-import {SpanDescription} from 'sentry/views/starfish/components/spanDescription';
-import DurationCell from 'sentry/views/starfish/components/tableCells/durationCell';
-import ThroughputCell from 'sentry/views/starfish/components/tableCells/throughputCell';
-import {TimeSpentCell} from 'sentry/views/starfish/components/tableCells/timeSpentCell';
-import type {IndexedSpan} from 'sentry/views/starfish/queries/types';
-import {
-  ApplicationMetrics,
-  useApplicationMetrics,
-} from 'sentry/views/starfish/queries/useApplicationMetrics';
-import {SpanMetrics, useSpanMetrics} from 'sentry/views/starfish/queries/useSpanMetrics';
-import {DataTitles} from 'sentry/views/starfish/views/spans/types';
-
-type Props = {
-  span: IndexedSpan;
-};
-
-type Row = {
-  description: string;
-  metrics: SpanMetrics;
-};
-
-export type Keys =
-  | 'description'
-  | 'sps()'
-  | 'p95(span.self_time)'
-  | 'time_spent_percentage()';
-export type TableColumnHeader = GridColumnHeader<Keys>;
-
-export function SpanBaselineTable({span}: Props) {
-  const location = useLocation();
-
-  const {data: applicationMetrics} = useApplicationMetrics();
-  const {data: spanMetrics} = useSpanMetrics(
-    span,
-    undefined,
-    ['sps()', 'sum(span.duration)', 'p95(span.duration)', 'time_spent_percentage()'],
-    'span-baseline-table'
-  );
-
-  const renderHeadCell = column => {
-    return <span>{column.name}</span>;
-  };
-
-  const renderBodyCell = (column: TableColumnHeader, row: Row) => {
-    return (
-      <BodyCell
-        span={span}
-        column={column}
-        row={row}
-        applicationMetrics={applicationMetrics}
-      />
-    );
-  };
-
-  return (
-    <GridEditable
-      isLoading={false}
-      data={[
-        {
-          description: span.description ?? '',
-          metrics: spanMetrics,
-        },
-      ]}
-      columnOrder={COLUMN_ORDER}
-      columnSortBy={[]}
-      grid={{
-        renderHeadCell,
-        renderBodyCell,
-      }}
-      location={location}
-    />
-  );
-}
-
-type CellProps = {
-  column: TableColumnHeader;
-  row: Row;
-  span: IndexedSpan;
-};
-
-function BodyCell({
-  span,
-  column,
-  row,
-}: CellProps & {applicationMetrics: ApplicationMetrics}) {
-  if (column.key === 'description') {
-    return <DescriptionCell span={span} row={row} column={column} />;
-  }
-
-  if (column.key === 'p95(span.self_time)') {
-    return <DurationCell milliseconds={row.metrics?.['p95(span.duration)']} />;
-  }
-
-  if (column.key === 'sps()') {
-    return <ThroughputCell throughputPerSecond={row.metrics?.['sps()']} />;
-  }
-
-  if (column.key === 'time_spent_percentage()') {
-    return (
-      <TimeSpentCell
-        formattedTimeSpent={formatPercentage(row.metrics?.['time_spent_percentage()'])}
-        totalSpanTime={row.metrics?.['sum(span.duration)']}
-      />
-    );
-  }
-
-  return <span>{row[column.key]}</span>;
-}
-
-function DescriptionCell({span}: CellProps) {
-  return <SpanDescription span={span} />;
-}
-
-const COLUMN_ORDER: TableColumnHeader[] = [
-  {
-    key: 'description',
-    name: 'Description',
-    width: 500,
-  },
-  {
-    key: 'sps()',
-    name: DataTitles.throughput,
-    width: COL_WIDTH_UNDEFINED,
-  },
-  {
-    key: 'p95(span.self_time)',
-    name: DataTitles.p95,
-    width: COL_WIDTH_UNDEFINED,
-  },
-  {
-    key: 'time_spent_percentage()',
-    name: DataTitles.timeSpent,
-    width: COL_WIDTH_UNDEFINED,
-  },
-];