transactions.tsx 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. import {doEventsRequest} from 'sentry/actionCreators/events';
  2. import type {Client} from 'sentry/api';
  3. import type {PageFilters} from 'sentry/types/core';
  4. import type {Series} from 'sentry/types/echarts';
  5. import type {TagCollection} from 'sentry/types/group';
  6. import type {
  7. EventsStats,
  8. MultiSeriesEventsStats,
  9. Organization,
  10. } from 'sentry/types/organization';
  11. import {defined} from 'sentry/utils';
  12. import type {CustomMeasurementCollection} from 'sentry/utils/customMeasurements/customMeasurements';
  13. import type {EventsTableData, TableData} from 'sentry/utils/discover/discoverQuery';
  14. import {SPAN_OP_BREAKDOWN_FIELDS, TRANSACTION_FIELDS} from 'sentry/utils/discover/fields';
  15. import type {
  16. DiscoverQueryExtras,
  17. DiscoverQueryRequestParams,
  18. } from 'sentry/utils/discover/genericDiscoverQuery';
  19. import {doDiscoverQuery} from 'sentry/utils/discover/genericDiscoverQuery';
  20. import {DiscoverDatasets} from 'sentry/utils/discover/types';
  21. import {getMeasurements} from 'sentry/utils/measurements/measurements';
  22. import {MEPState} from 'sentry/utils/performance/contexts/metricsEnhancedSetting';
  23. import {
  24. type OnDemandControlContext,
  25. shouldUseOnDemandMetrics,
  26. } from 'sentry/utils/performance/contexts/onDemandControl';
  27. import {getSeriesRequestData} from 'sentry/views/dashboards/datasetConfig/utils/getSeriesRequestData';
  28. import {generateFieldOptions} from 'sentry/views/discover/utils';
  29. import type {Widget, WidgetQuery} from '../types';
  30. import {DisplayType} from '../types';
  31. import {eventViewFromWidget} from '../utils';
  32. import {EventsSearchBar} from '../widgetBuilder/buildSteps/filterResultsStep/eventsSearchBar';
  33. import {type DatasetConfig, handleOrderByReset} from './base';
  34. import {
  35. doOnDemandMetricsRequest,
  36. filterAggregateParams,
  37. filterSeriesSortOptions,
  38. filterYAxisAggregateParams,
  39. filterYAxisOptions,
  40. getCustomEventsFieldRenderer,
  41. getTableSortOptions,
  42. getTimeseriesSortOptions,
  43. transformEventsResponseToSeries,
  44. transformEventsResponseToTable,
  45. } from './errorsAndTransactions';
  46. const DEFAULT_WIDGET_QUERY: WidgetQuery = {
  47. name: '',
  48. fields: ['count()'],
  49. columns: [],
  50. fieldAliases: [],
  51. aggregates: ['count()'],
  52. conditions: '',
  53. orderby: '-count()',
  54. };
  55. export type SeriesWithOrdering = [order: number, series: Series];
  56. export const TransactionsConfig: DatasetConfig<
  57. EventsStats | MultiSeriesEventsStats,
  58. TableData | EventsTableData
  59. > = {
  60. defaultWidgetQuery: DEFAULT_WIDGET_QUERY,
  61. enableEquations: true,
  62. getCustomFieldRenderer: getCustomEventsFieldRenderer,
  63. SearchBar: EventsSearchBar,
  64. filterSeriesSortOptions,
  65. filterYAxisAggregateParams,
  66. filterYAxisOptions,
  67. getTableFieldOptions: getEventsTableFieldOptions,
  68. getTimeseriesSortOptions,
  69. getTableSortOptions,
  70. getGroupByFieldOptions: getEventsTableFieldOptions,
  71. handleOrderByReset,
  72. supportedDisplayTypes: [
  73. DisplayType.AREA,
  74. DisplayType.BAR,
  75. DisplayType.BIG_NUMBER,
  76. DisplayType.LINE,
  77. DisplayType.TABLE,
  78. DisplayType.TOP_N,
  79. ],
  80. getTableRequest: (
  81. api: Client,
  82. widget: Widget,
  83. query: WidgetQuery,
  84. organization: Organization,
  85. pageFilters: PageFilters,
  86. onDemandControlContext?: OnDemandControlContext,
  87. limit?: number,
  88. cursor?: string,
  89. referrer?: string,
  90. mepSetting?: MEPState | null
  91. ) => {
  92. const useOnDemandMetrics = shouldUseOnDemandMetrics(
  93. organization,
  94. widget,
  95. onDemandControlContext
  96. );
  97. const queryExtras = {
  98. useOnDemandMetrics,
  99. onDemandType: 'dynamic_query',
  100. };
  101. return getEventsRequest(
  102. api,
  103. query,
  104. organization,
  105. pageFilters,
  106. limit,
  107. cursor,
  108. referrer,
  109. mepSetting,
  110. queryExtras
  111. );
  112. },
  113. getSeriesRequest: getEventsSeriesRequest,
  114. transformSeries: transformEventsResponseToSeries,
  115. transformTable: transformEventsResponseToTable,
  116. filterAggregateParams,
  117. };
  118. function getEventsTableFieldOptions(
  119. organization: Organization,
  120. tags?: TagCollection,
  121. customMeasurements?: CustomMeasurementCollection
  122. ) {
  123. const measurements = getMeasurements();
  124. return generateFieldOptions({
  125. organization,
  126. tagKeys: Object.values(tags ?? {}).map(({key}) => key),
  127. measurementKeys: Object.values(measurements).map(({key}) => key),
  128. spanOperationBreakdownKeys: SPAN_OP_BREAKDOWN_FIELDS,
  129. customMeasurements: Object.values(customMeasurements ?? {}).map(
  130. ({key, functions}) => ({
  131. key,
  132. functions,
  133. })
  134. ),
  135. fieldKeys: TRANSACTION_FIELDS,
  136. });
  137. }
  138. function getEventsRequest(
  139. api: Client,
  140. query: WidgetQuery,
  141. organization: Organization,
  142. pageFilters: PageFilters,
  143. limit?: number,
  144. cursor?: string,
  145. referrer?: string,
  146. mepSetting?: MEPState | null,
  147. queryExtras?: DiscoverQueryExtras
  148. ) {
  149. const isMEPEnabled = defined(mepSetting) && mepSetting !== MEPState.TRANSACTIONS_ONLY;
  150. const url = `/organizations/${organization.slug}/events/`;
  151. const eventView = eventViewFromWidget('', query, pageFilters);
  152. const params: DiscoverQueryRequestParams = {
  153. per_page: limit,
  154. cursor,
  155. referrer,
  156. dataset: isMEPEnabled
  157. ? DiscoverDatasets.METRICS_ENHANCED
  158. : DiscoverDatasets.TRANSACTIONS,
  159. ...queryExtras,
  160. };
  161. if (query.orderby) {
  162. params.sort = typeof query.orderby === 'string' ? [query.orderby] : query.orderby;
  163. }
  164. return doDiscoverQuery<EventsTableData>(
  165. api,
  166. url,
  167. {
  168. ...eventView.generateQueryStringObject(),
  169. ...params,
  170. },
  171. // Tries events request up to 3 times on rate limit
  172. {
  173. retry: {
  174. statusCodes: [429],
  175. tries: 3,
  176. },
  177. }
  178. );
  179. }
  180. function getEventsSeriesRequest(
  181. api: Client,
  182. widget: Widget,
  183. queryIndex: number,
  184. organization: Organization,
  185. pageFilters: PageFilters,
  186. onDemandControlContext?: OnDemandControlContext,
  187. referrer?: string,
  188. mepSetting?: MEPState | null
  189. ) {
  190. const isMEPEnabled = defined(mepSetting) && mepSetting !== MEPState.TRANSACTIONS_ONLY;
  191. const requestData = getSeriesRequestData(
  192. widget,
  193. queryIndex,
  194. organization,
  195. pageFilters,
  196. isMEPEnabled ? DiscoverDatasets.METRICS_ENHANCED : DiscoverDatasets.TRANSACTIONS,
  197. referrer
  198. );
  199. if (shouldUseOnDemandMetrics(organization, widget, onDemandControlContext)) {
  200. requestData.queryExtras = {
  201. ...requestData.queryExtras,
  202. ...{dataset: DiscoverDatasets.METRICS_ENHANCED},
  203. };
  204. return doOnDemandMetricsRequest(api, requestData, widget.widgetType);
  205. }
  206. return doEventsRequest<true>(api, requestData);
  207. }