events.tsx 5.6 KB

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