Browse Source

feat(starfish): Switch over span group breakdown to category (#50410)

Switches over from module breakdown to
category breakdown and removes the fallback
to scraped data.
Shruthi 1 year ago
parent
commit
85e7c9befa

+ 0 - 7
static/app/views/starfish/colours.tsx

@@ -1,13 +1,6 @@
 import {CHART_PALETTE} from 'sentry/constants/chartPalette';
-import {ModuleName} from 'sentry/views/starfish/types';
 
 export const THROUGHPUT_COLOR = CHART_PALETTE[0][0];
 export const P50_COLOR = CHART_PALETTE[2][2];
 export const P95_COLOR = CHART_PALETTE[2][1];
 export const ERRORS_COLOR = CHART_PALETTE[2][2];
-export const MODULE_COLOR: Record<ModuleName, string> = {
-  [ModuleName.HTTP]: CHART_PALETTE[3][3],
-  [ModuleName.DB]: CHART_PALETTE[3][2],
-  [ModuleName.NONE]: CHART_PALETTE[3][1],
-  [ModuleName.ALL]: CHART_PALETTE[3][0],
-};

+ 1 - 1
static/app/views/starfish/utils/useSpansQuery.tsx

@@ -112,7 +112,7 @@ export function useWrappedDiscoverTimeseriesQuery({
       ...eventView.getEventsAPIPayload(location),
       yAxis: eventView.yAxis,
       topEvents: eventView.topEvents,
-      excludeOther: 1,
+      excludeOther: 0,
       partial: 1,
       orderby: eventView.sorts?.[0] ? encodeSort(eventView.sorts?.[0]) : undefined,
       interval: eventView.interval,

+ 13 - 15
static/app/views/starfish/views/webServiceView/spanGroupBreakdown.tsx

@@ -1,5 +1,6 @@
 import {useEffect, useState} from 'react';
 import {Link} from 'react-router';
+import {useTheme} from '@emotion/react';
 import styled from '@emotion/styled';
 import * as qs from 'query-string';
 
@@ -15,9 +16,7 @@ import {NumberContainer} from 'sentry/utils/discover/styles';
 import {formatPercentage} from 'sentry/utils/formatters';
 import usePageFilters from 'sentry/utils/usePageFilters';
 import {RightAlignedCell} from 'sentry/views/performance/landing/widgets/components/selectableList';
-import {MODULE_COLOR} from 'sentry/views/starfish/colours';
 import Chart from 'sentry/views/starfish/components/chart';
-import {ModuleName} from 'sentry/views/starfish/types';
 import {DataRow} from 'sentry/views/starfish/views/webServiceView/spanGroupBreakdownContainer';
 
 type Props = {
@@ -36,6 +35,7 @@ export function SpanGroupBreakdown({
   initialShowSeries,
 }: Props) {
   const {selection} = usePageFilters();
+  const theme = useTheme();
   const [showSeriesArray, setShowSeriesArray] = useState<boolean[]>(initialShowSeries);
 
   useEffect(() => {
@@ -50,16 +50,17 @@ export function SpanGroupBreakdown({
       visibleSeries.push(series);
     }
   }
+  const colorPalette = theme.charts.getColorPalette(transformedData.length - 2);
 
   return (
     <FlexRowContainer>
       <ChartPadding>
         <Header>
-          <ChartLabel>{t('App Time Breakdown (p95)')}</ChartLabel>
+          <ChartLabel>{t('App Time Breakdown (P95)')}</ChartLabel>
         </Header>
         <Chart
           statsPeriod="24h"
-          height={175}
+          height={210}
           data={visibleSeries}
           start=""
           end=""
@@ -89,23 +90,20 @@ export function SpanGroupBreakdown({
             start && end
               ? {start: getUtcDateString(start), end: getUtcDateString(end), utc}
               : {statsPeriod: period};
-          ['span.module'].forEach(key => {
-            if (group[key] !== undefined && group[key] !== null) {
-              spansLinkQueryParams[key] = group[key];
-            }
-          });
+          if (['db', 'http'].includes(group['span.category'])) {
+            spansLinkQueryParams['span.module'] = group['span.category'];
+          }
 
           const spansLink =
-            group['span.module'] === 'other'
+            group['span.category'] === 'Other'
               ? `/starfish/spans/`
               : `/starfish/spans/?${qs.stringify(spansLinkQueryParams)}`;
-          const module = group['span.module'] as ModuleName;
           return (
-            <StyledLineItem key={`${group['span.module']}`}>
+            <StyledLineItem key={`${group['span.category']}`}>
               <ListItemContainer>
                 <Checkbox
                   size="sm"
-                  checkboxColor={MODULE_COLOR[module]}
+                  checkboxColor={colorPalette[index]}
                   inputCss={{backgroundColor: 'red'}}
                   checked={checkedValue}
                   onChange={() => {
@@ -116,7 +114,7 @@ export function SpanGroupBreakdown({
                 />
                 <TextAlignLeft>
                   <Link to={spansLink}>
-                    <TextOverflow>{group['span.module']}</TextOverflow>
+                    <TextOverflow>{group['span.category']}</TextOverflow>
                   </Link>
                 </TextAlignLeft>
                 <RightAlignedCell>
@@ -124,7 +122,7 @@ export function SpanGroupBreakdown({
                     title={t(
                       '%s time spent on %s',
                       formatPercentage(row.cumulativeTime / totalValues, 1),
-                      group['span.module']
+                      group['span.category']
                     )}
                     containerDisplayMode="block"
                     position="top"

+ 64 - 128
static/app/views/starfish/views/webServiceView/spanGroupBreakdownContainer.tsx

@@ -1,37 +1,29 @@
 import {useTheme} from '@emotion/react';
 import styled from '@emotion/styled';
-import moment from 'moment';
 
 import {getInterval} from 'sentry/components/charts/utils';
 import {Panel} from 'sentry/components/panels';
+import Placeholder from 'sentry/components/placeholder';
 import {space} from 'sentry/styles/space';
 import {PageFilters} from 'sentry/types';
 import {Series} from 'sentry/types/echarts';
+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 usePageFilters from 'sentry/utils/usePageFilters';
-import {MODULE_COLOR} from 'sentry/views/starfish/colours';
-import {ModuleName} from 'sentry/views/starfish/types';
-import {PERIOD_REGEX} from 'sentry/views/starfish/utils/dates';
-import {useSpansQuery} from 'sentry/views/starfish/utils/useSpansQuery';
-import {zeroFillSeries} from 'sentry/views/starfish/utils/zeroFillSeries';
-import {
-  getOtherModulesTimeseries,
-  getTopModules,
-  getTopModulesTimeseries,
-  totalCumulativeTime,
-} from 'sentry/views/starfish/views/webServiceView/queries';
+import {useWrappedDiscoverTimeseriesQuery} from 'sentry/views/starfish/utils/useSpansQuery';
 import {SpanGroupBreakdown} from 'sentry/views/starfish/views/webServiceView/spanGroupBreakdown';
 
-export const OTHER_SPAN_GROUP_MODULE = 'other';
-const FORCE_USE_DISCOVER = true;
+export const OTHER_SPAN_GROUP_MODULE = 'Other';
 
 type Props = {
   transaction?: string;
 };
 
 type Group = {
-  'span.module': string;
+  'span.category': string;
 };
 
 export type Segment = Group & {
@@ -47,161 +39,104 @@ export type DataRow = {
 export function SpanGroupBreakdownContainer({transaction: maybeTransaction}: Props) {
   const transaction = maybeTransaction ?? '';
   const pageFilter = usePageFilters();
+  const organization = useOrganization();
+  const location = useLocation();
   const {selection} = pageFilter;
   const theme = useTheme();
 
-  const {data: segments, isLoading: isSegmentsLoading} = useSpansQuery<Segment[]>({
-    queryString: `${getTopModules({
-      transaction,
-      datetime: selection.datetime,
-    })}`,
+  const {data: segments, isLoading: isSegmentsLoading} = useDiscoverQuery({
     eventView: getEventView(
       selection,
-      `span.module:[db,http] ${transaction ? `transaction:${transaction}` : ''}`,
-      ['span.module']
+      // TODO: Fix has:span.category in the backend
+      `has:span.category ${transaction ? `transaction:${transaction}` : ''}`,
+      ['span.category']
     ),
-    initialData: [],
-    forceUseDiscover: FORCE_USE_DISCOVER,
+    orgSlug: organization.slug,
+    location,
+    limit: 4,
   });
 
-  const {data: cumulativeTime} = useSpansQuery({
-    queryString: `${totalCumulativeTime({
-      transaction,
-      datetime: selection.datetime,
-    })}`,
+  const {data: cumulativeTime} = useDiscoverQuery({
     eventView: getEventView(
       selection,
       `${transaction ? `transaction:${transaction}` : ''}`,
       []
     ),
+    orgSlug: organization.slug,
+    location,
+  });
+
+  const {isLoading: isTopDataLoading, data: topData} = useWrappedDiscoverTimeseriesQuery({
+    eventView: getEventView(
+      selection,
+      `has:span.category  ${transaction ? `transaction:${transaction}` : ''}`,
+      ['span.category'],
+      true
+    ),
     initialData: [],
-    forceUseDiscover: FORCE_USE_DISCOVER,
   });
 
-  const totalValues = cumulativeTime.reduce(
-    (acc, segment) => acc + segment['sum(span.duration)'],
-    0
-  );
-  const totalSegments = segments.reduce(
-    (acc, segment) => acc + segment['sum(span.duration)'],
-    0
-  );
-  const otherValue = totalValues - totalSegments;
+  if (!segments?.data || !cumulativeTime?.data || topData.length === 0) {
+    return <Placeholder height="200px" />;
+  }
+
+  const totalValues = cumulativeTime.data[0]['sum(span.duration)']
+    ? parseInt(cumulativeTime?.data[0]['sum(span.duration)'] as string, 10)
+    : 0;
+  const totalSegments =
+    segments?.data.reduce(
+      (acc, segment) => acc + parseInt(segment['sum(span.duration)'] as string, 10),
+      0
+    ) ?? 0;
+
+  const otherValue = totalValues ? totalValues - totalSegments : 0;
 
   const transformedData: DataRow[] = [];
 
-  for (let index = 0; index < segments.length; index++) {
-    const element = segments[index];
+  for (let index = 0; index < segments.data.length; index++) {
+    const element = segments.data[index];
     transformedData.push({
-      cumulativeTime: element['sum(span.duration)'],
+      cumulativeTime: parseInt(element['sum(span.duration)'] as string, 10),
       group: {
-        'span.module': element['span.module'],
+        'span.category': element['span.category'] as string,
       },
     });
   }
 
-  transformedData.push({
-    cumulativeTime: otherValue,
-    group: {
-      'span.module': OTHER_SPAN_GROUP_MODULE,
-    },
-  });
-
-  let topConditions =
-    segments.length > 0 ? ` span.module = '${segments[0]['span.module']}'` : '';
-
-  for (let index = 1; index < segments.length; index++) {
-    const element = segments[index];
-    topConditions = topConditions.concat(
-      ' OR ',
-      ` span.module = '${element['span.module']}'`
-    );
+  if (otherValue > 0) {
+    transformedData.push({
+      cumulativeTime: otherValue,
+      group: {
+        'span.category': OTHER_SPAN_GROUP_MODULE,
+      },
+    });
   }
 
-  const {isLoading: isTopDataLoading, data: topData} = useSpansQuery({
-    queryString: `${getTopModulesTimeseries({
-      transaction,
-      topConditions,
-      datetime: selection.datetime,
-    })}`,
-    eventView: getEventView(
-      selection,
-      `span.module:[db,http] ${transaction ? `transaction:${transaction}` : ''}`,
-      ['span.module'],
-      true
-    ),
-    initialData: [],
-    forceUseDiscover: FORCE_USE_DISCOVER,
-  });
+  const seriesByDomain: {[category: string]: Series} = {};
+  const colorPalette = theme.charts.getColorPalette(transformedData.length - 2);
 
-  const {isLoading: isOtherDataLoading, data: otherData} = useSpansQuery({
-    queryString: `${getOtherModulesTimeseries({
-      transaction,
-      topConditions,
-      datetime: selection.datetime,
-    })}`,
-    eventView: getEventView(
-      selection,
-      `!span.module:[db,http] ${transaction ? `transaction:${transaction}` : ''}`,
-      [],
-      true
-    ),
-    initialData: [],
-    forceUseDiscover: FORCE_USE_DISCOVER,
-  });
-
-  const seriesByDomain: {[module: string]: Series} = {};
-  const [_, num, unit] = pageFilter.selection.datetime.period?.match(PERIOD_REGEX) ?? [];
-  const start =
-    num && unit
-      ? moment().subtract(num, unit as 'h' | 'd')
-      : moment(pageFilter.selection.datetime.start);
-  const end = moment(pageFilter.selection.datetime.end ?? undefined);
-
-  const colorPalette = theme.charts.getColorPalette(transformedData.length - 3);
-
-  if (
-    !isTopDataLoading &&
-    !isOtherDataLoading &&
-    topData.length > 0 &&
-    segments.length > 0
-  ) {
-    segments.forEach(segment => {
-      const label = segment['span.module'] as ModuleName;
+  if (!isTopDataLoading && topData.length > 0 && transformedData.length > 0) {
+    transformedData.forEach((segment, index) => {
+      const label = segment.group['span.category'];
       seriesByDomain[label] = {
         seriesName: `${label}`,
         data: [],
-        color: MODULE_COLOR[label],
+        color: colorPalette[index],
       };
     });
 
     topData.forEach(value => {
-      seriesByDomain[value['span.module'] ?? value.group].data.push({
-        value: value['p95(span.duration)'],
-        name: value.interval,
-      });
-    });
-
-    seriesByDomain.Other = {
-      seriesName: `Other`,
-      data: [],
-      color: theme.gray100,
-    };
-
-    otherData.forEach(value => {
-      seriesByDomain.Other.data.push({
+      seriesByDomain[value.group].data.push({
         value: value['p95(span.duration)'],
         name: value.interval,
       });
     });
   }
 
-  const data = Object.values(seriesByDomain).map(series =>
-    zeroFillSeries(series, moment.duration(12, 'hour'), start, end)
-  );
+  const data = Object.values(seriesByDomain);
 
   const initialShowSeries = transformedData.map(
-    segment => segment.group['span.module'] !== OTHER_SPAN_GROUP_MODULE
+    segment => segment.group['span.category'] !== OTHER_SPAN_GROUP_MODULE
   );
 
   return (
@@ -238,9 +173,10 @@ const getEventView = (
     start: pageFilters.datetime.start ?? undefined,
     end: pageFilters.datetime.end ?? undefined,
     range: pageFilters.datetime.period ?? undefined,
+    orderby: '-sum_span_duration',
     projects: [1],
     version: 2,
-    topEvents: groups.length > 0 ? '5' : undefined,
+    topEvents: groups.length > 0 ? '4' : undefined,
     interval: getTimeseries ? getInterval(pageFilters.datetime, 'low') : undefined,
   });
 };