destinationSummaryPage.tsx 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. import {Fragment} from 'react';
  2. import styled from '@emotion/styled';
  3. import FeatureBadge from 'sentry/components/badge/featureBadge';
  4. import {Breadcrumbs} from 'sentry/components/breadcrumbs';
  5. import ButtonBar from 'sentry/components/buttonBar';
  6. import FeedbackWidgetButton from 'sentry/components/feedback/widget/feedbackWidgetButton';
  7. import * as Layout from 'sentry/components/layouts/thirds';
  8. import {DatePageFilter} from 'sentry/components/organizations/datePageFilter';
  9. import {EnvironmentPageFilter} from 'sentry/components/organizations/environmentPageFilter';
  10. import PageFilterBar from 'sentry/components/organizations/pageFilterBar';
  11. import {ProjectPageFilter} from 'sentry/components/organizations/projectPageFilter';
  12. import {t} from 'sentry/locale';
  13. import {space} from 'sentry/styles/space';
  14. import {DurationUnit} from 'sentry/utils/discover/fields';
  15. import {decodeScalar} from 'sentry/utils/queryString';
  16. import {useLocation} from 'sentry/utils/useLocation';
  17. import useOrganization from 'sentry/utils/useOrganization';
  18. import {normalizeUrl} from 'sentry/utils/withDomainRequired';
  19. import {useOnboardingProject} from 'sentry/views/performance/browser/webVitals/utils/useOnboardingProject';
  20. import {MetricReadout} from 'sentry/views/performance/metricReadout';
  21. import * as ModuleLayout from 'sentry/views/performance/moduleLayout';
  22. import {ModulePageProviders} from 'sentry/views/performance/modulePageProviders';
  23. import Onboarding from 'sentry/views/performance/onboarding';
  24. import {LatencyChart} from 'sentry/views/performance/queues/charts/latencyChart';
  25. import {ThroughputChart} from 'sentry/views/performance/queues/charts/throughputChart';
  26. import {MessageSpanSamplesPanel} from 'sentry/views/performance/queues/destinationSummary/messageSpanSamplesPanel';
  27. import {TransactionsTable} from 'sentry/views/performance/queues/destinationSummary/transactionsTable';
  28. import {useQueuesMetricsQuery} from 'sentry/views/performance/queues/queries/useQueuesMetricsQuery';
  29. import {
  30. BASE_URL,
  31. DESTINATION_TITLE,
  32. MODULE_TITLE,
  33. RELEASE_LEVEL,
  34. } from 'sentry/views/performance/queues/settings';
  35. import {useQueueModuleURL} from 'sentry/views/performance/utils/useModuleURL';
  36. import {getTimeSpentExplanation} from 'sentry/views/starfish/components/tableCells/timeSpentCell';
  37. function DestinationSummaryPage() {
  38. const moduleURL = useQueueModuleURL();
  39. const organization = useOrganization();
  40. const onboardingProject = useOnboardingProject();
  41. const {query} = useLocation();
  42. const destination = decodeScalar(query.destination);
  43. const {data, isLoading} = useQueuesMetricsQuery({destination});
  44. const errorRate = 1 - (data[0]?.['trace_status_rate(ok)'] ?? 0);
  45. return (
  46. <Fragment>
  47. <Layout.Header>
  48. <Layout.HeaderContent>
  49. <Breadcrumbs
  50. crumbs={[
  51. {
  52. label: t('Performance'),
  53. to: normalizeUrl(`/organizations/${organization.slug}/performance/`),
  54. preservePageFilters: true,
  55. },
  56. {
  57. label: MODULE_TITLE,
  58. to: moduleURL,
  59. preservePageFilters: true,
  60. },
  61. {
  62. label: DESTINATION_TITLE,
  63. },
  64. ]}
  65. />
  66. <Layout.Title>
  67. {destination}
  68. <FeatureBadge type={RELEASE_LEVEL} />
  69. </Layout.Title>
  70. </Layout.HeaderContent>
  71. <Layout.HeaderActions>
  72. <ButtonBar gap={1}>
  73. <FeedbackWidgetButton />
  74. </ButtonBar>
  75. </Layout.HeaderActions>
  76. </Layout.Header>
  77. <Layout.Body>
  78. <Layout.Main fullWidth>
  79. <ModuleLayout.Layout>
  80. <ModuleLayout.Full>
  81. <HeaderContainer>
  82. <PageFilterBar condensed>
  83. <ProjectPageFilter />
  84. <EnvironmentPageFilter />
  85. <DatePageFilter />
  86. </PageFilterBar>
  87. {!onboardingProject && (
  88. <MetricsRibbon>
  89. <MetricReadout
  90. title={t('Avg Time In Queue')}
  91. value={data[0]?.['avg(messaging.message.receive.latency)']}
  92. unit={DurationUnit.MILLISECOND}
  93. isLoading={isLoading}
  94. />
  95. <MetricReadout
  96. title={t('Avg Processing Time')}
  97. value={data[0]?.['avg_if(span.duration,span.op,queue.process)']}
  98. unit={DurationUnit.MILLISECOND}
  99. isLoading={isLoading}
  100. />
  101. <MetricReadout
  102. title={t('Error Rate')}
  103. value={errorRate}
  104. unit={'percentage'}
  105. isLoading={isLoading}
  106. />
  107. <MetricReadout
  108. title={t('Published')}
  109. value={data[0]?.['count_op(queue.publish)']}
  110. unit={'count'}
  111. isLoading={isLoading}
  112. />
  113. <MetricReadout
  114. title={t('Processed')}
  115. value={data[0]?.['count_op(queue.process)']}
  116. unit={'count'}
  117. isLoading={isLoading}
  118. />
  119. <MetricReadout
  120. title={t('Time Spent')}
  121. value={data[0]?.['sum(span.duration)']}
  122. unit={DurationUnit.MILLISECOND}
  123. tooltip={getTimeSpentExplanation(
  124. data[0]?.['time_spent_percentage(app,span.duration)']
  125. )}
  126. isLoading={isLoading}
  127. />
  128. </MetricsRibbon>
  129. )}
  130. </HeaderContainer>
  131. </ModuleLayout.Full>
  132. {onboardingProject && (
  133. <Onboarding organization={organization} project={onboardingProject} />
  134. )}
  135. {!onboardingProject && (
  136. <Fragment>
  137. <ModuleLayout.Half>
  138. <LatencyChart destination={destination} />
  139. </ModuleLayout.Half>
  140. <ModuleLayout.Half>
  141. <ThroughputChart destination={destination} />
  142. </ModuleLayout.Half>
  143. <ModuleLayout.Full>
  144. <Flex>
  145. <TransactionsTable />
  146. </Flex>
  147. </ModuleLayout.Full>
  148. </Fragment>
  149. )}
  150. </ModuleLayout.Layout>
  151. </Layout.Main>
  152. </Layout.Body>
  153. <MessageSpanSamplesPanel />
  154. </Fragment>
  155. );
  156. }
  157. function PageWithProviders() {
  158. return (
  159. <ModulePageProviders
  160. title={[t('Performance'), MODULE_TITLE].join(' — ')}
  161. baseURL={`/performance/${BASE_URL}`}
  162. features="performance-queues-view"
  163. >
  164. <DestinationSummaryPage />
  165. </ModulePageProviders>
  166. );
  167. }
  168. export default PageWithProviders;
  169. const Flex = styled('div')`
  170. display: flex;
  171. flex-direction: column;
  172. gap: ${space(2)};
  173. `;
  174. const MetricsRibbon = styled('div')`
  175. display: flex;
  176. flex-wrap: wrap;
  177. gap: ${space(4)};
  178. `;
  179. const HeaderContainer = styled('div')`
  180. display: flex;
  181. justify-content: space-between;
  182. `;