useResourcesQuery.ts 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. import {useDiscoverQuery} from 'sentry/utils/discover/discoverQuery';
  2. import EventView from 'sentry/utils/discover/eventView';
  3. import {DiscoverDatasets} from 'sentry/utils/discover/types';
  4. import {useLocation} from 'sentry/utils/useLocation';
  5. import useOrganization from 'sentry/utils/useOrganization';
  6. import usePageFilters from 'sentry/utils/usePageFilters';
  7. import {FONT_FILE_EXTENSIONS} from 'sentry/views/performance/browser/resources/shared/constants';
  8. import {
  9. ModuleFilters,
  10. useResourceModuleFilters,
  11. } from 'sentry/views/performance/browser/resources/utils/useResourceFilters';
  12. import {ValidSort} from 'sentry/views/performance/browser/resources/utils/useResourceSort';
  13. import {SpanFunction, SpanMetricsField} from 'sentry/views/starfish/types';
  14. import {EMPTY_OPTION_VALUE} from 'sentry/views/starfish/views/spans/selectors/emptyOption';
  15. const {
  16. SPAN_DOMAIN,
  17. SPAN_GROUP,
  18. SPAN_DESCRIPTION,
  19. SPAN_OP,
  20. SPAN_SELF_TIME,
  21. RESOURCE_RENDER_BLOCKING_STATUS,
  22. HTTP_RESPONSE_CONTENT_LENGTH,
  23. PROJECT_ID,
  24. FILE_EXTENSION,
  25. } = SpanMetricsField;
  26. const {TIME_SPENT_PERCENTAGE} = SpanFunction;
  27. type Props = {
  28. referrer: string;
  29. sort: ValidSort;
  30. cursor?: string;
  31. defaultResourceTypes?: string[];
  32. limit?: number;
  33. query?: string;
  34. };
  35. export const DEFAULT_RESOURCE_FILTERS = ['!span.description:"browser-extension://*"'];
  36. export const getResourcesEventViewQuery = (
  37. resourceFilters: Partial<ModuleFilters>,
  38. defaultResourceTypes: string[] | undefined
  39. ): string[] => {
  40. return [
  41. ...DEFAULT_RESOURCE_FILTERS,
  42. ...(resourceFilters.transaction
  43. ? [`transaction:"${resourceFilters.transaction}"`]
  44. : []),
  45. ...getDomainFilter(resourceFilters[SPAN_DOMAIN]),
  46. ...(resourceFilters[RESOURCE_RENDER_BLOCKING_STATUS]
  47. ? [
  48. `${RESOURCE_RENDER_BLOCKING_STATUS}:${resourceFilters[RESOURCE_RENDER_BLOCKING_STATUS]}`,
  49. ]
  50. : []),
  51. ...getResourceTypeFilter(resourceFilters[SPAN_OP], defaultResourceTypes),
  52. ];
  53. };
  54. export const useResourcesQuery = ({
  55. sort,
  56. defaultResourceTypes,
  57. query,
  58. limit,
  59. cursor,
  60. referrer,
  61. }: Props) => {
  62. const pageFilters = usePageFilters();
  63. const location = useLocation();
  64. const resourceFilters = useResourceModuleFilters();
  65. const {slug: orgSlug} = useOrganization();
  66. const queryConditions = [
  67. ...(!query ? getResourcesEventViewQuery(resourceFilters, defaultResourceTypes) : []),
  68. query,
  69. ];
  70. // TODO - we should be using metrics data here
  71. const eventView = EventView.fromNewQueryWithPageFilters(
  72. {
  73. fields: [
  74. SPAN_DESCRIPTION,
  75. SPAN_OP,
  76. 'count()',
  77. `avg(${SPAN_SELF_TIME})`,
  78. 'spm()',
  79. SPAN_GROUP,
  80. SPAN_DOMAIN,
  81. `avg(${HTTP_RESPONSE_CONTENT_LENGTH})`,
  82. 'project.id',
  83. `${TIME_SPENT_PERCENTAGE}()`,
  84. `sum(${SPAN_SELF_TIME})`,
  85. ],
  86. name: 'Resource module - resource table',
  87. query: queryConditions.join(' '),
  88. orderby: '-count',
  89. version: 2,
  90. dataset: DiscoverDatasets.SPANS_METRICS,
  91. },
  92. pageFilters.selection
  93. );
  94. if (sort) {
  95. eventView.sorts = [sort];
  96. }
  97. const result = useDiscoverQuery({
  98. eventView,
  99. limit: limit ?? 100,
  100. location,
  101. orgSlug,
  102. options: {
  103. refetchOnWindowFocus: false,
  104. },
  105. cursor,
  106. referrer,
  107. });
  108. const data = result?.data?.data.map(row => ({
  109. [SPAN_OP]: row[SPAN_OP].toString() as `resource.${string}`,
  110. [SPAN_DESCRIPTION]: row[SPAN_DESCRIPTION].toString(),
  111. ['avg(span.self_time)']: row[`avg(${SPAN_SELF_TIME})`] as number,
  112. 'count()': row['count()'] as number,
  113. 'spm()': row['spm()'] as number,
  114. [SPAN_GROUP]: row[SPAN_GROUP].toString(),
  115. [RESOURCE_RENDER_BLOCKING_STATUS]: row[RESOURCE_RENDER_BLOCKING_STATUS] as
  116. | ''
  117. | 'non-blocking'
  118. | 'blocking',
  119. [SPAN_DOMAIN]: row[SPAN_DOMAIN][0]?.toString(),
  120. [PROJECT_ID]: row[PROJECT_ID] as number,
  121. [`avg(http.response_content_length)`]: row[
  122. `avg(${HTTP_RESPONSE_CONTENT_LENGTH})`
  123. ] as number,
  124. [`time_spent_percentage()`]: row[`${TIME_SPENT_PERCENTAGE}()`] as number,
  125. ['count_unique(transaction)']: row['count_unique(transaction)'] as number,
  126. [`sum(span.self_time)`]: row[`sum(${SPAN_SELF_TIME})`] as number,
  127. }));
  128. return {...result, data: data || []};
  129. };
  130. export const getDomainFilter = (selectedDomain: string | undefined) => {
  131. if (!selectedDomain) {
  132. return [];
  133. }
  134. if (selectedDomain === EMPTY_OPTION_VALUE) {
  135. return [`!has:${SPAN_DOMAIN}`];
  136. }
  137. return [`${SPAN_DOMAIN}:"${selectedDomain}"`];
  138. };
  139. const SPAN_OP_FILTER = {
  140. 'resource.script': [`${SPAN_OP}:resource.script`],
  141. 'resource.css': [`${FILE_EXTENSION}:css`],
  142. 'resource.font': [`${FILE_EXTENSION}:[${FONT_FILE_EXTENSIONS.join(',')}]`],
  143. };
  144. export const getResourceTypeFilter = (
  145. selectedSpanOp: string | undefined,
  146. defaultResourceTypes: string[] | undefined
  147. ) => {
  148. let resourceFilter: string[] = [`${SPAN_OP}:resource.*`];
  149. if (selectedSpanOp) {
  150. resourceFilter = SPAN_OP_FILTER[selectedSpanOp] || [`${SPAN_OP}:${selectedSpanOp}`];
  151. } else if (defaultResourceTypes) {
  152. resourceFilter = [
  153. defaultResourceTypes.map(type => SPAN_OP_FILTER[type]).join(' OR '),
  154. ];
  155. }
  156. return ['(', ...resourceFilter, ')'];
  157. };