tracesChart.tsx 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. import {useMemo} from 'react';
  2. import styled from '@emotion/styled';
  3. import {getInterval} from 'sentry/components/charts/utils';
  4. import {CHART_PALETTE} from 'sentry/constants/chartPalette';
  5. import {t} from 'sentry/locale';
  6. import type {Series} from 'sentry/types/echarts';
  7. import {tooltipFormatter} from 'sentry/utils/discover/charts';
  8. import {decodeList} from 'sentry/utils/queryString';
  9. import {MutableSearch} from 'sentry/utils/tokenizeSearch';
  10. import {useLocation} from 'sentry/utils/useLocation';
  11. import usePageFilters from 'sentry/utils/usePageFilters';
  12. import Chart, {ChartType} from 'sentry/views/insights/common/components/chart';
  13. import ChartPanel from 'sentry/views/insights/common/components/chartPanel';
  14. import {useSpanIndexedSeries} from 'sentry/views/insights/common/queries/useDiscoverSeries';
  15. import {CHART_HEIGHT} from 'sentry/views/insights/database/settings';
  16. import {areQueriesEmpty} from './utils';
  17. interface Props {}
  18. export function TracesChart({}: Props) {
  19. const location = useLocation();
  20. const queries = useMemo(() => {
  21. return decodeList(location.query.query)?.map(query => query.trim());
  22. }, [location.query.query]);
  23. const enabled = useMemo(
  24. () => [
  25. true, // always visualize the first series
  26. Boolean(queries?.[1]),
  27. Boolean(queries?.[2]),
  28. ],
  29. [queries]
  30. );
  31. const firstCountSeries = useTraceCountSeries({
  32. query: queries?.[0] || '',
  33. enabled: enabled[0],
  34. });
  35. const secondCountSeries = useTraceCountSeries({
  36. query: queries?.[1],
  37. enabled: enabled[1],
  38. });
  39. const thirdCountSeries = useTraceCountSeries({
  40. query: queries?.[2],
  41. enabled: enabled[2],
  42. });
  43. const seriesAreLoading =
  44. // Disabled queries have `isLoading: true`, but this changes in v5.
  45. // To handle this gracefully, we check if the query is enabled + isLoading.
  46. //
  47. // References
  48. // - https://tanstack.com/query/v4/docs/framework/react/guides/disabling-queries
  49. // - https://tanstack.com/query/latest/docs/framework/react/guides/disabling-queries#isloading-previously-isinitialloading
  50. (enabled[0] && firstCountSeries.isLoading) ||
  51. (enabled[1] && secondCountSeries.isLoading) ||
  52. (enabled[2] && thirdCountSeries.isLoading);
  53. const chartData = useMemo<Series[]>(() => {
  54. const series = [firstCountSeries.data, secondCountSeries.data, thirdCountSeries.data];
  55. const allData: Series[] = [];
  56. for (let i = 0; i < series.length; i++) {
  57. if (!enabled[i]) {
  58. continue;
  59. }
  60. const data = series[i]['count()'];
  61. data.color = CHART_PALETTE[2][i];
  62. data.seriesName =
  63. `span ${i + 1}: ${queries[i] || t('All spans')}` || t('All spans');
  64. allData.push(data);
  65. }
  66. return allData;
  67. }, [
  68. enabled,
  69. queries,
  70. firstCountSeries.data,
  71. secondCountSeries.data,
  72. thirdCountSeries.data,
  73. ]);
  74. return (
  75. <ChartContainer>
  76. <ChartPanel
  77. title={areQueriesEmpty(queries) ? t('All Spans') : t('All Matching Spans')}
  78. >
  79. <Chart
  80. height={CHART_HEIGHT}
  81. grid={{
  82. left: '0',
  83. right: '0',
  84. top: '8px',
  85. bottom: '0',
  86. }}
  87. data={chartData}
  88. loading={seriesAreLoading}
  89. chartColors={CHART_PALETTE[2]}
  90. type={ChartType.LINE}
  91. aggregateOutputFormat="number"
  92. showLegend
  93. tooltipFormatterOptions={{
  94. valueFormatter: value => tooltipFormatter(value),
  95. }}
  96. />
  97. </ChartPanel>
  98. </ChartContainer>
  99. );
  100. }
  101. const ChartContainer = styled('div')`
  102. display: grid;
  103. gap: 0;
  104. grid-template-columns: 1fr;
  105. `;
  106. const useTraceCountSeries = ({
  107. enabled,
  108. query,
  109. }: {
  110. enabled: boolean;
  111. query: string | null;
  112. }) => {
  113. const pageFilters = usePageFilters();
  114. return useSpanIndexedSeries(
  115. {
  116. search: new MutableSearch(query ?? ''),
  117. yAxis: ['count()'],
  118. interval: getInterval(pageFilters.selection.datetime, 'metrics'),
  119. overriddenRoute: 'traces-stats',
  120. enabled,
  121. },
  122. 'api.trace-explorer.stats'
  123. );
  124. };