resourceSummaryCharts.tsx 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. import {t} from 'sentry/locale';
  2. import type {Series} from 'sentry/types/echarts';
  3. import {formatBytesBase2} from 'sentry/utils';
  4. import {formatRate} from 'sentry/utils/formatters';
  5. import getDynamicText from 'sentry/utils/getDynamicText';
  6. import {RESOURCE_THROUGHPUT_UNIT} from 'sentry/views/performance/browser/resources';
  7. import {useResourceModuleFilters} from 'sentry/views/performance/browser/resources/utils/useResourceFilters';
  8. import {AVG_COLOR, THROUGHPUT_COLOR} from 'sentry/views/starfish/colours';
  9. import Chart from 'sentry/views/starfish/components/chart';
  10. import ChartPanel from 'sentry/views/starfish/components/chartPanel';
  11. import {useSpanMetricsSeries} from 'sentry/views/starfish/queries/useSpanMetricsSeries';
  12. import {SpanMetricsField} from 'sentry/views/starfish/types';
  13. import {
  14. DataTitles,
  15. getDurationChartTitle,
  16. getThroughputChartTitle,
  17. } from 'sentry/views/starfish/views/spans/types';
  18. import {Block, BlockContainer} from 'sentry/views/starfish/views/spanSummaryPage/block';
  19. const {
  20. SPAN_SELF_TIME,
  21. HTTP_RESPONSE_CONTENT_LENGTH,
  22. HTTP_DECODED_RESPONSE_CONTENT_LENGTH,
  23. HTTP_RESPONSE_TRANSFER_SIZE,
  24. RESOURCE_RENDER_BLOCKING_STATUS,
  25. } = SpanMetricsField;
  26. function ResourceSummaryCharts(props: {groupId: string}) {
  27. const filters = useResourceModuleFilters();
  28. // console.log({
  29. // ...(filters[RESOURCE_RENDER_BLOCKING_STATUS]
  30. // ? {[RESOURCE_RENDER_BLOCKING_STATUS]: filters[RESOURCE_RENDER_BLOCKING_STATUS]}
  31. // : {}),
  32. // });
  33. const {data: spanMetricsSeriesData, isLoading: areSpanMetricsSeriesLoading} =
  34. useSpanMetricsSeries({
  35. filters: {
  36. 'span.group': props.groupId,
  37. ...(filters[RESOURCE_RENDER_BLOCKING_STATUS]
  38. ? {[RESOURCE_RENDER_BLOCKING_STATUS]: filters[RESOURCE_RENDER_BLOCKING_STATUS]}
  39. : {}),
  40. },
  41. yAxis: [
  42. `spm()`,
  43. `avg(${SPAN_SELF_TIME})`,
  44. `avg(${HTTP_RESPONSE_CONTENT_LENGTH})`,
  45. `avg(${HTTP_DECODED_RESPONSE_CONTENT_LENGTH})`,
  46. `avg(${HTTP_RESPONSE_TRANSFER_SIZE})`,
  47. ],
  48. enabled: Boolean(props.groupId),
  49. });
  50. if (spanMetricsSeriesData) {
  51. spanMetricsSeriesData[`avg(${HTTP_RESPONSE_TRANSFER_SIZE})`].lineStyle = {
  52. type: 'dashed',
  53. };
  54. spanMetricsSeriesData[`avg(${HTTP_DECODED_RESPONSE_CONTENT_LENGTH})`].lineStyle = {
  55. type: 'dashed',
  56. };
  57. }
  58. return (
  59. <BlockContainer>
  60. <Block>
  61. <ChartPanel title={getThroughputChartTitle('http', RESOURCE_THROUGHPUT_UNIT)}>
  62. <Chart
  63. height={160}
  64. data={[spanMetricsSeriesData?.[`spm()`]]}
  65. loading={areSpanMetricsSeriesLoading}
  66. isLineChart
  67. definedAxisTicks={4}
  68. aggregateOutputFormat="rate"
  69. rateUnit={RESOURCE_THROUGHPUT_UNIT}
  70. stacked
  71. chartColors={[THROUGHPUT_COLOR]}
  72. tooltipFormatterOptions={{
  73. valueFormatter: value => formatRate(value, RESOURCE_THROUGHPUT_UNIT),
  74. nameFormatter: () => t('Requests'),
  75. }}
  76. />
  77. </ChartPanel>
  78. </Block>
  79. <Block>
  80. <ChartPanel title={getDurationChartTitle('http')}>
  81. <Chart
  82. height={160}
  83. data={[spanMetricsSeriesData?.[`avg(${SPAN_SELF_TIME})`]]}
  84. loading={areSpanMetricsSeriesLoading}
  85. chartColors={[AVG_COLOR]}
  86. isLineChart
  87. definedAxisTicks={4}
  88. />
  89. </ChartPanel>
  90. </Block>
  91. <Block>
  92. <ChartPanel title={t('Average Resource Size')}>
  93. <Chart
  94. height={160}
  95. aggregateOutputFormat="size"
  96. data={[
  97. spanMetricsSeriesData?.[`avg(${HTTP_DECODED_RESPONSE_CONTENT_LENGTH})`],
  98. spanMetricsSeriesData?.[`avg(${HTTP_RESPONSE_TRANSFER_SIZE})`],
  99. spanMetricsSeriesData?.[`avg(${HTTP_RESPONSE_CONTENT_LENGTH})`],
  100. ]}
  101. loading={areSpanMetricsSeriesLoading}
  102. chartColors={[AVG_COLOR]}
  103. isLineChart
  104. definedAxisTicks={4}
  105. tooltipFormatterOptions={{
  106. valueFormatter: bytes =>
  107. getDynamicText({
  108. value: formatBytesBase2(bytes),
  109. fixed: 'xx KiB',
  110. }),
  111. nameFormatter: name => DataTitles[name],
  112. }}
  113. />
  114. </ChartPanel>
  115. </Block>
  116. </BlockContainer>
  117. );
  118. }
  119. /**
  120. * Ensures a series has no zeros between two non-zero datapoints. This is useful in
  121. * @param series the series to fill
  122. * @returns a reference to the initial series filled
  123. */
  124. export const fillSeries = (series: Series): Series => {
  125. if (!series.data.length) {
  126. return series;
  127. }
  128. let lastSeenValue = series.data[0].value;
  129. return {
  130. ...series,
  131. data: series.data.map(dataPoint => {
  132. const value = dataPoint.value;
  133. if (value !== lastSeenValue && value !== 0) {
  134. lastSeenValue = value;
  135. return {...dataPoint};
  136. }
  137. return {...dataPoint, value: lastSeenValue};
  138. }),
  139. };
  140. };
  141. export default ResourceSummaryCharts;