utils.tsx 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. import moment from 'moment-timezone';
  2. import {getInterval} from 'sentry/components/charts/utils';
  3. import {getUtcDateString} from 'sentry/utils/dates';
  4. import {
  5. API_INTERVAL_POINTS_LIMIT,
  6. API_INTERVAL_POINTS_MIN,
  7. TIME_WINDOWS,
  8. type TimePeriodType,
  9. } from 'sentry/views/alerts/rules/metric/details/constants';
  10. import type {MetricRule} from 'sentry/views/alerts/rules/metric/types';
  11. import {Dataset, TimePeriod} from 'sentry/views/alerts/rules/metric/types';
  12. import {extractEventTypeFilterFromRule} from 'sentry/views/alerts/rules/metric/utils/getEventTypeFilter';
  13. import type {Incident} from 'sentry/views/alerts/types';
  14. import {isCrashFreeAlert} from '../utils/isCrashFreeAlert';
  15. /**
  16. * Retrieve start/end date of a metric alert incident for the events graph
  17. * Will show at least 150 and no more than 10,000 data points
  18. */
  19. export function buildMetricGraphDateRange(incident: Incident): {
  20. end: string;
  21. start: string;
  22. } {
  23. const timeWindowMillis = incident.alertRule.timeWindow * 60 * 1000;
  24. const minRange = timeWindowMillis * API_INTERVAL_POINTS_MIN;
  25. const maxRange = timeWindowMillis * API_INTERVAL_POINTS_LIMIT;
  26. const now = moment.utc();
  27. const startDate = moment.utc(incident.dateStarted);
  28. // make a copy of now since we will modify endDate and use now for comparing
  29. const endDate = incident.dateClosed ? moment.utc(incident.dateClosed) : moment(now);
  30. const incidentRange = Math.max(endDate.diff(startDate), 3 * timeWindowMillis);
  31. const range = Math.min(maxRange, Math.max(minRange, incidentRange));
  32. const halfRange = moment.duration(range / 2);
  33. return {
  34. start: getUtcDateString(startDate.subtract(halfRange)),
  35. end: getUtcDateString(moment.min(endDate.add(halfRange), now)),
  36. };
  37. }
  38. export function getPeriodInterval(timePeriod: TimePeriodType, rule: MetricRule) {
  39. const startDate = moment.utc(timePeriod.start);
  40. const endDate = moment.utc(timePeriod.end);
  41. const timeWindow = rule?.timeWindow;
  42. const startEndDifferenceMs = endDate.diff(startDate);
  43. if (
  44. timeWindow &&
  45. (startEndDifferenceMs < API_INTERVAL_POINTS_LIMIT * timeWindow * 60 * 1000 ||
  46. // Special case 7 days * 1m interval over the api limit
  47. startEndDifferenceMs === TIME_WINDOWS[TimePeriod.SEVEN_DAYS])
  48. ) {
  49. return `${timeWindow}m`;
  50. }
  51. return getInterval({start: timePeriod.start, end: timePeriod.end}, 'high');
  52. }
  53. export function getFilter(rule: MetricRule): string[] | null {
  54. const {dataset, query} = rule;
  55. if (isCrashFreeAlert(dataset) || dataset === Dataset.EVENTS_ANALYTICS_PLATFORM) {
  56. return query.trim().split(' ');
  57. }
  58. const eventType = extractEventTypeFilterFromRule(rule);
  59. return (query ? `(${eventType}) AND (${query.trim()})` : eventType).split(' ');
  60. }
  61. export function getViableDateRange({
  62. interval,
  63. rule: {timeWindow, dataset},
  64. timePeriod: rawTimePeriod,
  65. }: {
  66. interval: string;
  67. rule: MetricRule;
  68. timePeriod: TimePeriodType;
  69. }) {
  70. const timePeriod = {...rawTimePeriod};
  71. // Fix for 7 days * 1m interval being over the max number of results from events api
  72. // 10k events is the current max
  73. if (
  74. timePeriod.usingPeriod &&
  75. timePeriod.period === TimePeriod.SEVEN_DAYS &&
  76. interval === '1m'
  77. ) {
  78. timePeriod.start = getUtcDateString(
  79. // -5 minutes provides a small cushion for rounding up minutes. This might be able to be smaller
  80. moment(moment.utc(timePeriod.end).subtract(10000 - 5, 'minutes'))
  81. );
  82. }
  83. // If the chart duration isn't as long as the rollup duration the events-stats
  84. // endpoint will return an invalid timeseriesData dataset
  85. let viableStartDate = getUtcDateString(
  86. moment.min(
  87. moment.utc(timePeriod.start),
  88. moment.utc(timePeriod.end).subtract(timeWindow, 'minutes')
  89. )
  90. );
  91. // Events Analytics Platform Span queries only support up to 2016 buckets.
  92. // 14 day 10m and 7 day 5m interval queries actually exceed this limit because we always extend the end date by an extra bucket.
  93. // We push forward the start date by a bucket to counteract this and return to 2016 buckets.
  94. if (
  95. dataset === Dataset.EVENTS_ANALYTICS_PLATFORM &&
  96. timePeriod.usingPeriod &&
  97. ((timePeriod.period === TimePeriod.FOURTEEN_DAYS && interval === '10m') ||
  98. (timePeriod.period === TimePeriod.SEVEN_DAYS && interval === '5m'))
  99. ) {
  100. viableStartDate = getUtcDateString(
  101. moment.utc(viableStartDate).add(timeWindow, 'minutes')
  102. );
  103. }
  104. const viableEndDate = getUtcDateString(
  105. moment.utc(timePeriod.end).add(timeWindow, 'minutes')
  106. );
  107. return {
  108. start: viableStartDate,
  109. end: viableEndDate,
  110. };
  111. }