Browse Source

feat(starfish): Add a module breakdown to endpoint detail (#48346)

Add module level breakdown, but scoped down to endpoint
in the detail panel slide out. 
![Screenshot 2023-05-02 at 11 59 41
AM](https://user-images.githubusercontent.com/63818634/235720813-4ddaef89-388d-43c8-9fdd-8dd03e94c46f.png)

---------

Co-authored-by: Ash Anand <0Calories@users.noreply.github.com>
Shruthi 1 year ago
parent
commit
15f222f0f9

+ 26 - 16
static/app/views/starfish/components/breakdownBar.tsx

@@ -11,11 +11,11 @@ import {useQuery} from 'sentry/utils/queryClient';
 import {DatabaseDurationChart} from 'sentry/views/starfish/views/webServiceView/databaseDurationChart';
 import {HttpBreakdownChart} from 'sentry/views/starfish/views/webServiceView/httpBreakdownChart';
 import {
-  DB_THROUGHPUT,
-  DB_TIME_SPENT,
-  HTTP_THROUGHPUT,
-  OTHER_DOMAINS,
-  TOP_DOMAINS,
+  getDatabaseTimeSpent,
+  getDbThroughput,
+  getHttpThroughput,
+  getOtherDomains,
+  getTopHttpDomains,
 } from 'sentry/views/starfish/views/webServiceView/queries';
 
 const COLORS = ['#402A65', '#694D99', '#9A81C4', '#BBA6DF', '#EAE2F8'];
@@ -29,47 +29,57 @@ type ModuleSegment = {
 type Props = {
   segments: ModuleSegment[];
   title: string;
+  transaction?: string;
 };
 
-function FacetBreakdownBar({segments, title}: Props) {
+function FacetBreakdownBar({segments, title, transaction: maybeTransaction}: Props) {
   const [hoveredValue, setHoveredValue] = useState<ModuleSegment | null>(null);
   const [currentSegment, setCurrentSegment] = useState<
     ModuleSegment['module'] | undefined
   >(segments[0]?.module);
   const totalValues = segments.reduce((acc, segment) => acc + segment.sum, 0);
 
+  const transaction = maybeTransaction ?? '';
+
   const {isLoading: isHttpDurationDataLoading, data: httpDurationData} = useQuery({
-    queryKey: ['topDomains'],
-    queryFn: () => fetch(`${HOST}/?query=${TOP_DOMAINS}`).then(res => res.json()),
+    queryKey: [`topDomains${transaction}`],
+    queryFn: () =>
+      fetch(`${HOST}/?query=${getTopHttpDomains({transaction})}`).then(res => res.json()),
     retry: false,
     initialData: [],
   });
 
   const {isLoading: isOtherHttpDurationDataLoading, data: otherHttpDurationData} =
     useQuery({
-      queryKey: ['otherDomains'],
-      queryFn: () => fetch(`${HOST}/?query=${OTHER_DOMAINS}`).then(res => res.json()),
+      queryKey: [`otherDomains${transaction}`],
+      queryFn: () =>
+        fetch(`${HOST}/?query=${getOtherDomains({transaction})}`).then(res => res.json()),
       retry: false,
       initialData: [],
     });
 
   const {isLoading: isDbDurationLoading, data: dbDurationData} = useQuery({
-    queryKey: ['databaseDuration'],
-    queryFn: () => fetch(`${HOST}/?query=${DB_TIME_SPENT}`).then(res => res.json()),
+    queryKey: [`databaseDuration${transaction}`],
+    queryFn: () =>
+      fetch(`${HOST}/?query=${getDatabaseTimeSpent({transaction})}`).then(res =>
+        res.json()
+      ),
     retry: false,
     initialData: [],
   });
 
   const {data: dbThroughputData} = useQuery({
-    queryKey: ['dbThroughputData'],
-    queryFn: () => fetch(`${HOST}/?query=${DB_THROUGHPUT}`).then(res => res.json()),
+    queryKey: [`dbThroughputData${transaction}`],
+    queryFn: () =>
+      fetch(`${HOST}/?query=${getDbThroughput({transaction})}`).then(res => res.json()),
     retry: false,
     initialData: [],
   });
 
   const {data: httpThroughputData} = useQuery({
-    queryKey: ['httpThroughputData'],
-    queryFn: () => fetch(`${HOST}/?query=${HTTP_THROUGHPUT}`).then(res => res.json()),
+    queryKey: [`httpThroughputData${transaction}`],
+    queryFn: () =>
+      fetch(`${HOST}/?query=${getHttpThroughput({transaction})}`).then(res => res.json()),
     retry: false,
     initialData: [],
   });

+ 18 - 0
static/app/views/starfish/views/webServiceView/endpointDetails/index.tsx

@@ -17,6 +17,7 @@ import {useQuery} from 'sentry/utils/queryClient';
 import {MutableSearch} from 'sentry/utils/tokenizeSearch';
 import usePageFilters from 'sentry/utils/usePageFilters';
 import withApi from 'sentry/utils/withApi';
+import FacetBreakdownBar from 'sentry/views/starfish/components/breakdownBar';
 import Chart from 'sentry/views/starfish/components/chart';
 import Detail from 'sentry/views/starfish/components/detailPanel';
 import EndpointTable from 'sentry/views/starfish/modules/APIModule/endpointTable';
@@ -24,6 +25,7 @@ import DatabaseTableView from 'sentry/views/starfish/modules/databaseModule/data
 import {getMainTable} from 'sentry/views/starfish/modules/databaseModule/queries';
 import {HOST} from 'sentry/views/starfish/utils/constants';
 import {getDateFilters} from 'sentry/views/starfish/utils/dates';
+import {getModuleBreakdown} from 'sentry/views/starfish/views/webServiceView/queries';
 
 const EventsRequest = withApi(_EventsRequest);
 
@@ -135,6 +137,17 @@ function EndpointDetailBody({
   const theme = useTheme();
   const pageFilter = usePageFilters();
   const {aggregateDetails} = row;
+
+  const {data: moduleBreakdown} = useQuery({
+    queryKey: [`moduleBreakdown${row.transaction}`],
+    queryFn: () =>
+      fetch(`${HOST}/?query=${getModuleBreakdown({transaction: row.transaction})}`).then(
+        res => res.json()
+      ),
+    retry: false,
+    initialData: [],
+  });
+
   const query = new MutableSearch([
     'has:http.method',
     'transaction.op:http.server',
@@ -242,6 +255,11 @@ function EndpointDetailBody({
           );
         }}
       </EventsRequest>
+      <FacetBreakdownBar
+        segments={moduleBreakdown}
+        title={t('Where is time spent in this endpoint?')}
+        transaction={row.transaction}
+      />
       <SubHeader>{t('HTTP Spans')}</SubHeader>
       <EndpointTable
         location={location}

+ 67 - 47
static/app/views/starfish/views/webServiceView/queries.js

@@ -1,12 +1,16 @@
-export const MODULE_BREAKDOWN = `SELECT
- sum(exclusive_time) as sum, module
- FROM spans_experimental_starfish
- WHERE module != 'none'
- GROUP BY module
- ORDER BY -sum
-`;
+export const getModuleBreakdown = ({transaction}) => {
+  return `SELECT
+  sum(exclusive_time) as sum, module
+  FROM spans_experimental_starfish
+  WHERE module != 'none'
+  ${transaction ? `AND transaction = '${transaction}'` : ''}
+  GROUP BY module
+  ORDER BY -sum
+ `;
+};
 
-export const TOP_DOMAINS = `SELECT
+export const getTopHttpDomains = ({transaction}) => {
+  return `SELECT
  quantile(0.75)(exclusive_time) as p75, domain,
  toStartOfInterval(start_timestamp, INTERVAL 1 DAY) as interval
  FROM default.spans_experimental_starfish
@@ -14,56 +18,72 @@ export const TOP_DOMAINS = `SELECT
   SELECT domain
    FROM spans_experimental_starfish
    WHERE startsWith(span_operation, 'http')
+   ${transaction ? `AND transaction = '${transaction}'` : ''}
    GROUP BY domain
    ORDER BY -sum(exclusive_time)
    LIMIT 2
  ) AND startsWith(span_operation, 'http')
+ ${transaction ? `AND transaction = '${transaction}'` : ''}
  GROUP BY interval, domain
  ORDER BY interval, domain
  `;
+};
 
-export const OTHER_DOMAINS = `SELECT
- quantile(0.75)(exclusive_time) as p75,
- toStartOfInterval(start_timestamp, INTERVAL 1 DAY) as interval
- FROM default.spans_experimental_starfish
- WHERE domain NOT IN (
-  SELECT domain
-   FROM spans_experimental_starfish
-   WHERE startsWith(span_operation, 'http')
-   GROUP BY domain
-   ORDER BY -sum(exclusive_time)
-   LIMIT 2
- ) AND startsWith(span_operation, 'http')
- GROUP BY interval
- ORDER BY interval
- `;
+export const getOtherDomains = ({transaction}) => {
+  return `SELECT
+  quantile(0.75)(exclusive_time) as p75,
+  toStartOfInterval(start_timestamp, INTERVAL 1 DAY) as interval
+  FROM default.spans_experimental_starfish
+  WHERE domain NOT IN (
+   SELECT domain
+    FROM spans_experimental_starfish
+    WHERE startsWith(span_operation, 'http')
+    ${transaction ? `AND transaction = '${transaction}'` : ''}
+    GROUP BY domain
+    ORDER BY -sum(exclusive_time)
+    LIMIT 2
+  ) AND startsWith(span_operation, 'http')
+  ${transaction ? `AND transaction = '${transaction}'` : ''}
+  GROUP BY interval
+  ORDER BY interval
+  `;
+};
 
-export const DB_TIME_SPENT = `SELECT
- quantile(0.75)(exclusive_time) as p75,
- toStartOfInterval(start_timestamp, INTERVAL 1 DAY) as interval
- FROM default.spans_experimental_starfish
- WHERE startsWith(span_operation, 'db') and span_operation != 'db.redis'
- GROUP BY interval
- ORDER BY interval
- `;
+export const getDatabaseTimeSpent = ({transaction}) => {
+  return `SELECT
+  quantile(0.75)(exclusive_time) as p75,
+  toStartOfInterval(start_timestamp, INTERVAL 1 DAY) as interval
+  FROM default.spans_experimental_starfish
+  WHERE startsWith(span_operation, 'db') and span_operation != 'db.redis'
+  ${transaction ? `AND transaction = '${transaction}'` : ''}
+  GROUP BY interval
+  ORDER BY interval
+  `;
+};
 
-export const DB_THROUGHPUT = `SELECT
- count() as count,
- toStartOfInterval(start_timestamp, INTERVAL 1 DAY) as interval
- FROM default.spans_experimental_starfish
- WHERE module = 'db'
- GROUP BY interval
- ORDER BY interval
- `;
+export const getDbThroughput = ({transaction}) => {
+  return `SELECT
+  count() as count,
+  toStartOfInterval(start_timestamp, INTERVAL 1 DAY) as interval
+  FROM default.spans_experimental_starfish
+  WHERE module = 'db'
+  ${transaction ? `AND transaction = '${transaction}'` : ''}
+  GROUP BY interval
+  ORDER BY interval
+  `;
+};
 
-export const HTTP_THROUGHPUT = `SELECT
- count() as count,
- toStartOfInterval(start_timestamp, INTERVAL 1 DAY) as interval
- FROM default.spans_experimental_starfish
- WHERE module = 'http'
- GROUP BY interval
- ORDER BY interval
-`;
+export const getHttpThroughput = ({transaction}) => {
+  return `SELECT
+  count() as count,
+  toStartOfInterval(start_timestamp, INTERVAL 1 DAY) as interval
+  FROM default.spans_experimental_starfish
+  WHERE module = 'http'
+  ${transaction ? `AND transaction = '${transaction}'` : ''}
+  GROUP BY interval
+  ORDER BY interval
+ `;
+};
 
 export const FAILURE_RATE_QUERY = `SELECT
  toStartOfInterval(start_timestamp, INTERVAL 5 MINUTE) as interval,

+ 5 - 3
static/app/views/starfish/views/webServiceView/starfishView.tsx

@@ -26,7 +26,7 @@ import ChartPanel from 'sentry/views/starfish/components/chartPanel';
 import {insertClickableAreasIntoSeries} from 'sentry/views/starfish/utils/insertClickableAreasIntoSeries';
 import {EndpointDataRow} from 'sentry/views/starfish/views/webServiceView/endpointDetails';
 import FailureDetailPanel from 'sentry/views/starfish/views/webServiceView/failureDetailPanel';
-import {MODULE_BREAKDOWN} from 'sentry/views/starfish/views/webServiceView/queries';
+import {getModuleBreakdown} from 'sentry/views/starfish/views/webServiceView/queries';
 import {FailureSpike} from 'sentry/views/starfish/views/webServiceView/types';
 
 import EndpointList from './endpointList';
@@ -45,11 +45,13 @@ export function StarfishView(props: BasePerformanceViewProps) {
   const {organization, eventView, onSelect} = props;
   const theme = useTheme();
   const [selectedSpike, setSelectedSpike] = useState<FailureSpike>(null);
-
   // Queries
   const {data: moduleBreakdown} = useQuery({
     queryKey: ['moduleBreakdown'],
-    queryFn: () => fetch(`${HOST}/?query=${MODULE_BREAKDOWN}`).then(res => res.json()),
+    queryFn: () =>
+      fetch(`${HOST}/?query=${getModuleBreakdown({transaction: ''})}`).then(res =>
+        res.json()
+      ),
     retry: false,
     initialData: [],
   });