Просмотр исходного кода

feat(starfish): Span view improvements (#48934)

Mainly, adds an "API Status" indicator, which is handy. Also, improves
how the clusters at the top are structured.
George Gritsouk 1 год назад
Родитель
Сommit
12db492e69

+ 23 - 0
static/app/views/starfish/modules/APIModule/hostDetails.tsx

@@ -1,6 +1,8 @@
 import {useTheme} from '@emotion/react';
 import styled from '@emotion/styled';
+import {useQuery} from '@tanstack/react-query';
 
+import CircleIndicator from 'sentry/components/circleIndicator';
 import {IconOpen} from 'sentry/icons';
 import {t} from 'sentry/locale';
 import {space} from 'sentry/styles/space';
@@ -46,6 +48,15 @@ export function HostDetails({host}: Props) {
 
   const externalApi = hostMarketingName && EXTERNAL_APIS[hostMarketingName];
 
+  const {isLoading: isStatusLoading, data: statusData} = useQuery({
+    queryKey: ['domain-status', host],
+    queryFn: () =>
+      fetch(`${externalApi?.statusPage}?format=json`).then(res => res.json()),
+    retry: false,
+    initialData: {},
+    enabled: !!externalApi,
+  });
+
   return (
     <DetailsContainer>
       <FlexContainer>
@@ -57,6 +68,7 @@ export function HostDetails({host}: Props) {
             style={{marginRight: space(1)}}
           />
         )}
+
         {hostMarketingName ? (
           <span>
             <Host>{hostMarketingName}</Host>
@@ -66,6 +78,13 @@ export function HostDetails({host}: Props) {
           <Host>{host}</Host>
         )}
 
+        {!isStatusLoading && statusData.status ? (
+          <StatusText>
+            <CircleIndicator size={8} enabled={statusData.status.indicator === 'none'} />{' '}
+            {statusData.status.description}
+          </StatusText>
+        ) : null}
+
         <LinkContainer>
           {externalApi?.statusPage && (
             <a href={externalApi.statusPage} target="_blank" rel="noreferrer">
@@ -133,6 +152,10 @@ const Host = styled('span')`
   font-weight: bold;
 `;
 
+const StatusText = styled('span')`
+  margin-left: ${space(2)};
+`;
+
 const StyledIconOpen = styled(IconOpen)`
   flex: 0;
   top: 2px;

+ 2 - 14
static/app/views/starfish/views/spans/clusters.tsx

@@ -8,6 +8,7 @@ export type Cluster = {
   grouping_column?: string;
   grouping_condition?: (value: any) => () => string;
   isDynamic?: boolean;
+  value?: string;
 };
 
 export const CLUSTERS: Record<string, Cluster> = {
@@ -52,7 +53,7 @@ export const CLUSTERS: Record<string, Cluster> = {
     description_label: 'URL',
     domain_label: 'Host',
     condition: () => "module == 'http'",
-    grouping_column: 'span_operation',
+    grouping_column: "concat('http.client.',  lower(action))",
   },
   'top.other': {
     name: 'top.other',
@@ -61,14 +62,6 @@ export const CLUSTERS: Record<string, Cluster> = {
     grouping_column: "splitByChar('.', span_operation)[1]",
     grouping_condition: value => () => `splitByChar('.', span_operation)[1] = '${value}'`,
   },
-  'http.client': {
-    name: 'http.client',
-    label: 'Client',
-    explanation: 'HTTP Methods',
-    condition: () => "span_operation == 'http.client'",
-    grouping_column:
-      "action IN ['GET', 'POST'] ? concat('http.client.', lower(action)) : 'http.client.other'",
-  },
   'http.client.get': {
     name: 'http.client.get',
     label: 'GET',
@@ -87,9 +80,4 @@ export const CLUSTERS: Record<string, Cluster> = {
     label: 'Other',
     condition: () => "action NOT IN ['GET', 'POST']",
   },
-  'http.server': {
-    name: 'http.server',
-    label: 'Server',
-    condition: () => "span_operation == 'http.server'",
-  },
 };

+ 19 - 3
static/app/views/starfish/views/spans/spansView.tsx

@@ -11,6 +11,7 @@ import SearchBar from 'sentry/components/searchBar';
 import TagDistributionMeter from 'sentry/components/tagDistributionMeter';
 import {space} from 'sentry/styles/space';
 import usePageFilters from 'sentry/utils/usePageFilters';
+import {HostDetails} from 'sentry/views/starfish/modules/APIModule/hostDetails';
 import {HOST} from 'sentry/views/starfish/utils/constants';
 import {SpanTimeCharts} from 'sentry/views/starfish/views/spans/spanTimeCharts';
 
@@ -42,7 +43,9 @@ export default function SpansView(props: Props) {
     clusterName =>
       CLUSTERS[clusterName] || {
         isDynamic: true,
-        name: clusterName,
+        name: clusterName.split(':')[1],
+        value: clusterName.split(':')[1],
+        parentClusterName: clusterName.split(':')[0],
       }
   );
 
@@ -55,6 +58,8 @@ export default function SpansView(props: Props) {
       previousCluster?.grouping_condition?.(currentCluster.name) || (() => '');
   }
 
+  const lastStaticCluster = currentClusters.findLast(cluster => !cluster.isDynamic);
+
   const clusterBreakdowns = useQueries({
     queries: currentClusters.map(cluster => {
       return {
@@ -156,8 +161,15 @@ export default function SpansView(props: Props) {
             <TagDistributionMeter
               key={cluster.name}
               title={cluster.explanation || cluster.label}
-              onTagClick={(_name, value) => {
-                setClusterPath([...clusterPath.slice(0, depth + 1), value.value]);
+              onTagClick={(_name, tag) => {
+                const incomingCluster = CLUSTERS[tag.value];
+                const bottomCluster = currentClusters.at(-1);
+
+                const incomingClusterName = incomingCluster
+                  ? tag.value
+                  : `${bottomCluster?.name || ''}:${tag.value}`;
+
+                setClusterPath([...clusterPath.slice(0, depth + 1), incomingClusterName]);
               }}
               segments={segments}
               totalValues={sumBy(segments, 'count')}
@@ -182,6 +194,10 @@ export default function SpansView(props: Props) {
         }}
       />
 
+      {lastStaticCluster?.name === 'http.client.get' && currentCluster?.value && (
+        <HostDetails host={currentCluster.value} />
+      )}
+
       <SpanTimeCharts
         descriptionFilter={descriptionFilter || ''}
         clusters={currentClusters}