Browse Source

feat(stack-trace): Add amplitude analytics code - (#44951)

Priscila Oliveira 2 years ago
parent
commit
109ab9b1c7

+ 195 - 5
static/app/components/events/traceEventDataSection.tsx

@@ -1,4 +1,10 @@
-import {AnchorHTMLAttributes, cloneElement, createContext, useState} from 'react';
+import {
+  AnchorHTMLAttributes,
+  cloneElement,
+  createContext,
+  useCallback,
+  useState,
+} from 'react';
 import styled from '@emotion/styled';
 
 import {Button} from 'sentry/components/button';
@@ -12,7 +18,8 @@ import {space} from 'sentry/styles/space';
 import {PlatformType, Project} from 'sentry/types';
 import {Event} from 'sentry/types/event';
 import {STACK_TYPE} from 'sentry/types/stacktrace';
-import {isNativePlatform} from 'sentry/utils/platform';
+import trackAdvancedAnalyticsEvent from 'sentry/utils/analytics/trackAdvancedAnalyticsEvent';
+import {isMobilePlatform, isNativePlatform} from 'sentry/utils/platform';
 import useApi from 'sentry/utils/useApi';
 import useOrganization from 'sentry/utils/useOrganization';
 
@@ -91,6 +98,181 @@ export function TraceEventDataSection({
     display: [],
   });
 
+  const isMobile = isMobilePlatform(platform);
+
+  const handleFilterFramesChange = useCallback(
+    (val: 'full' | 'relevant') => {
+      const isFullOptionClicked = val === 'full';
+
+      trackAdvancedAnalyticsEvent(
+        isFullOptionClicked
+          ? 'stack-trace.full_stack_trace_clicked'
+          : 'stack-trace.most_relevant_clicked',
+        {
+          organization,
+          project_slug: projectSlug,
+          platform,
+          is_mobile: isMobile,
+        }
+      );
+
+      setState(currentState => ({...currentState, fullStackTrace: isFullOptionClicked}));
+    },
+    [organization, platform, projectSlug, isMobile]
+  );
+
+  const handleSortByChange = useCallback(
+    (val: keyof typeof sortByOptions) => {
+      const isRecentFirst = val === 'recent-first';
+
+      trackAdvancedAnalyticsEvent(
+        isRecentFirst
+          ? 'stack-trace.sort_option_recent_first_clicked'
+          : 'stack-trace.sort_option_recent_last_clicked',
+        {
+          organization,
+          project_slug: projectSlug,
+          platform,
+          is_mobile: isMobile,
+        }
+      );
+
+      setState(currentState => ({...currentState, sortBy: val}));
+    },
+    [organization, platform, projectSlug, isMobile]
+  );
+
+  const handleDisplayChange = useCallback(
+    (vals: (keyof typeof displayOptions)[]) => {
+      if (vals.includes('raw-stack-trace')) {
+        trackAdvancedAnalyticsEvent(
+          'stack-trace.display_option_raw_stack_trace_clicked',
+          {
+            organization,
+            project_slug: projectSlug,
+            platform,
+            is_mobile: isMobile,
+            checked: true,
+          }
+        );
+      } else if (state.display.includes('raw-stack-trace')) {
+        trackAdvancedAnalyticsEvent(
+          'stack-trace.display_option_raw_stack_trace_clicked',
+          {
+            organization,
+            project_slug: projectSlug,
+            platform,
+            is_mobile: isMobile,
+            checked: false,
+          }
+        );
+      }
+
+      if (vals.includes('absolute-addresses')) {
+        trackAdvancedAnalyticsEvent(
+          'stack-trace.display_option_absolute_addresses_clicked',
+          {
+            organization,
+            project_slug: projectSlug,
+            platform,
+            is_mobile: isMobile,
+            checked: true,
+          }
+        );
+      } else if (state.display.includes('absolute-addresses')) {
+        trackAdvancedAnalyticsEvent(
+          'stack-trace.display_option_absolute_addresses_clicked',
+          {
+            organization,
+            project_slug: projectSlug,
+            platform,
+            is_mobile: isMobile,
+            checked: false,
+          }
+        );
+      }
+
+      if (vals.includes('absolute-file-paths')) {
+        trackAdvancedAnalyticsEvent(
+          'stack-trace.display_option_absolute_file_paths_clicked',
+          {
+            organization,
+            project_slug: projectSlug,
+            platform,
+            is_mobile: isMobile,
+            checked: true,
+          }
+        );
+      } else if (state.display.includes('absolute-file-paths')) {
+        trackAdvancedAnalyticsEvent(
+          'stack-trace.display_option_absolute_file_paths_clicked',
+          {
+            organization,
+            project_slug: projectSlug,
+            platform,
+            is_mobile: isMobile,
+            checked: false,
+          }
+        );
+      }
+
+      if (vals.includes('minified')) {
+        trackAdvancedAnalyticsEvent(
+          platform.startsWith('javascript')
+            ? 'stack-trace.display_option_minified_clicked'
+            : 'stack-trace.display_option_unsymbolicated_clicked',
+          {
+            organization,
+            project_slug: projectSlug,
+            platform,
+            is_mobile: isMobile,
+            checked: true,
+          }
+        );
+      } else if (state.display.includes('minified')) {
+        trackAdvancedAnalyticsEvent(
+          platform.startsWith('javascript')
+            ? 'stack-trace.display_option_minified_clicked'
+            : 'stack-trace.display_option_unsymbolicated_clicked',
+          {
+            organization,
+            project_slug: projectSlug,
+            platform,
+            is_mobile: isMobile,
+            checked: false,
+          }
+        );
+      }
+
+      if (vals.includes('verbose-function-names')) {
+        trackAdvancedAnalyticsEvent(
+          'stack-trace.display_option_verbose_function_names_clicked',
+          {
+            organization,
+            project_slug: projectSlug,
+            platform,
+            is_mobile: isMobile,
+            checked: true,
+          }
+        );
+      } else if (state.display.includes('verbose-function-names')) {
+        trackAdvancedAnalyticsEvent(
+          'stack-trace.display_option_verbose_function_names_clicked',
+          {
+            organization,
+            project_slug: projectSlug,
+            platform,
+            is_mobile: isMobile,
+            checked: false,
+          }
+        );
+      }
+
+      setState(currentState => ({...currentState, display: vals}));
+    },
+    [organization, platform, projectSlug, isMobile, state]
+  );
+
   function getDisplayOptions(): {
     label: string;
     value: keyof typeof displayOptions;
@@ -216,7 +398,7 @@ export function TraceEventDataSection({
                   size="xs"
                   aria-label={t('Filter frames')}
                   value={state.fullStackTrace ? 'full' : 'relevant'}
-                  onChange={val => setState({...state, fullStackTrace: val === 'full'})}
+                  onChange={handleFilterFramesChange}
                 >
                   <SegmentedControl.Item key="relevant" disabled={!hasAppOnlyFrames}>
                     {t('Most Relevant')}
@@ -232,6 +414,14 @@ export function TraceEventDataSection({
                 size="xs"
                 href={rawStackTraceDownloadLink}
                 title={t('Download raw stack trace file')}
+                onClick={() => {
+                  trackAdvancedAnalyticsEvent('stack-trace.download_clicked', {
+                    organization,
+                    project_slug: projectSlug,
+                    platform,
+                    is_mobile: isMobile,
+                  });
+                }}
               >
                 {t('Download')}
               </Button>
@@ -245,7 +435,7 @@ export function TraceEventDataSection({
               disabled={!!sortByTooltip}
               position="bottom-end"
               onChange={selectedOption => {
-                setState({...state, sortBy: selectedOption.value});
+                handleSortByChange(selectedOption.value);
               }}
               value={state.sortBy}
               options={Object.entries(sortByOptions).map(([value, label]) => ({
@@ -264,7 +454,7 @@ export function TraceEventDataSection({
               triggerLabel=""
               position="bottom-end"
               value={state.display}
-              onChange={opts => setState({...state, display: opts.map(opt => opt.value)})}
+              onChange={opts => handleDisplayChange(opts.map(opt => opt.value))}
               options={[{label: t('Display'), options: getDisplayOptions()}]}
             />
           </ButtonBar>

+ 85 - 0
static/app/utils/analytics/stackTraceAnalyticsEvents.tsx

@@ -0,0 +1,85 @@
+export type StackTraceEventParameters = {
+  'stack-trace.display_option_absolute_addresses_clicked': {
+    checked: boolean;
+    is_mobile: boolean;
+    project_slug: string;
+    platform?: string;
+  };
+  'stack-trace.display_option_absolute_file_paths_clicked': {
+    checked: boolean;
+    is_mobile: boolean;
+    project_slug: string;
+    platform?: string;
+  };
+  'stack-trace.display_option_minified_clicked': {
+    checked: boolean;
+    is_mobile: boolean;
+    project_slug: string;
+    platform?: string;
+  };
+  'stack-trace.display_option_raw_stack_trace_clicked': {
+    checked: boolean;
+    is_mobile: boolean;
+    project_slug: string;
+    platform?: string;
+  };
+  'stack-trace.display_option_unsymbolicated_clicked': {
+    checked: boolean;
+    is_mobile: boolean;
+    project_slug: string;
+    platform?: string;
+  };
+  'stack-trace.display_option_verbose_function_names_clicked': {
+    checked: boolean;
+    is_mobile: boolean;
+    project_slug: string;
+    platform?: string;
+  };
+  'stack-trace.download_clicked': {
+    is_mobile: boolean;
+    project_slug: string;
+    platform?: string;
+  };
+  'stack-trace.full_stack_trace_clicked': {
+    is_mobile: boolean;
+    project_slug: string;
+    platform?: string;
+  };
+  'stack-trace.most_relevant_clicked': {
+    is_mobile: boolean;
+    project_slug: string;
+    platform?: string;
+  };
+  'stack-trace.sort_option_recent_first_clicked': {
+    is_mobile: boolean;
+    project_slug: string;
+    platform?: string;
+  };
+  'stack-trace.sort_option_recent_last_clicked': {
+    is_mobile: boolean;
+    project_slug: string;
+    platform?: string;
+  };
+};
+
+export const stackTraceEventMap: Record<keyof StackTraceEventParameters, string> = {
+  'stack-trace.display_option_absolute_addresses_clicked':
+    'Stack Trace: Display Option - Absolute Addresses - Clicked',
+  'stack-trace.display_option_absolute_file_paths_clicked':
+    'Stack Trace: Display Option - Absolute File Paths - Clicked',
+  'stack-trace.display_option_minified_clicked':
+    'Stack Trace: Display Option - Minified - Clicked',
+  'stack-trace.display_option_raw_stack_trace_clicked':
+    'Stack Trace: Display Option - Raw Stack Trace - Clicked',
+  'stack-trace.display_option_unsymbolicated_clicked':
+    'Stack Trace: Display Option - Unsymbolicated - Clicked',
+  'stack-trace.display_option_verbose_function_names_clicked':
+    'Stack Trace: Display Option - Verbose Function Names - Clicked',
+  'stack-trace.download_clicked': 'Stack Trace: Download - Clicked',
+  'stack-trace.full_stack_trace_clicked': 'Stack Trace: Full Stack Trace - Clicked',
+  'stack-trace.most_relevant_clicked': 'Stack Trace: Most Relevant - Clicked',
+  'stack-trace.sort_option_recent_first_clicked':
+    'Stack Trace: Sort Option - Recent First - Clicked',
+  'stack-trace.sort_option_recent_last_clicked':
+    'Stack Trace: Sort Option - Recent Last - Clicked',
+};

+ 4 - 1
static/app/utils/analytics/trackAdvancedAnalyticsEvent.tsx

@@ -19,6 +19,7 @@ import {releasesEventMap, ReleasesEventParameters} from './releasesAnalyticsEven
 import {replayEventMap, ReplayEventParameters} from './replayAnalyticsEvents';
 import {searchEventMap, SearchEventParameters} from './searchAnalyticsEvents';
 import {settingsEventMap, SettingsEventParameters} from './settingsAnalyticsEvents';
+import {stackTraceEventMap, StackTraceEventParameters} from './stackTraceAnalyticsEvents';
 import {TeamInsightsEventParameters, workflowEventMap} from './workflowAnalyticsEvents';
 
 type EventParameters = GrowthEventParameters &
@@ -35,7 +36,8 @@ type EventParameters = GrowthEventParameters &
   SettingsEventParameters &
   TeamInsightsEventParameters &
   DynamicSamplingEventParameters &
-  HeartbeatEventParameters;
+  HeartbeatEventParameters &
+  StackTraceEventParameters;
 
 const allEventMap: Record<string, string | null> = {
   ...coreUIEventMap,
@@ -53,6 +55,7 @@ const allEventMap: Record<string, string | null> = {
   ...workflowEventMap,
   ...dynamicSamplingEventMap,
   ...heartbeatEventMap,
+  ...stackTraceEventMap,
 };
 
 /**