generatePerformanceEventView.tsx 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. import {Location} from 'history';
  2. import {COL_WIDTH_UNDEFINED} from 'sentry/components/gridEditable';
  3. import {wrapQueryInWildcards} from 'sentry/components/performance/searchBar';
  4. import {t} from 'sentry/locale';
  5. import {NewQuery, Organization, Project} from 'sentry/types';
  6. import EventView from 'sentry/utils/discover/eventView';
  7. import {DiscoverDatasets} from 'sentry/utils/discover/types';
  8. import {WEB_VITAL_DETAILS} from 'sentry/utils/performance/vitals/constants';
  9. import {decodeScalar} from 'sentry/utils/queryString';
  10. import {MutableSearch} from 'sentry/utils/tokenizeSearch';
  11. import {getCurrentTrendParameter} from 'sentry/views/performance/trends/utils';
  12. const DEFAULT_STATS_PERIOD = '7d';
  13. const TOKEN_KEYS_SUPPORTED_IN_LIMITED_SEARCH = ['transaction'];
  14. export const TIME_SPENT_IN_SERVICE = 'time_spent_percentage()';
  15. export const getDefaultStatsPeriod = (organization: Organization) => {
  16. if (organization?.features?.includes('performance-landing-page-stats-period')) {
  17. return '14d';
  18. }
  19. return DEFAULT_STATS_PERIOD;
  20. };
  21. function prepareQueryForLandingPage(searchQuery, withStaticFilters) {
  22. const conditions = new MutableSearch(searchQuery);
  23. // If there is a bare text search, we want to treat it as a search
  24. // on the transaction name.
  25. if (conditions.freeText.length > 0) {
  26. const parsedFreeText = conditions.freeText.join(' ');
  27. // the query here is a user entered condition, no need to escape it
  28. conditions.setFilterValues(
  29. 'transaction',
  30. [wrapQueryInWildcards(parsedFreeText)],
  31. false
  32. );
  33. conditions.freeText = [];
  34. }
  35. if (withStaticFilters) {
  36. conditions.tokens = conditions.tokens.filter(
  37. token => token.key && TOKEN_KEYS_SUPPORTED_IN_LIMITED_SEARCH.includes(token.key)
  38. );
  39. }
  40. return conditions.formatString();
  41. }
  42. function generateGenericPerformanceEventView(
  43. location: Location,
  44. withStaticFilters: boolean,
  45. organization: Organization
  46. ): EventView {
  47. const {query} = location;
  48. const fields = ['transaction', 'http.method', 'tpm()', 'p50()', 'p95()', 'project'];
  49. const hasStartAndEnd = query.start && query.end;
  50. const savedQuery: NewQuery = {
  51. id: undefined,
  52. name: t('Performance'),
  53. query: 'event.type:transaction has:http.method',
  54. projects: [],
  55. fields,
  56. version: 2,
  57. };
  58. const widths = Array(savedQuery.fields.length).fill(COL_WIDTH_UNDEFINED);
  59. widths[savedQuery.fields.length - 1] = '110';
  60. savedQuery.widths = widths;
  61. if (!query.statsPeriod && !hasStartAndEnd) {
  62. savedQuery.range = getDefaultStatsPeriod(organization);
  63. }
  64. savedQuery.orderby = decodeScalar(query.sort, '-tpm');
  65. const searchQuery = decodeScalar(query.query, '');
  66. savedQuery.query = prepareQueryForLandingPage(searchQuery, withStaticFilters);
  67. const eventView = EventView.fromNewQueryWithLocation(savedQuery, location);
  68. eventView.additionalConditions.addFilterValues('event.type', ['transaction']);
  69. if (query.trendParameter) {
  70. // projects and projectIds are not necessary here since trendParameter will always
  71. // be present in location and will not be determined based on the project type
  72. const trendParameter = getCurrentTrendParameter(location, [], []);
  73. if (WEB_VITAL_DETAILS[trendParameter.column]) {
  74. eventView.additionalConditions.addFilterValues('has', [trendParameter.column]);
  75. }
  76. }
  77. return eventView;
  78. }
  79. export function generatePerformanceEventView(
  80. location: Location,
  81. _: Project[],
  82. {isTrends = false, withStaticFilters = false} = {},
  83. organization: Organization
  84. ) {
  85. const eventView = generateGenericPerformanceEventView(
  86. location,
  87. withStaticFilters,
  88. organization
  89. );
  90. if (isTrends) {
  91. return eventView;
  92. }
  93. return eventView;
  94. }
  95. export function generateWebServiceEventView(
  96. location: Location,
  97. _: Project[],
  98. {withStaticFilters = false} = {},
  99. organization: Organization
  100. ) {
  101. const {query} = location;
  102. const hasStartAndEnd = query.start && query.end;
  103. const orderby = decodeScalar(query.sort, `-time_spent_percentage`);
  104. const fields = [
  105. 'transaction',
  106. 'http.method',
  107. 'tps()',
  108. 'tps_percent_change()',
  109. 'p95(transaction.duration)',
  110. 'percentile_percent_change(transaction.duration,0.95)',
  111. 'http_error_count()',
  112. 'http_error_count_percent_change()',
  113. 'time_spent_percentage()',
  114. 'sum(transaction.duration)',
  115. ];
  116. const savedQuery: NewQuery = {
  117. id: undefined,
  118. name: t('Performance'),
  119. query: 'event.type:transaction has:http.method transaction.op:http.server',
  120. projects: [],
  121. fields,
  122. version: 2,
  123. dataset: DiscoverDatasets.METRICS,
  124. };
  125. const widths = Array(savedQuery.fields.length).fill(COL_WIDTH_UNDEFINED);
  126. widths[savedQuery.fields.length - 1] = '110';
  127. savedQuery.widths = widths;
  128. if (!query.statsPeriod && !hasStartAndEnd) {
  129. savedQuery.range = getDefaultStatsPeriod(organization);
  130. }
  131. savedQuery.orderby = orderby;
  132. const searchQuery = decodeScalar(query.query, '');
  133. savedQuery.query = `${savedQuery.query} ${prepareQueryForLandingPage(
  134. searchQuery,
  135. withStaticFilters
  136. )}`;
  137. const eventView = EventView.fromNewQueryWithLocation(savedQuery, location);
  138. return eventView;
  139. }