events.tsx 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. import {LocationDescriptor} from 'history';
  2. import pick from 'lodash/pick';
  3. import {Client} from 'sentry/api';
  4. import {canIncludePreviousPeriod} from 'sentry/components/charts/utils';
  5. import {
  6. DateString,
  7. EventsStats,
  8. MultiSeriesEventsStats,
  9. OrganizationSummary,
  10. } from 'sentry/types';
  11. import {LocationQuery} from 'sentry/utils/discover/eventView';
  12. import {getPeriod} from 'sentry/utils/getPeriod';
  13. import {PERFORMANCE_URL_PARAM} from 'sentry/utils/performance/constants';
  14. import {QueryBatching} from 'sentry/utils/performance/contexts/genericQueryBatcher';
  15. type Options = {
  16. organization: OrganizationSummary;
  17. partial: boolean;
  18. comparisonDelta?: number;
  19. end?: DateString;
  20. environment?: Readonly<string[]>;
  21. field?: string[];
  22. generatePathname?: (org: OrganizationSummary) => string;
  23. includePrevious?: boolean;
  24. interval?: string;
  25. limit?: number;
  26. orderby?: string;
  27. period?: string | null;
  28. project?: Readonly<number[]>;
  29. query?: string;
  30. queryBatching?: QueryBatching;
  31. queryExtras?: Record<string, string>;
  32. referrer?: string;
  33. start?: DateString;
  34. team?: Readonly<string | string[]>;
  35. topEvents?: number;
  36. withoutZerofill?: boolean;
  37. yAxis?: string | string[];
  38. };
  39. /**
  40. * Make requests to `events-stats` endpoint
  41. *
  42. * @param {Object} api API client instance
  43. * @param {Object} options Request parameters
  44. * @param {Object} options.organization Organization object
  45. * @param {Number[]} options.project List of project ids
  46. * @param {String[]} options.environment List of environments to query for
  47. * @param {String[]} options.team List of teams to query for
  48. * @param {String} options.period Time period to query for, in the format: <integer><units> where units are "d" or "h"
  49. * @param {String} options.interval Time interval to group results in, in the format: <integer><units> where units are "d", "h", "m", "s"
  50. * @param {Number} options.comparisonDelta Comparison delta for change alert event stats to include comparison stats
  51. * @param {Boolean} options.includePrevious Should request also return reqsults for previous period?
  52. * @param {Number} options.limit The number of rows to return
  53. * @param {String} options.query Search query
  54. * @param {QueryBatching} options.queryBatching A container for batching functions from a provider
  55. * @param {Record<string, string>} options.queryExtras A list of extra query parameters
  56. * @param {(org: OrganizationSummary) => string} options.generatePathname A function that returns an override for the pathname
  57. */
  58. export const doEventsRequest = (
  59. api: Client,
  60. {
  61. organization,
  62. project,
  63. environment,
  64. team,
  65. period,
  66. start,
  67. end,
  68. interval,
  69. comparisonDelta,
  70. includePrevious,
  71. query,
  72. yAxis,
  73. field,
  74. topEvents,
  75. orderby,
  76. partial,
  77. withoutZerofill,
  78. referrer,
  79. queryBatching,
  80. generatePathname,
  81. queryExtras,
  82. }: Options
  83. ): Promise<EventsStats | MultiSeriesEventsStats> => {
  84. const shouldDoublePeriod = canIncludePreviousPeriod(includePrevious, period);
  85. const urlQuery = Object.fromEntries(
  86. Object.entries({
  87. interval,
  88. comparisonDelta,
  89. project,
  90. environment,
  91. team,
  92. query,
  93. yAxis,
  94. field,
  95. topEvents,
  96. orderby,
  97. partial: partial ? '1' : undefined,
  98. withoutZerofill: withoutZerofill ? '1' : undefined,
  99. referrer: referrer ? referrer : 'api.organization-event-stats',
  100. }).filter(([, value]) => typeof value !== 'undefined')
  101. );
  102. // Doubling period for absolute dates is not accurate unless starting and
  103. // ending times are the same (at least for daily intervals). This is
  104. // the tradeoff for now.
  105. const periodObj = getPeriod({period, start, end}, {shouldDoublePeriod});
  106. const queryObject = {
  107. query: {
  108. ...urlQuery,
  109. ...periodObj,
  110. ...queryExtras,
  111. },
  112. };
  113. const pathname =
  114. generatePathname?.(organization) ??
  115. `/organizations/${organization.slug}/events-stats/`;
  116. if (queryBatching?.batchRequest) {
  117. return queryBatching.batchRequest(api, pathname, queryObject);
  118. }
  119. return api.requestPromise(pathname, queryObject);
  120. };
  121. export type EventQuery = {
  122. field: string[];
  123. query: string;
  124. environment?: string[];
  125. equation?: string[];
  126. noPagination?: boolean;
  127. per_page?: number;
  128. project?: string | string[];
  129. referrer?: string;
  130. sort?: string | string[];
  131. team?: string | string[];
  132. };
  133. export type TagSegment = {
  134. count: number;
  135. name: string;
  136. url: LocationDescriptor;
  137. value: string;
  138. isOther?: boolean;
  139. key?: string;
  140. };
  141. export type Tag = {
  142. key: string;
  143. topValues: Array<TagSegment>;
  144. };
  145. /**
  146. * Fetches tag facets for a query
  147. */
  148. export async function fetchTagFacets(
  149. api: Client,
  150. orgSlug: string,
  151. query: EventQuery
  152. ): Promise<Tag[]> {
  153. const urlParams = pick(query, Object.values(PERFORMANCE_URL_PARAM));
  154. const queryOption = {...urlParams, query: query.query};
  155. return api.requestPromise(`/organizations/${orgSlug}/events-facets/`, {
  156. query: queryOption,
  157. });
  158. }
  159. /**
  160. * Fetches total count of events for a given query
  161. */
  162. export async function fetchTotalCount(
  163. api: Client,
  164. orgSlug: String,
  165. query: EventQuery & LocationQuery
  166. ): Promise<number> {
  167. const urlParams = pick(query, Object.values(PERFORMANCE_URL_PARAM));
  168. const queryOption = {...urlParams, query: query.query};
  169. type Response = {
  170. count: number;
  171. };
  172. return api
  173. .requestPromise(`/organizations/${orgSlug}/events-meta/`, {
  174. query: queryOption,
  175. })
  176. .then((res: Response) => res.count);
  177. }