utils.tsx 5.5 KB

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