Просмотр исходного кода

feat(stat-detectors): Update start and end values for widgets (#57692)

* The chart will now center with at most 7 days of data on either side
of the breakpoint
* All other widgets/data fetches on the page go from data start to the
current time

Closes #57393
Nar Saynorath 1 год назад
Родитель
Сommit
c69c9fc0a4

+ 7 - 4
static/app/components/events/eventStatisticalDetector/aggregateSpanDiff.tsx

@@ -1,5 +1,7 @@
+import {useMemo} from 'react';
 import styled from '@emotion/styled';
 import {Location} from 'history';
+import moment from 'moment';
 
 import EmptyStateWarning from 'sentry/components/emptyStateWarning';
 import {DataSection} from 'sentry/components/events/styles';
@@ -195,11 +197,12 @@ function renderBodyCell({
 function AggregateSpanDiff({event, projectId}: {event: Event; projectId: string}) {
   const location = useLocation();
   const organization = useOrganization();
-  const {transaction, requestStart, requestEnd, breakpoint} =
-    event?.occurrence?.evidenceData ?? {};
+  const now = useMemo(() => Date.now(), []);
+  const retentionPeriodMs = moment().subtract(90, 'days').valueOf();
+  const {transaction, dataStart, breakpoint} = event?.occurrence?.evidenceData ?? {};
 
-  const start = new Date(requestStart * 1000).toISOString();
-  const end = new Date(requestEnd * 1000).toISOString();
+  const start = new Date(Math.max(dataStart * 1000, retentionPeriodMs)).toISOString();
+  const end = new Date(now).toISOString();
   const breakpointTimestamp = new Date(breakpoint * 1000).toISOString();
   const {data, isLoading, isError} = useFetchAdvancedAnalysis({
     transaction,

+ 12 - 7
static/app/components/events/eventStatisticalDetector/aggregateSpanOps/spanOpBreakdown.tsx

@@ -1,5 +1,7 @@
+import {useMemo} from 'react';
 import styled from '@emotion/styled';
 import {Location} from 'history';
+import moment from 'moment';
 
 import EmptyStateWarning from 'sentry/components/emptyStateWarning';
 import {DataSection} from 'sentry/components/events/styles';
@@ -24,15 +26,14 @@ const SPAN_OPS_NAME_MAP = {
   ['p100(spans.ui)']: 'ui',
 };
 
-function getPostBreakpointEventView(location: Location, event: Event) {
+function getPostBreakpointEventView(location: Location, event: Event, end: number) {
   const eventView = EventView.fromLocation(location);
   eventView.fields = REQUEST_FIELDS;
 
   if (event?.occurrence) {
-    const {breakpoint, aggregateRange2, transaction, requestEnd} =
-      event?.occurrence?.evidenceData;
+    const {breakpoint, aggregateRange2, transaction} = event?.occurrence?.evidenceData;
     eventView.start = new Date(breakpoint * 1000).toISOString();
-    eventView.end = new Date(requestEnd * 1000).toISOString();
+    eventView.end = new Date(end).toISOString();
 
     eventView.query = `event.type:transaction transaction:"${transaction}" transaction.duration:<${
       aggregateRange2 * 1.15
@@ -43,13 +44,16 @@ function getPostBreakpointEventView(location: Location, event: Event) {
 }
 
 function getPreBreakpointEventView(location: Location, event: Event) {
+  const retentionPeriodMs = moment().subtract(90, 'days').valueOf();
   const eventView = EventView.fromLocation(location);
   eventView.fields = REQUEST_FIELDS;
 
   if (event?.occurrence) {
-    const {breakpoint, aggregateRange1, transaction, requestStart} =
+    const {breakpoint, aggregateRange1, transaction, dataStart} =
       event?.occurrence?.evidenceData;
-    eventView.start = new Date(requestStart * 1000).toISOString();
+    eventView.start = new Date(
+      Math.max(dataStart * 1000, retentionPeriodMs)
+    ).toISOString();
     eventView.end = new Date(breakpoint * 1000).toISOString();
 
     eventView.query = `event.type:transaction transaction:"${transaction}" transaction.duration:<${
@@ -63,8 +67,9 @@ function getPreBreakpointEventView(location: Location, event: Event) {
 function EventSpanOpBreakdown({event}: {event: Event}) {
   const organization = useOrganization();
   const location = useLocation();
+  const now = useMemo(() => Date.now(), []);
 
-  const postBreakpointEventView = getPostBreakpointEventView(location, event);
+  const postBreakpointEventView = getPostBreakpointEventView(location, event, now);
   const preBreakpointEventView = getPreBreakpointEventView(location, event);
 
   const queryExtras = {dataset: 'metricsEnhanced'};

+ 21 - 5
static/app/components/events/eventStatisticalDetector/breakpointChart.tsx

@@ -1,3 +1,5 @@
+import {useMemo} from 'react';
+
 import TransitionChart from 'sentry/components/charts/transitionChart';
 import TransparentLoadingMask from 'sentry/components/charts/transparentLoadingMask';
 import {Event, EventsStatsData} from 'sentry/types';
@@ -27,20 +29,34 @@ type EventBreakpointChartProps = {
   event: Event;
 };
 
+const DAY = 24 * 60 * 60 * 1000;
+
 function EventBreakpointChart({event}: EventBreakpointChartProps) {
   const organization = useOrganization();
   const location = useLocation();
 
-  const {transaction, requestStart, requestEnd} = event?.occurrence?.evidenceData ?? {};
+  const {transaction, breakpoint} = event?.occurrence?.evidenceData ?? {};
 
   const eventView = EventView.fromLocation(location);
   eventView.query = `event.type:transaction transaction:"${transaction}"`;
-  eventView.start = new Date(requestStart * 1000).toISOString();
-  eventView.end = new Date(requestEnd * 1000).toISOString();
   eventView.dataset = DiscoverDatasets.METRICS;
 
-  // If start and end were defined, then do not use default 14d stats period
-  eventView.statsPeriod = requestStart && requestEnd ? '' : eventView.statsPeriod;
+  const maxDateTime = useMemo(() => Date.now(), []);
+  const minDateTime = maxDateTime - 90 * DAY;
+
+  const breakpointTime = breakpoint * 1000;
+
+  const beforeTime = breakpointTime - DAY * 7;
+  const beforeDateTime =
+    beforeTime >= minDateTime ? new Date(beforeTime) : new Date(minDateTime);
+
+  const afterTime = breakpointTime + DAY * 7;
+  const afterDateTime =
+    afterTime <= maxDateTime ? new Date(afterTime) : new Date(maxDateTime);
+
+  eventView.start = beforeDateTime.toISOString();
+  eventView.end = afterDateTime.toISOString();
+  eventView.statsPeriod = undefined;
 
   // The evidence data keys are returned to us in camelCase, but we need to
   // convert them to snake_case to match the NormalizedTrendsTransaction type

+ 3 - 2
static/app/components/events/eventStatisticalDetector/eventComparison/eventDisplay.tsx

@@ -70,8 +70,9 @@ function useFetchSampleEvents({
   const organization = useOrganization();
   const eventView = new EventView({
     dataset: DiscoverDatasets.DISCOVER,
-    start: new Date(start * 1000).toISOString(),
-    end: new Date(end * 1000).toISOString(),
+    // Assumes the start and end timestamps are already in milliseconds
+    start: new Date(start).toISOString(),
+    end: new Date(end).toISOString(),
     fields: [{field: 'id'}, {field: 'timestamp'}],
     query: getSampleEventQuery({transaction, durationBaseline}),
 

+ 10 - 12
static/app/components/events/eventStatisticalDetector/eventComparison/index.tsx

@@ -1,4 +1,6 @@
+import {useMemo} from 'react';
 import styled from '@emotion/styled';
+import moment from 'moment';
 
 import {EventDisplay} from 'sentry/components/events/eventStatisticalDetector/eventComparison/eventDisplay';
 import {t} from 'sentry/locale';
@@ -18,14 +20,10 @@ type EventComparisonProps = {
 };
 
 function EventComparison({event, project, group}: EventComparisonProps) {
-  const {
-    aggregateRange1,
-    aggregateRange2,
-    requestStart,
-    requestEnd,
-    breakpoint,
-    transaction,
-  } = event?.occurrence?.evidenceData ?? {};
+  const now = useMemo(() => Date.now(), []);
+  const retentionPeriodMs = moment().subtract(90, 'days').valueOf();
+  const {aggregateRange1, aggregateRange2, dataStart, breakpoint, transaction} =
+    event?.occurrence?.evidenceData ?? {};
 
   return (
     <DataSection>
@@ -36,8 +34,8 @@ function EventComparison({event, project, group}: EventComparisonProps) {
           <EventDisplay
             eventSelectLabel={t('Baseline Event ID')}
             project={project}
-            start={requestStart}
-            end={breakpoint}
+            start={Math.max(dataStart * 1000, retentionPeriodMs)}
+            end={breakpoint * 1000}
             transaction={transaction}
             durationBaseline={aggregateRange1}
             group={group}
@@ -47,8 +45,8 @@ function EventComparison({event, project, group}: EventComparisonProps) {
           <EventDisplay
             eventSelectLabel={t('Regressed Event ID')}
             project={project}
-            start={breakpoint}
-            end={requestEnd}
+            start={breakpoint * 1000}
+            end={now}
             transaction={transaction}
             durationBaseline={aggregateRange2}
             group={group}

+ 4 - 3
static/app/components/group/tagFacets/index.tsx

@@ -133,8 +133,9 @@ export default function TagFacets({
   event,
 }: Props) {
   const organization = useOrganization();
+  const now = useMemo(() => Date.now(), []);
 
-  const {transaction, aggregateRange2, breakpoint, requestEnd} =
+  const {transaction, aggregateRange2, breakpoint} =
     event?.occurrence?.evidenceData ?? {};
   const {isLoading, isError, data, refetch} = useFetchIssueTagsForDetailsPage({
     groupId,
@@ -142,12 +143,12 @@ export default function TagFacets({
     environment: environments,
     isStatisticalDetector,
     statisticalDetectorParameters:
-      isStatisticalDetector && defined(breakpoint) && defined(requestEnd)
+      isStatisticalDetector && defined(breakpoint)
         ? {
             transaction,
             durationBaseline: aggregateRange2,
             start: new Date(breakpoint * 1000).toISOString(),
-            end: new Date(requestEnd * 1000).toISOString(),
+            end: new Date(now).toISOString(),
           }
         : undefined,
   });

+ 4 - 3
static/app/views/issueDetails/allEventsTable.tsx

@@ -1,4 +1,4 @@
-import {useEffect, useState} from 'react';
+import {useEffect, useMemo, useState} from 'react';
 import {Location} from 'history';
 
 import {getSampleEventQuery} from 'sentry/components/events/eventStatisticalDetector/eventComparison/eventDisplay';
@@ -43,6 +43,7 @@ function AllEventsTable(props: Props) {
   const [error, setError] = useState<string>('');
   const routes = useRoutes();
   const {fields, columnTitles} = getColumns(group, organization);
+  const now = useMemo(() => Date.now(), []);
 
   const endpointUrl = makeGroupPreviewRequestUrl({
     groupId: group.id,
@@ -87,7 +88,7 @@ function AllEventsTable(props: Props) {
     group.issueType === IssueType.PERFORMANCE_DURATION_REGRESSION &&
     groupIsOccurrenceBacked
   ) {
-    const {transaction, aggregateRange2, breakpoint, requestEnd} =
+    const {transaction, aggregateRange2, breakpoint} =
       data?.occurrence?.evidenceData ?? {};
 
     // Surface the "bad" events that occur after the breakpoint
@@ -99,7 +100,7 @@ function AllEventsTable(props: Props) {
 
     eventView.dataset = DiscoverDatasets.DISCOVER;
     eventView.start = new Date(breakpoint * 1000).toISOString();
-    eventView.end = new Date(requestEnd * 1000).toISOString();
+    eventView.end = new Date(now).toISOString();
     eventView.statsPeriod = undefined;
   }
   eventView.project = [parseInt(group.project.id, 10)];

+ 6 - 3
static/app/views/issueDetails/groupTags.tsx

@@ -31,6 +31,7 @@ type Props = DeprecatedAsyncComponent['props'] & {
 } & RouteComponentProps<{}, {}>;
 
 type State = DeprecatedAsyncComponent['state'] & {
+  now: number;
   tagList: null | TagWithTopValues[];
 };
 
@@ -39,6 +40,7 @@ class GroupTags extends DeprecatedAsyncComponent<Props, State> {
     return {
       ...super.getDefaultState(),
       tagList: null,
+      now: Date.now(),
     };
   }
 
@@ -47,7 +49,8 @@ class GroupTags extends DeprecatedAsyncComponent<Props, State> {
 
     if (
       organization.features.includes('performance-duration-regression-visible') &&
-      group.issueType === IssueType.PERFORMANCE_DURATION_REGRESSION
+      group.issueType === IssueType.PERFORMANCE_DURATION_REGRESSION &&
+      this.state
     ) {
       if (!event) {
         // We need the event for its occurrence data to get the timestamps
@@ -55,7 +58,7 @@ class GroupTags extends DeprecatedAsyncComponent<Props, State> {
         return [];
       }
 
-      const {transaction, aggregateRange2, breakpoint, requestEnd} =
+      const {transaction, aggregateRange2, breakpoint} =
         event.occurrence?.evidenceData ?? {};
       return [
         [
@@ -72,7 +75,7 @@ class GroupTags extends DeprecatedAsyncComponent<Props, State> {
                 addUpperBound: false,
               }),
               start: new Date(breakpoint * 1000).toISOString(),
-              end: new Date(requestEnd * 1000).toISOString(),
+              end: new Date(this.state.now).toISOString(),
             },
           },
         ],