utils.tsx 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. import type {Location, Query} from 'history';
  2. import {t} from 'sentry/locale';
  3. import type {Organization} from 'sentry/types/organization';
  4. import type {TableDataRow} from 'sentry/utils/discover/discoverQuery';
  5. import type EventView from 'sentry/utils/discover/eventView';
  6. import type {QueryFieldValue} from 'sentry/utils/discover/fields';
  7. import {decodeScalar} from 'sentry/utils/queryString';
  8. import type {DomainView} from 'sentry/views/insights/pages/useFilters';
  9. import type {SpanOperationBreakdownFilter} from '../filter';
  10. import {filterToField} from '../filter';
  11. import {getTransactionSummaryBaseUrl, TransactionFilterOptions} from '../utils';
  12. export enum EventsDisplayFilterName {
  13. P50 = 'p50',
  14. P75 = 'p75',
  15. P95 = 'p95',
  16. P99 = 'p99',
  17. P100 = 'p100',
  18. }
  19. export type PercentileValues = Record<EventsDisplayFilterName, number>;
  20. export type EventsDisplayFilter = {
  21. label: string;
  22. name: EventsDisplayFilterName;
  23. query?: string[][];
  24. sort?: {field: string; kind: 'desc' | 'asc'};
  25. };
  26. export type EventsFilterOptions = {
  27. [name in EventsDisplayFilterName]: EventsDisplayFilter;
  28. };
  29. export type EventsFilterPercentileValues = {
  30. [name in Exclude<EventsDisplayFilterName, EventsDisplayFilterName.P100>]: number;
  31. };
  32. export function getEventsFilterOptions(
  33. spanOperationBreakdownFilter: SpanOperationBreakdownFilter,
  34. percentileValues?: EventsFilterPercentileValues
  35. ): EventsFilterOptions {
  36. const {p99, p95, p75, p50} = percentileValues
  37. ? percentileValues
  38. : {p99: 0, p95: 0, p75: 0, p50: 0};
  39. return {
  40. [EventsDisplayFilterName.P50]: {
  41. name: EventsDisplayFilterName.P50,
  42. query: p50 ? [['transaction.duration', `<=${p50.toFixed(0)}`]] : undefined,
  43. sort: {
  44. kind: 'desc',
  45. field: filterToField(spanOperationBreakdownFilter) || 'transaction.duration',
  46. },
  47. label: t('p50'),
  48. },
  49. [EventsDisplayFilterName.P75]: {
  50. name: EventsDisplayFilterName.P75,
  51. query: p75 ? [['transaction.duration', `<=${p75.toFixed(0)}`]] : undefined,
  52. sort: {
  53. kind: 'desc',
  54. field: filterToField(spanOperationBreakdownFilter) || 'transaction.duration',
  55. },
  56. label: t('p75'),
  57. },
  58. [EventsDisplayFilterName.P95]: {
  59. name: EventsDisplayFilterName.P95,
  60. query: p95 ? [['transaction.duration', `<=${p95.toFixed(0)}`]] : undefined,
  61. sort: {
  62. kind: 'desc',
  63. field: filterToField(spanOperationBreakdownFilter) || 'transaction.duration',
  64. },
  65. label: t('p95'),
  66. },
  67. [EventsDisplayFilterName.P99]: {
  68. name: EventsDisplayFilterName.P99,
  69. query: p99 ? [['transaction.duration', `<=${p99.toFixed(0)}`]] : undefined,
  70. sort: {
  71. kind: 'desc',
  72. field: filterToField(spanOperationBreakdownFilter) || 'transaction.duration',
  73. },
  74. label: t('p99'),
  75. },
  76. [EventsDisplayFilterName.P100]: {
  77. name: EventsDisplayFilterName.P100,
  78. label: t('p100'),
  79. },
  80. };
  81. }
  82. export function eventsRouteWithQuery({
  83. organization,
  84. transaction,
  85. projectID,
  86. query,
  87. view,
  88. }: {
  89. organization: Organization;
  90. query: Query;
  91. transaction: string;
  92. projectID?: string | string[];
  93. view?: DomainView;
  94. }) {
  95. const pathname = `${getTransactionSummaryBaseUrl(organization, view)}/events/`;
  96. return {
  97. pathname,
  98. query: {
  99. transaction,
  100. project: projectID,
  101. environment: query.environment,
  102. statsPeriod: query.statsPeriod,
  103. start: query.start,
  104. end: query.end,
  105. query: query.query,
  106. },
  107. };
  108. }
  109. function stringToFilter(option: string) {
  110. if (
  111. Object.values(EventsDisplayFilterName).includes(option as EventsDisplayFilterName)
  112. ) {
  113. return option as EventsDisplayFilterName;
  114. }
  115. return EventsDisplayFilterName.P100;
  116. }
  117. export function decodeEventsDisplayFilterFromLocation(location: Location) {
  118. return stringToFilter(
  119. decodeScalar(location.query.showTransactions, EventsDisplayFilterName.P100)
  120. );
  121. }
  122. export function filterEventsDisplayToLocationQuery(
  123. option: EventsDisplayFilterName,
  124. spanOperationBreakdownFilter: SpanOperationBreakdownFilter
  125. ) {
  126. const eventsFilterOptions = getEventsFilterOptions(spanOperationBreakdownFilter);
  127. const kind = eventsFilterOptions[option].sort?.kind;
  128. const field = eventsFilterOptions[option].sort?.field;
  129. const query: {showTransactions: string; sort?: string} = {
  130. showTransactions: option,
  131. };
  132. if (kind && field) {
  133. query.sort = `${kind === 'desc' ? '-' : ''}${field}`;
  134. }
  135. return query;
  136. }
  137. export function mapShowTransactionToPercentile(
  138. showTransaction: any
  139. ): EventsDisplayFilterName | undefined {
  140. switch (showTransaction) {
  141. case TransactionFilterOptions.OUTLIER:
  142. return EventsDisplayFilterName.P100;
  143. case TransactionFilterOptions.SLOW:
  144. return EventsDisplayFilterName.P95;
  145. default:
  146. return undefined;
  147. }
  148. }
  149. export function mapPercentileValues(percentileData?: TableDataRow | null) {
  150. return {
  151. p100: percentileData?.['p100()'],
  152. p99: percentileData?.['p99()'],
  153. p95: percentileData?.['p95()'],
  154. p75: percentileData?.['p75()'],
  155. p50: percentileData?.['p50()'],
  156. } as PercentileValues;
  157. }
  158. export function getPercentilesEventView(eventView: EventView): EventView {
  159. const percentileColumns: QueryFieldValue[] = [
  160. {
  161. kind: 'function',
  162. function: ['p100', '', undefined, undefined],
  163. },
  164. {
  165. kind: 'function',
  166. function: ['p99', '', undefined, undefined],
  167. },
  168. {
  169. kind: 'function',
  170. function: ['p95', '', undefined, undefined],
  171. },
  172. {
  173. kind: 'function',
  174. function: ['p75', '', undefined, undefined],
  175. },
  176. {
  177. kind: 'function',
  178. function: ['p50', '', undefined, undefined],
  179. },
  180. ];
  181. return eventView.withColumns(percentileColumns);
  182. }