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

feat(replays): track replay backend issues events (#48797)

## Summary

Adds `trackAnalytics` for replays backend errors success metrics.

Note: there's some overlap here in events, but nothing specific enough
to get the exact insights we needed. Amplitude can derive part of this
information, such as `details-viewed` w/ `referrer` however it lacks
`project` specific information, and constraints on the order of the
events would yield incorrect results.
 

Closes: https://github.com/getsentry/team-replay/issues/54
Elias Hussary 1 год назад
Родитель
Сommit
a8dd737384

+ 14 - 0
static/app/utils/analytics/replayAnalyticsEvents.tsx

@@ -38,6 +38,13 @@ export type ReplayEventParameters = {
     referrer: undefined | string;
     user_email: string;
   };
+  // similar purpose as "replay.details-viewed", however we're capturing the navigation action
+  // in order to also include a project platform
+  'replay.list-navigate-to-details': {
+    platform: string | undefined;
+    project_id: string | undefined;
+    referrer: string;
+  };
   'replay.list-paginated': {
     direction: 'next' | 'prev';
   };
@@ -53,6 +60,11 @@ export type ReplayEventParameters = {
     play: boolean;
     user_email: string;
   };
+  'replay.render-issues-detail-count': {
+    count: number;
+    platform: string;
+    project_id: string;
+  };
   'replay.render-player': {
     aspect_ratio: 'portrait' | 'landscape';
     /*
@@ -84,11 +96,13 @@ export const replayEventMap: Record<ReplayEventKey, string | null> = {
   'replay.details-tab-changed': 'Changed Replay Details Tab',
   'replay.details-time-spent': 'Time Spent Viewing Replay Details',
   'replay.details-viewed': 'Viewed Replay Details',
+  'replay.list-navigate-to-details': 'Replays List Navigate to Replay Details',
   'replay.list-paginated': 'Paginated Replay List',
   'replay.list-sorted': 'Sorted Replay List',
   'replay.list-time-spent': 'Time Spent Viewing Replay List',
   'replay.list-view-setup-sidebar': 'Views Set Up Replays Sidebar',
   'replay.play-pause': 'Played/Paused Replay',
+  'replay.render-issues-detail-count': 'Render Issues Detail Replay Count',
   'replay.render-player': 'Rendered ReplayPlayer',
   'replay.search': 'Searched Replay',
   'replay.toggle-fullscreen': 'Toggled Replay Fullscreen',

+ 15 - 1
static/app/views/issueDetails/header.tsx

@@ -1,4 +1,4 @@
-import {useMemo} from 'react';
+import {useEffect, useMemo} from 'react';
 import styled from '@emotion/styled';
 import {LocationDescriptor} from 'history';
 import omit from 'lodash/omit';
@@ -27,6 +27,7 @@ import {IconChat} from 'sentry/icons';
 import {t} from 'sentry/locale';
 import {space} from 'sentry/styles/space';
 import {Event, Group, IssueType, Organization, Project} from 'sentry/types';
+import {trackAnalytics} from 'sentry/utils/analytics';
 import {getMessage} from 'sentry/utils/events';
 import {getConfigForIssueType} from 'sentry/utils/issueTypeConfig';
 import {useLocation} from 'sentry/utils/useLocation';
@@ -74,6 +75,19 @@ function GroupHeaderTabs({
 
   const issueTypeConfig = getConfigForIssueType(group);
 
+  useEffect(() => {
+    if (!hasReplaySupport || typeof replaysCount === 'undefined') {
+      return;
+    }
+
+    trackAnalytics('replay.render-issues-detail-count', {
+      platform: project.platform!,
+      project_id: project.id,
+      count: replaysCount,
+      organization,
+    });
+  }, [hasReplaySupport, replaysCount, project, organization]);
+
   return (
     <StyledTabList hideBorder>
       <TabList.Item

+ 13 - 2
static/app/views/replays/replayTable/tableCell.tsx

@@ -15,6 +15,7 @@ import {IconCalendar, IconDelete} from 'sentry/icons';
 import {t} from 'sentry/locale';
 import {space, ValidSize} from 'sentry/styles/space';
 import type {Organization} from 'sentry/types';
+import {trackAnalytics} from 'sentry/utils/analytics';
 import EventView from 'sentry/utils/discover/eventView';
 import {spanOperationRelativeBreakdownRenderer} from 'sentry/utils/discover/fieldRenderers';
 import {getShortEventId} from 'sentry/utils/events';
@@ -63,6 +64,14 @@ export function ReplayCell({
     },
   };
 
+  const trackNavigationEvent = () =>
+    trackAnalytics('replay.list-navigate-to-details', {
+      project_id: project?.id,
+      platform: project?.platform,
+      organization,
+      referrer,
+    });
+
   if (replay.is_archived) {
     return (
       <Item isArchived={replay.is_archived}>
@@ -86,7 +95,9 @@ export function ReplayCell({
       <Row gap={1}>
         <Row gap={0.5}>
           {project ? <Avatar size={12} project={project} /> : null}
-          <Link to={replayDetails}>{getShortEventId(replay.id)}</Link>
+          <Link to={replayDetails} onClick={trackNavigationEvent}>
+            {getShortEventId(replay.id)}
+          </Link>
         </Row>
         <Row gap={0.5}>
           <IconCalendar color="gray300" size="xs" />
@@ -104,7 +115,7 @@ export function ReplayCell({
           replay.is_archived ? (
             replay.user.display_name || t('Unknown User')
           ) : (
-            <MainLink to={replayDetails}>
+            <MainLink to={replayDetails} onClick={trackNavigationEvent}>
               {replay.user.display_name || t('Unknown User')}
             </MainLink>
           )